Merge commit '04bb1f2f035343217875ce0fc19d3a7abde41717' into HEAD

Bug: 155031873
Change-Id: Ie7dc3f5c4b8999adf8e8885761fe65fd6ee65227
Merged-In: Ie7dc3f5c4b8999adf8e8885761fe65fd6ee65227
diff --git a/xfa/BUILD.gn b/xfa/BUILD.gn
new file mode 100644
index 0000000..df29737
--- /dev/null
+++ b/xfa/BUILD.gn
@@ -0,0 +1,14 @@
+# Copyright 2018 The 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.
+
+import("../pdfium.gni")
+
+assert(pdf_enable_xfa)
+
+config("xfa_warnings") {
+  visibility = [ ":*" ]
+  if (is_posix && !is_clang) {  # When GCC.
+    cflags = [ "-Wno-strict-overflow" ]
+  }
+}
diff --git a/xfa/DEPS b/xfa/DEPS
index 2dd4ef3..dba1791 100644
--- a/xfa/DEPS
+++ b/xfa/DEPS
@@ -1,5 +1,7 @@
 include_rules = [
   '+core',
   '+fxbarcode',
-  '+third_party/bigint'
+
+  # xfa/fwl should be standalone. https://crbug.com/pdfium/507
+  '-xfa/fwl',
 ]
diff --git a/xfa/fde/BUILD.gn b/xfa/fde/BUILD.gn
new file mode 100644
index 0000000..1806683
--- /dev/null
+++ b/xfa/fde/BUILD.gn
@@ -0,0 +1,42 @@
+# Copyright 2018 The 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.
+
+import("../../pdfium.gni")
+import("../../testing/test.gni")
+
+assert(pdf_enable_xfa)
+
+source_set("fde") {
+  sources = [
+    "cfde_data.h",
+    "cfde_texteditengine.cpp",
+    "cfde_texteditengine.h",
+    "cfde_textout.cpp",
+    "cfde_textout.h",
+    "cfde_wordbreak_data.cpp",
+    "cfde_wordbreak_data.h",
+  ]
+  deps = [
+    "../../core/fxcrt",
+    "../../core/fxge",
+    "../fgas",
+    "../fgas/layout",
+  ]
+  configs += [
+    "../../:pdfium_core_config",
+    "../:xfa_warnings",
+  ]
+  visibility = [ "../../*" ]
+}
+
+pdfium_unittest_source_set("unittests") {
+  sources = [ "cfde_texteditengine_unittest.cpp" ]
+  deps = [
+    ":fde",
+    "../../core/fxge",
+    "../../testing:unit_test_support",
+    "../fgas",
+  ]
+  pdfium_root_dir = "../../"
+}
diff --git a/xfa/fde/cfde_data.h b/xfa/fde/cfde_data.h
index d4ca63d..ad0740e 100644
--- a/xfa/fde/cfde_data.h
+++ b/xfa/fde/cfde_data.h
@@ -17,9 +17,8 @@
 };
 
 struct FDE_TextStyle {
-  FDE_TextStyle()
-      : single_line_(false), line_wrap_(false), last_line_height_(false) {}
-  ~FDE_TextStyle() {}
+  FDE_TextStyle() = default;
+  ~FDE_TextStyle() = default;
 
   void Reset() {
     single_line_ = false;
@@ -27,20 +26,9 @@
     last_line_height_ = false;
   }
 
-  bool single_line_;
-  bool line_wrap_;
-  bool last_line_height_;
-};
-
-struct FDE_TTOPIECE {
-  FDE_TTOPIECE();
-  FDE_TTOPIECE(const FDE_TTOPIECE& that);
-  ~FDE_TTOPIECE();
-
-  int32_t iStartChar;
-  int32_t iChars;
-  uint32_t dwCharStyles;
-  CFX_RectF rtPiece;
+  bool single_line_ = false;
+  bool line_wrap_ = false;
+  bool last_line_height_ = false;
 };
 
 #endif  // XFA_FDE_CFDE_DATA_H_
diff --git a/xfa/fde/cfde_texteditengine.cpp b/xfa/fde/cfde_texteditengine.cpp
index d085a8d..957b6ff 100644
--- a/xfa/fde/cfde_texteditengine.cpp
+++ b/xfa/fde/cfde_texteditengine.cpp
@@ -8,7 +8,10 @@
 
 #include <algorithm>
 #include <limits>
+#include <utility>
 
+#include "core/fxge/text_char_pos.h"
+#include "third_party/base/ptr_util.h"
 #include "xfa/fde/cfde_textout.h"
 #include "xfa/fde/cfde_wordbreak_data.h"
 #include "xfa/fgas/font/cfgas_gefont.h"
@@ -19,7 +22,7 @@
 constexpr size_t kGapSize = 128;
 constexpr size_t kPageWidthMax = 0xffff;
 
-class InsertOperation : public CFDE_TextEditEngine::Operation {
+class InsertOperation final : public CFDE_TextEditEngine::Operation {
  public:
   InsertOperation(CFDE_TextEditEngine* engine,
                   size_t start_idx,
@@ -44,7 +47,7 @@
   WideString added_text_;
 };
 
-class DeleteOperation : public CFDE_TextEditEngine::Operation {
+class DeleteOperation final : public CFDE_TextEditEngine::Operation {
  public:
   DeleteOperation(CFDE_TextEditEngine* engine,
                   size_t start_idx,
@@ -69,7 +72,7 @@
   WideString removed_text_;
 };
 
-class ReplaceOperation : public CFDE_TextEditEngine::Operation {
+class ReplaceOperation final : public CFDE_TextEditEngine::Operation {
  public:
   ReplaceOperation(CFDE_TextEditEngine* engine,
                    size_t start_idx,
@@ -95,20 +98,6 @@
   DeleteOperation delete_op_;
 };
 
-bool CheckStateChangeForWordBreak(WordBreakProperty from,
-                                  WordBreakProperty to) {
-  ASSERT(static_cast<int>(from) < 13);
-
-  return !!(gs_FX_WordBreak_Table[static_cast<int>(from)] &
-            static_cast<uint16_t>(1 << static_cast<int>(to)));
-}
-
-WordBreakProperty GetWordBreakProperty(wchar_t wcCodePoint) {
-  uint8_t dwProperty = gs_FX_WordBreak_CodePointProperties[wcCodePoint >> 1];
-  return static_cast<WordBreakProperty>((wcCodePoint & 1) ? (dwProperty & 0x0F)
-                                                          : (dwProperty >> 4));
-}
-
 int GetBreakFlagsFor(WordBreakProperty current, WordBreakProperty next) {
   if (current == WordBreakProperty::kMidLetter) {
     if (next == WordBreakProperty::kALetter)
@@ -238,34 +227,59 @@
   text_out->SetStyles(style);
 
   size_t length = text.GetLength();
-  WideStringView temp(text.c_str(), length);
+  WideStringView temp = text.AsStringView();
 
   float vertical_height = line_spacing_ * visible_line_count_;
   size_t chars_exceeding_size = 0;
   // TODO(dsinclair): Can this get changed to a binary search?
   for (size_t i = 0; i < num_to_check; i++) {
-    // This does a lot of string copying ....
-    // TODO(dsinclair): make CalcLogicSize take a WideStringC instead.
-    text_out->CalcLogicSize(WideString(temp), text_rect);
-
+    text_out->CalcLogicSize(temp, &text_rect);
     if (limit_horizontal_area_ && text_rect.width <= available_width_)
       break;
     if (limit_vertical_area_ && text_rect.height <= vertical_height)
       break;
 
-    --length;
-    temp = temp.Mid(0, length);
     ++chars_exceeding_size;
+
+    --length;
+    temp = temp.First(length);
   }
 
   return chars_exceeding_size;
 }
 
 void CFDE_TextEditEngine::Insert(size_t idx,
-                                 const WideString& text,
+                                 const WideString& request_text,
                                  RecordOperation add_operation) {
-  if (idx > text_length_)
-    idx = text_length_;
+  WideString text = request_text;
+  if (text.IsEmpty())
+    return;
+
+  idx = std::min(idx, text_length_);
+
+  TextChange change;
+  change.selection_start = idx;
+  change.selection_end = idx;
+  change.text = text;
+  change.previous_text = GetText();
+  change.cancelled = false;
+
+  if (delegate_ && (add_operation != RecordOperation::kSkipRecord &&
+                    add_operation != RecordOperation::kSkipNotify)) {
+    delegate_->OnTextWillChange(&change);
+    if (change.cancelled)
+      return;
+
+    text = change.text;
+    idx = change.selection_start;
+
+    // Delegate extended the selection, so delete it before we insert.
+    if (change.selection_end != change.selection_start)
+      DeleteSelectedText(RecordOperation::kSkipRecord);
+
+    // Delegate may have changed text entirely, recheck.
+    idx = std::min(idx, text_length_);
+  }
 
   size_t length = text.GetLength();
   if (length == 0)
@@ -274,11 +288,23 @@
   // If we're going to be too big we insert what we can and notify the
   // delegate we've filled the text after the insert is done.
   bool exceeded_limit = false;
-  if (has_character_limit_ && text_length_ + length > character_limit_) {
-    exceeded_limit = true;
-    length = character_limit_ - text_length_;
-  }
 
+  // Currently we allow inserting a number of characters over the text limit if
+  // we're skipping notify. This means we're setting the formatted text into the
+  // engine. Otherwise, if you enter 123456789 for an SSN into a field
+  // with a 9 character limit and we reformat to 123-45-6789 we'll truncate
+  // the 89 when inserting into the text edit. See https://crbug.com/pdfium/1089
+  if (has_character_limit_ && text_length_ + length > character_limit_) {
+    if (add_operation == RecordOperation::kSkipNotify) {
+      // Raise the limit to allow subsequent changes to expanded text.
+      character_limit_ = text_length_ + length;
+    } else {
+      // Trucate the text to comply with the limit.
+      CHECK(text_length_ <= character_limit_);
+      length = character_limit_ - text_length_;
+      exceeded_limit = true;
+    }
+  }
   AdjustGap(idx, length);
 
   if (validation_enabled_ || limit_horizontal_area_ || limit_vertical_area_) {
@@ -341,7 +367,7 @@
     if (exceeded_limit)
       delegate_->NotifyTextFull();
 
-    delegate_->OnTextChanged(previous_text);
+    delegate_->OnTextChanged();
   }
 }
 
@@ -408,10 +434,9 @@
     return 0;
   --pos;
 
-  wchar_t ch = GetChar(pos);
   while (pos != 0) {
     // We want to be on the location just before the \r or \n
-    ch = GetChar(pos - 1);
+    wchar_t ch = GetChar(pos - 1);
     if (ch != '\r' && ch != '\n')
       break;
 
@@ -605,6 +630,7 @@
     return;
 
   has_character_limit_ = limit;
+  character_limit_ = std::max(character_limit_, text_length_);
   if (is_comb_text_)
     SetCombTextWidth();
 
@@ -617,7 +643,7 @@
 
   ClearOperationRecords();
 
-  character_limit_ = limit;
+  character_limit_ = std::max(limit, text_length_);
   if (is_comb_text_)
     SetCombTextWidth();
 
@@ -655,10 +681,6 @@
   is_dirty_ = true;
 }
 
-float CFDE_TextEditEngine::GetFontAscent() const {
-  return (static_cast<float>(font_->GetAscent()) * font_size_) / 1000;
-}
-
 void CFDE_TextEditEngine::SetAlignment(uint32_t alignment) {
   if (alignment == character_alignment_)
     return;
@@ -759,7 +781,7 @@
 
 WideString CFDE_TextEditEngine::GetSelectedText() const {
   if (!has_selection_)
-    return L"";
+    return WideString();
 
   WideString text;
   if (selection_.start_idx < gap_position_) {
@@ -793,7 +815,7 @@
 WideString CFDE_TextEditEngine::DeleteSelectedText(
     RecordOperation add_operation) {
   if (!has_selection_)
-    return L"";
+    return WideString();
 
   return Delete(selection_.start_idx, selection_.count, add_operation);
 }
@@ -802,7 +824,29 @@
                                        size_t length,
                                        RecordOperation add_operation) {
   if (start_idx >= text_length_)
-    return L"";
+    return WideString();
+
+  TextChange change;
+  change.text.clear();
+  change.cancelled = false;
+  if (delegate_ && (add_operation != RecordOperation::kSkipRecord &&
+                    add_operation != RecordOperation::kSkipNotify)) {
+    change.previous_text = GetText();
+    change.selection_start = start_idx;
+    change.selection_end = start_idx + length;
+
+    delegate_->OnTextWillChange(&change);
+    if (change.cancelled)
+      return WideString();
+
+    // Delegate may have changed the selection range.
+    start_idx = change.selection_start;
+    length = change.selection_end - change.selection_start;
+
+    // Delegate may have changed text entirely, recheck.
+    if (start_idx >= text_length_)
+      return WideString();
+  }
 
   length = std::min(length, text_length_ - start_idx);
   AdjustGap(start_idx + length, 0);
@@ -821,17 +865,40 @@
   gap_size_ += length;
 
   text_length_ -= length;
+  is_dirty_ = true;
   ClearSelection();
 
+  // The JS requested the insertion of text instead of just a deletion.
+  if (!change.text.IsEmpty())
+    Insert(start_idx, change.text, RecordOperation::kSkipRecord);
+
   if (delegate_)
-    delegate_->OnTextChanged(previous_text);
+    delegate_->OnTextChanged();
 
   return ret;
 }
 
-void CFDE_TextEditEngine::ReplaceSelectedText(const WideString& rep) {
-  size_t start_idx = selection_.start_idx;
+void CFDE_TextEditEngine::ReplaceSelectedText(const WideString& requested_rep) {
+  WideString rep = requested_rep;
 
+  if (delegate_) {
+    TextChange change;
+    change.selection_start = selection_.start_idx;
+    change.selection_end = selection_.start_idx + selection_.count;
+    change.text = rep;
+    change.previous_text = GetText();
+    change.cancelled = false;
+
+    delegate_->OnTextWillChange(&change);
+    if (change.cancelled)
+      return;
+
+    rep = change.text;
+    selection_.start_idx = change.selection_start;
+    selection_.count = change.selection_end - change.selection_start;
+  }
+
+  size_t start_idx = selection_.start_idx;
   WideString txt = DeleteSelectedText(RecordOperation::kSkipRecord);
   Insert(gap_position_, rep, RecordOperation::kSkipRecord);
 
@@ -899,14 +966,26 @@
 
   size_t start_it_idx = start_it->nStart;
   for (; start_it <= end_it; ++start_it) {
-    if (!start_it->rtPiece.Contains(point))
+    bool piece_contains_point_vertically =
+        (point.y >= start_it->rtPiece.top &&
+         point.y < start_it->rtPiece.bottom());
+    if (!piece_contains_point_vertically)
       continue;
 
     std::vector<CFX_RectF> rects = GetCharRects(*start_it);
     for (size_t i = 0; i < rects.size(); ++i) {
-      if (!rects[i].Contains(point))
+      bool character_contains_point_horizontally =
+          (point.x >= rects[i].left && point.x < rects[i].right());
+      if (!character_contains_point_horizontally)
         continue;
-      size_t pos = start_it->nStart + i;
+
+      // When clicking on the left half of a character, the cursor should be
+      // moved before it. If the click was on the right half of that character,
+      // move the cursor after it.
+      bool closer_to_left =
+          (point.x - rects[i].left < rects[i].right() - point.x);
+      int caret_pos = (closer_to_left ? i : i + 1);
+      size_t pos = start_it->nStart + caret_pos;
       if (pos >= text_length_)
         return text_length_;
 
@@ -920,6 +999,28 @@
       // TODO(dsinclair): Old code had a before flag set based on bidi?
       return pos;
     }
+
+    // Point is not within the horizontal range of any characters, it's
+    // afterwards. Return the position after the last character.
+    // The last line has nCount equal to the number of characters + 1 (sentinel
+    // character maybe?). Restrict to the text_length_ to account for that.
+    size_t pos = std::min(
+        static_cast<size_t>(start_it->nStart + start_it->nCount), text_length_);
+
+    // If the line is not the last one and it was broken right after a breaking
+    // whitespace (space or line break), the cursor should not be placed after
+    // the whitespace, but before it. If the cursor is moved after the
+    // whitespace, it goes to the beginning of the next line.
+    bool is_last_line = (std::next(start_it) == text_piece_info_.end());
+    if (!is_last_line && pos > 0) {
+      wchar_t previous_char = GetChar(pos - 1);
+      if (previous_char == L' ' || previous_char == L'\n' ||
+          previous_char == L'\r') {
+        --pos;
+      }
+    }
+
+    return pos;
   }
 
   if (start_it == text_piece_info_.end())
@@ -937,9 +1038,9 @@
   if (piece.nCount < 1)
     return std::vector<CFX_RectF>();
 
-  FX_TXTRUN tr;
+  CFX_TxtBreak::Run tr;
   tr.pEdtEngine = this;
-  tr.pIdentity = &piece;
+  tr.iStart = piece.nStart;
   tr.iLength = piece.nCount;
   tr.pFont = font_;
   tr.fFontSize = font_size_;
@@ -949,14 +1050,14 @@
   return text_break_.GetCharRects(&tr, false);
 }
 
-std::vector<FXTEXT_CHARPOS> CFDE_TextEditEngine::GetDisplayPos(
+std::vector<TextCharPos> CFDE_TextEditEngine::GetDisplayPos(
     const FDE_TEXTEDITPIECE& piece) {
   if (piece.nCount < 1)
-    return std::vector<FXTEXT_CHARPOS>();
+    return std::vector<TextCharPos>();
 
-  FX_TXTRUN tr;
+  CFX_TxtBreak::Run tr;
   tr.pEdtEngine = this;
-  tr.pIdentity = &piece;
+  tr.iStart = piece.nStart;
   tr.iLength = piece.nCount;
   tr.pFont = font_;
   tr.fFontSize = font_size_;
@@ -964,7 +1065,7 @@
   tr.dwCharStyles = piece.dwCharStyles;
   tr.pRect = &piece.rtPiece;
 
-  std::vector<FXTEXT_CHARPOS> data(text_break_.GetDisplayPos(&tr, nullptr));
+  std::vector<TextCharPos> data(text_break_.GetDisplayPos(&tr, nullptr));
   text_break_.GetDisplayPos(&tr, data.data());
   return data;
 }
@@ -1001,19 +1102,17 @@
       const CFX_BreakPiece* piece = text_break_.GetBreakPieceUnstable(i);
 
       FDE_TEXTEDITPIECE txtEdtPiece;
-      memset(&txtEdtPiece, 0, sizeof(FDE_TEXTEDITPIECE));
-
-      txtEdtPiece.nBidiLevel = piece->m_iBidiLevel;
-      txtEdtPiece.nCount = piece->GetLength();
-      txtEdtPiece.nStart = current_piece_start;
-      txtEdtPiece.dwCharStyles = piece->m_dwCharStyles;
-      if (FX_IsOdd(piece->m_iBidiLevel))
-        txtEdtPiece.dwCharStyles |= FX_TXTCHARSTYLE_OddBidiLevel;
-
       txtEdtPiece.rtPiece.left = piece->m_iStartPos / 20000.0f;
       txtEdtPiece.rtPiece.top = current_line_start;
       txtEdtPiece.rtPiece.width = piece->m_iWidth / 20000.0f;
       txtEdtPiece.rtPiece.height = line_spacing_;
+      txtEdtPiece.nStart = current_piece_start;
+      txtEdtPiece.nCount = piece->GetLength();
+      txtEdtPiece.nBidiLevel = piece->m_iBidiLevel;
+      txtEdtPiece.dwCharStyles = piece->m_dwCharStyles;
+      if (FX_IsOdd(piece->m_iBidiLevel))
+        txtEdtPiece.dwCharStyles |= FX_TXTCHARSTYLE_OddBidiLevel;
+
       text_piece_info_.push_back(txtEdtPiece);
 
       if (initialized_bounding_box) {
@@ -1037,13 +1136,7 @@
   if (IsAlignedRight() && bounds_smaller) {
     delta = available_width_ - contents_bounding_box_.width;
   } else if (IsAlignedCenter() && bounds_smaller) {
-    // TODO(dsinclair): Old code used CombText here and set the space to
-    // something unrelated to the available width .... Figure out if this is
-    // needed and what it should do.
-    // if (is_comb_text_) {
-    // } else {
     delta = (available_width_ - contents_bounding_box_.width) / 2.0f;
-    // }
   }
 
   if (delta != 0.0) {
@@ -1168,17 +1261,17 @@
   WordBreakProperty ePreType = WordBreakProperty::kNone;
   if (!IsEOF(!bPrev)) {
     Next(!bPrev);
-    ePreType = GetWordBreakProperty(GetChar());
+    ePreType = FX_GetWordBreakProperty(GetChar());
     Next(bPrev);
   }
 
-  WordBreakProperty eCurType = GetWordBreakProperty(GetChar());
+  WordBreakProperty eCurType = FX_GetWordBreakProperty(GetChar());
   bool bFirst = true;
   while (!IsEOF(bPrev)) {
     Next(bPrev);
 
-    WordBreakProperty eNextType = GetWordBreakProperty(GetChar());
-    bool wBreak = CheckStateChangeForWordBreak(eCurType, eNextType);
+    WordBreakProperty eNextType = FX_GetWordBreakProperty(GetChar());
+    bool wBreak = FX_CheckStateChangeForWordBreak(eCurType, eNextType);
     if (wBreak) {
       if (IsEOF(bPrev)) {
         Next(!bPrev);
@@ -1203,7 +1296,7 @@
         }
 
         Next(bPrev);
-        eNextType = GetWordBreakProperty(GetChar());
+        eNextType = FX_GetWordBreakProperty(GetChar());
         if (BreakFlagsChanged(nFlags, eNextType)) {
           Next(!bPrev);
           Next(!bPrev);
diff --git a/xfa/fde/cfde_texteditengine.h b/xfa/fde/cfde_texteditengine.h
index 58f77ed..d68aa41 100644
--- a/xfa/fde/cfde_texteditengine.h
+++ b/xfa/fde/cfde_texteditengine.h
@@ -13,11 +13,11 @@
 
 #include "core/fxcrt/fx_string.h"
 #include "core/fxcrt/retain_ptr.h"
-#include "core/fxge/cfx_renderdevice.h"
 #include "core/fxge/fx_dib.h"
 #include "xfa/fgas/layout/cfx_txtbreak.h"
 
 class CFGAS_GEFont;
+class TextCharPos;
 
 struct FDE_TEXTEDITPIECE {
   FDE_TEXTEDITPIECE();
@@ -36,7 +36,7 @@
     default;
 inline FDE_TEXTEDITPIECE::~FDE_TEXTEDITPIECE() = default;
 
-class CFDE_TextEditEngine {
+class CFDE_TextEditEngine : public CFX_TxtBreak::Engine {
  public:
   class Iterator {
    public:
@@ -61,24 +61,34 @@
     virtual void Undo() const = 0;
   };
 
+  struct TextChange {
+    WideString text;
+    WideString previous_text;
+    size_t selection_start;
+    size_t selection_end;
+    bool cancelled;
+  };
+
   class Delegate {
    public:
     virtual ~Delegate() = default;
     virtual void NotifyTextFull() = 0;
     virtual void OnCaretChanged() = 0;
-    virtual void OnTextChanged(const WideString& prevText) = 0;
+    virtual void OnTextWillChange(TextChange* change) = 0;
+    virtual void OnTextChanged() = 0;
     virtual void OnSelChanged() = 0;
     virtual bool OnValidate(const WideString& wsText) = 0;
     virtual void SetScrollOffset(float fScrollOffset) = 0;
   };
 
-  enum class RecordOperation {
-    kInsertRecord,
-    kSkipRecord,
-  };
+  enum class RecordOperation { kInsertRecord, kSkipRecord, kSkipNotify };
 
   CFDE_TextEditEngine();
-  ~CFDE_TextEditEngine();
+  ~CFDE_TextEditEngine() override;
+
+  // CFX_TxtBreak::Engine:
+  wchar_t GetChar(size_t idx) const override;
+  size_t GetWidthOfChar(size_t idx) override;
 
   void SetDelegate(Delegate* delegate) { delegate_ = delegate; }
   void Clear();
@@ -103,7 +113,6 @@
   float GetFontSize() const { return font_size_; }
   void SetFontColor(FX_ARGB color) { font_color_ = color; }
   FX_ARGB GetFontColor() const { return font_color_; }
-  float GetFontAscent() const;
 
   void SetAlignment(uint32_t alignment);
   float GetLineSpace() const { return line_spacing_; }
@@ -152,9 +161,6 @@
 
   void Layout();
 
-  wchar_t GetChar(size_t idx) const;
-  // Non-const so we can force a Layout() if needed.
-  size_t GetWidthOfChar(size_t idx);
   // Non-const so we can force a Layout() if needed.
   size_t GetIndexForPoint(const CFX_PointF& point);
   // <start_idx, count>
@@ -165,15 +171,13 @@
   std::vector<CFX_RectF> GetCharacterRectsInRange(int32_t start_idx,
                                                   int32_t count);
 
-  CFX_TxtBreak* GetTextBreak() { return &text_break_; }
-
   const std::vector<FDE_TEXTEDITPIECE>& GetTextPieces() {
     // Force a layout if needed.
     Layout();
     return text_piece_info_;
   }
 
-  std::vector<FXTEXT_CHARPOS> GetDisplayPos(const FDE_TEXTEDITPIECE& info);
+  std::vector<TextCharPos> GetDisplayPos(const FDE_TEXTEDITPIECE& info);
 
   void SetMaxEditOperationsForTesting(size_t max);
 
@@ -209,8 +213,11 @@
   float line_spacing_;
   std::vector<WideString::CharType> content_;
   size_t text_length_;
+
+  // See e.g. https://en.wikipedia.org/wiki/Gap_buffer
   size_t gap_position_;
   size_t gap_size_;
+
   size_t available_width_;
   size_t character_limit_;
   size_t visible_line_count_;
diff --git a/xfa/fde/cfde_texteditengine_unittest.cpp b/xfa/fde/cfde_texteditengine_unittest.cpp
index 522e61a..2089dff 100644
--- a/xfa/fde/cfde_texteditengine_unittest.cpp
+++ b/xfa/fde/cfde_texteditengine_unittest.cpp
@@ -4,14 +4,15 @@
 
 #include "xfa/fde/cfde_texteditengine.h"
 
+#include "core/fxge/text_char_pos.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "testing/test_support.h"
+#include "testing/xfa_unit_test_support.h"
 #include "third_party/base/ptr_util.h"
 #include "xfa/fgas/font/cfgas_gefont.h"
 
 class CFDE_TextEditEngineTest : public testing::Test {
  public:
-  class Delegate : public CFDE_TextEditEngine::Delegate {
+  class Delegate final : public CFDE_TextEditEngine::Delegate {
    public:
     void Reset() {
       text_is_full = false;
@@ -21,7 +22,8 @@
     void NotifyTextFull() override { text_is_full = true; }
 
     void OnCaretChanged() override {}
-    void OnTextChanged(const WideString& prevText) override {}
+    void OnTextWillChange(CFDE_TextEditEngine::TextChange* change) override {}
+    void OnTextChanged() override {}
     void OnSelChanged() override {}
     bool OnValidate(const WideString& wsText) override {
       return !fail_validation;
@@ -38,7 +40,7 @@
   void SetUp() override {
     font_ =
         CFGAS_GEFont::LoadFont(L"Arial Black", 0, 0, GetGlobalFontManager());
-    ASSERT(font_.Get() != nullptr);
+    ASSERT_TRUE(font_.Get() != nullptr);
 
     engine_ = pdfium::MakeUnique<CFDE_TextEditEngine>();
     engine_->SetFont(font_);
@@ -159,6 +161,53 @@
   engine()->SetDelegate(nullptr);
 }
 
+TEST_F(CFDE_TextEditEngineTest, InsertToggleLimit) {
+  engine()->SetHasCharacterLimit(true);
+  engine()->Insert(0, L"Hello World");
+  engine()->SetCharacterLimit(5);
+  engine()->Insert(0, L"Not Inserted before ");
+  EXPECT_STREQ(L"Hello World", engine()->GetText().c_str());
+
+  engine()->SetHasCharacterLimit(false);
+  engine()->Insert(0, L"Inserted before ");
+  engine()->SetHasCharacterLimit(true);
+  engine()->Insert(0, L"Not Inserted before ");
+  EXPECT_STREQ(L"Inserted before Hello World", engine()->GetText().c_str());
+}
+
+TEST_F(CFDE_TextEditEngineTest, InsertSkipNotify) {
+  engine()->SetHasCharacterLimit(true);
+  engine()->SetCharacterLimit(8);
+  engine()->Insert(0, L"Hello");
+  engine()->Insert(5, L" World",
+                   CFDE_TextEditEngine::RecordOperation::kSkipNotify);
+  EXPECT_STREQ(L"Hello World", engine()->GetText().c_str());
+
+  engine()->Insert(0, L"Not inserted");
+  EXPECT_STREQ(L"Hello World", engine()->GetText().c_str());
+
+  engine()->Delete(5, 1);
+  EXPECT_STREQ(L"HelloWorld", engine()->GetText().c_str());
+
+  engine()->Insert(0, L"****");
+  EXPECT_STREQ(L"*HelloWorld", engine()->GetText().c_str());
+}
+
+TEST_F(CFDE_TextEditEngineTest, InsertGrowGap) {
+  engine()->Insert(0, L"||");
+  for (size_t i = 1; i < 1023; ++i) {
+    engine()->Insert(i, L"a");
+  }
+  WideString result = engine()->GetText();
+  ASSERT_EQ(result.GetLength(), 1024u);
+  EXPECT_EQ(result[0], L'|');
+  EXPECT_EQ(result[1], L'a');
+  EXPECT_EQ(result[2], L'a');
+  // ...
+  EXPECT_EQ(result[1022], L'a');
+  EXPECT_EQ(result[1023], L'|');
+}
+
 TEST_F(CFDE_TextEditEngineTest, Delete) {
   EXPECT_STREQ(L"", engine()->Delete(0, 50).c_str());
   EXPECT_STREQ(L"", engine()->GetText().c_str());
@@ -415,9 +464,41 @@
   engine()->Insert(0, L"Hello World");
   EXPECT_EQ(0U, engine()->GetIndexForPoint({0.0f, 0.0f}));
   EXPECT_EQ(11U, engine()->GetIndexForPoint({999999.0f, 9999999.0f}));
+  EXPECT_EQ(11U, engine()->GetIndexForPoint({999999.0f, 0.0f}));
+  EXPECT_EQ(1U, engine()->GetIndexForPoint({5.0f, 5.0f}));
   EXPECT_EQ(1U, engine()->GetIndexForPoint({10.0f, 5.0f}));
 }
 
+TEST_F(CFDE_TextEditEngineTest, GetIndexForPointLineWrap) {
+  engine()->SetFontSize(10.0f);
+  engine()->Insert(0,
+                   L"A text long enough to span multiple lines and test "
+                   L"getting indexes on multi-line edits.");
+  EXPECT_EQ(0U, engine()->GetIndexForPoint({0.0f, 0.0f}));
+  EXPECT_EQ(87U, engine()->GetIndexForPoint({999999.0f, 9999999.0f}));
+  EXPECT_EQ(11U, engine()->GetIndexForPoint({999999.0f, 0.0f}));
+  EXPECT_EQ(12U, engine()->GetIndexForPoint({1.0f, 10.0f}));
+  EXPECT_EQ(1U, engine()->GetIndexForPoint({5.0f, 5.0f}));
+  EXPECT_EQ(2U, engine()->GetIndexForPoint({10.0f, 5.0f}));
+}
+
+TEST_F(CFDE_TextEditEngineTest, GetIndexForPointSpaceAtEnd) {
+  engine()->SetFontSize(10.0f);
+  engine()->Insert(0, L"Hello World ");
+  EXPECT_EQ(0U, engine()->GetIndexForPoint({0.0f, 0.0f}));
+  EXPECT_EQ(12U, engine()->GetIndexForPoint({999999.0f, 9999999.0f}));
+  EXPECT_EQ(12U, engine()->GetIndexForPoint({999999.0f, 0.0f}));
+}
+
+TEST_F(CFDE_TextEditEngineTest, GetIndexForPointLineBreaks) {
+  engine()->SetFontSize(10.0f);
+  engine()->Insert(0, L"Hello\nWorld");
+  EXPECT_EQ(0U, engine()->GetIndexForPoint({0.0f, 0.0f}));
+  EXPECT_EQ(5U, engine()->GetIndexForPoint({999999.0f, 0.0f}));
+  EXPECT_EQ(6U, engine()->GetIndexForPoint({0.0f, 10.0f}));
+  EXPECT_EQ(11U, engine()->GetIndexForPoint({999999.0f, 9999999.0f}));
+}
+
 TEST_F(CFDE_TextEditEngineTest, BoundsForWordAt) {
   size_t start_idx;
   size_t count;
diff --git a/xfa/fde/cfde_textout.cpp b/xfa/fde/cfde_textout.cpp
index 19e7ae6..cd419bd 100644
--- a/xfa/fde/cfde_textout.cpp
+++ b/xfa/fde/cfde_textout.cpp
@@ -9,10 +9,15 @@
 #include <algorithm>
 #include <utility>
 
+#include "build/build_config.h"
 #include "core/fxcrt/fx_coordinates.h"
 #include "core/fxcrt/fx_system.h"
 #include "core/fxge/cfx_font.h"
 #include "core/fxge/cfx_pathdata.h"
+#include "core/fxge/cfx_renderdevice.h"
+#include "core/fxge/cfx_substfont.h"
+#include "core/fxge/fx_font.h"
+#include "core/fxge/text_char_pos.h"
 #include "third_party/base/ptr_util.h"
 #include "third_party/base/stl_util.h"
 #include "xfa/fgas/font/cfgas_gefont.h"
@@ -36,84 +41,82 @@
 bool CFDE_TextOut::DrawString(CFX_RenderDevice* device,
                               FX_ARGB color,
                               const RetainPtr<CFGAS_GEFont>& pFont,
-                              FXTEXT_CHARPOS* pCharPos,
-                              int32_t iCount,
+                              pdfium::span<TextCharPos> pCharPos,
                               float fFontSize,
-                              const CFX_Matrix* pMatrix) {
-  ASSERT(pFont && pCharPos && iCount > 0);
+                              const CFX_Matrix& matrix) {
+  ASSERT(pFont);
+  ASSERT(!pCharPos.empty());
 
   CFX_Font* pFxFont = pFont->GetDevFont();
   if (FontStyleIsItalic(pFont->GetFontStyles()) && !pFxFont->IsItalic()) {
-    for (int32_t i = 0; i < iCount; ++i) {
-      static const float mc = 0.267949f;
-      float* pAM = pCharPos->m_AdjustMatrix;
-      pAM[2] = mc * pAM[0] + pAM[2];
-      pAM[3] = mc * pAM[1] + pAM[3];
-      ++pCharPos;
+    for (auto& pos : pCharPos) {
+      static constexpr float mc = 0.267949f;
+      pos.m_AdjustMatrix[2] += mc * pos.m_AdjustMatrix[0];
+      pos.m_AdjustMatrix[3] += mc * pos.m_AdjustMatrix[1];
     }
   }
 
-#if _FX_PLATFORM_ != _FX_PLATFORM_WINDOWS_
+#if !defined(OS_WIN)
   uint32_t dwFontStyle = pFont->GetFontStyles();
   CFX_Font FxFont;
   auto SubstFxFont = pdfium::MakeUnique<CFX_SubstFont>();
-  SubstFxFont->m_Weight = FontStyleIsBold(dwFontStyle) ? 700 : 400;
+  SubstFxFont->m_Weight = FontStyleIsForceBold(dwFontStyle) ? 700 : 400;
   SubstFxFont->m_ItalicAngle = FontStyleIsItalic(dwFontStyle) ? -12 : 0;
   SubstFxFont->m_WeightCJK = SubstFxFont->m_Weight;
   SubstFxFont->m_bItalicCJK = FontStyleIsItalic(dwFontStyle);
   FxFont.SetSubstFont(std::move(SubstFxFont));
-#endif  // _FX_PLATFORM_ != _FX_PLATFORM_WINDOWS_
+#endif
 
   RetainPtr<CFGAS_GEFont> pCurFont;
-  FXTEXT_CHARPOS* pCurCP = nullptr;
+  TextCharPos* pCurCP = nullptr;
   int32_t iCurCount = 0;
-  for (int32_t i = 0; i < iCount; ++i) {
+  for (auto& pos : pCharPos) {
     RetainPtr<CFGAS_GEFont> pSTFont =
-        pFont->GetSubstFont(static_cast<int32_t>(pCharPos->m_GlyphIndex));
-    pCharPos->m_GlyphIndex &= 0x00FFFFFF;
-    pCharPos->m_bFontStyle = false;
+        pFont->GetSubstFont(static_cast<int32_t>(pos.m_GlyphIndex));
+    pos.m_GlyphIndex &= 0x00FFFFFF;
+    pos.m_bFontStyle = false;
     if (pCurFont != pSTFont) {
       if (pCurFont) {
         pFxFont = pCurFont->GetDevFont();
 
         CFX_Font* font;
-#if _FX_PLATFORM_ != _FX_PLATFORM_WINDOWS_
+#if !defined(OS_WIN)
         FxFont.SetFace(pFxFont->GetFace());
+        FxFont.SetFontSpan(pFxFont->GetFontSpan());
         font = &FxFont;
 #else
         font = pFxFont;
-#endif  // _FX_PLATFORM_ != _FX_PLATFORM_WINDOWS_
+#endif
 
-        device->DrawNormalText(iCurCount, pCurCP, font, -fFontSize, pMatrix,
+        device->DrawNormalText(iCurCount, pCurCP, font, -fFontSize, matrix,
                                color, FXTEXT_CLEARTYPE);
       }
       pCurFont = pSTFont;
-      pCurCP = pCharPos;
+      pCurCP = &pos;
       iCurCount = 1;
     } else {
       ++iCurCount;
     }
-    ++pCharPos;
   }
 
   bool bRet = true;
   if (pCurFont && iCurCount) {
     pFxFont = pCurFont->GetDevFont();
     CFX_Font* font;
-#if _FX_PLATFORM_ != _FX_PLATFORM_WINDOWS_
+#if !defined(OS_WIN)
     FxFont.SetFace(pFxFont->GetFace());
+    FxFont.SetFontSpan(pFxFont->GetFontSpan());
     font = &FxFont;
 #else
     font = pFxFont;
-#endif  // _FX_PLATFORM_ != _FX_PLATFORM_WINDOWS_
+#endif
 
-    bRet = device->DrawNormalText(iCurCount, pCurCP, font, -fFontSize, pMatrix,
+    bRet = device->DrawNormalText(iCurCount, pCurCP, font, -fFontSize, matrix,
                                   color, FXTEXT_CLEARTYPE);
   }
-
-#if _FX_PLATFORM_ != _FX_PLATFORM_WINDOWS_
-  FxFont.SetFace(nullptr);
-#endif  // _FX_PLATFORM_ != _FX_PLATFORM_WINDOWS_
+#if defined _SKIA_SUPPORT_ || defined _SKIA_SUPPORT_PATHS_
+  device->Flush(false);
+#endif
 
   return bRet;
 }
@@ -125,21 +128,9 @@
 FDE_TTOPIECE::~FDE_TTOPIECE() = default;
 
 CFDE_TextOut::CFDE_TextOut()
-    : m_pTxtBreak(pdfium::MakeUnique<CFX_TxtBreak>()),
-      m_pFont(nullptr),
-      m_fFontSize(12.0f),
-      m_fLineSpace(m_fFontSize),
-      m_fLinePos(0.0f),
-      m_fTolerance(0.0f),
-      m_iAlignment(FDE_TextAlignment::kTopLeft),
-      m_TxtColor(0xFF000000),
-      m_dwTxtBkStyles(0),
-      m_ttoLines(5),
-      m_iCurLine(0),
-      m_iCurPiece(0),
-      m_iTotalLines(0) {}
+    : m_pTxtBreak(pdfium::MakeUnique<CFX_TxtBreak>()), m_ttoLines(5) {}
 
-CFDE_TextOut::~CFDE_TextOut() {}
+CFDE_TextOut::~CFDE_TextOut() = default;
 
 void CFDE_TextOut::SetFont(const RetainPtr<CFGAS_GEFont>& pFont) {
   ASSERT(pFont);
@@ -192,32 +183,33 @@
   m_pTxtBreak->SetLineBreakTolerance(m_fTolerance);
 }
 
-void CFDE_TextOut::CalcLogicSize(const WideString& str, CFX_SizeF& size) {
-  CFX_RectF rtText(0.0f, 0.0f, size.width, size.height);
-  CalcLogicSize(str, rtText);
-  size = rtText.Size();
+void CFDE_TextOut::CalcLogicSize(WideStringView str, CFX_SizeF* pSize) {
+  CFX_RectF rtText(0.0f, 0.0f, pSize->width, pSize->height);
+  CalcLogicSize(str, &rtText);
+  *pSize = rtText.Size();
 }
 
-void CFDE_TextOut::CalcLogicSize(const WideString& str, CFX_RectF& rect) {
+void CFDE_TextOut::CalcLogicSize(WideStringView str, CFX_RectF* pRect) {
   if (str.IsEmpty()) {
-    rect.width = 0.0f;
-    rect.height = 0.0f;
+    pRect->width = 0.0f;
+    pRect->height = 0.0f;
     return;
   }
 
-  ASSERT(m_pFont && m_fFontSize >= 1.0f);
+  ASSERT(m_pFont);
+  ASSERT(m_fFontSize >= 1.0f);
 
   if (!m_Styles.single_line_) {
-    if (rect.Width() < 1.0f)
-      rect.width = m_fFontSize * 1000.0f;
+    if (pRect->Width() < 1.0f)
+      pRect->width = m_fFontSize * 1000.0f;
 
-    m_pTxtBreak->SetLineWidth(rect.Width());
+    m_pTxtBreak->SetLineWidth(pRect->Width());
   }
 
   m_iTotalLines = 0;
   float fWidth = 0.0f;
   float fHeight = 0.0f;
-  float fStartPos = rect.right();
+  float fStartPos = pRect->right();
   CFX_BreakType dwBreakStatus = CFX_BreakType::None;
   bool break_char_is_set = false;
   for (const wchar_t& wch : str) {
@@ -227,32 +219,32 @@
     }
     dwBreakStatus = m_pTxtBreak->AppendChar(wch);
     if (!CFX_BreakTypeNoneOrPiece(dwBreakStatus))
-      RetrieveLineWidth(dwBreakStatus, fStartPos, fWidth, fHeight);
+      RetrieveLineWidth(dwBreakStatus, &fStartPos, &fWidth, &fHeight);
   }
 
   dwBreakStatus = m_pTxtBreak->EndBreak(CFX_BreakType::Paragraph);
   if (!CFX_BreakTypeNoneOrPiece(dwBreakStatus))
-    RetrieveLineWidth(dwBreakStatus, fStartPos, fWidth, fHeight);
+    RetrieveLineWidth(dwBreakStatus, &fStartPos, &fWidth, &fHeight);
 
   m_pTxtBreak->Reset();
-  float fInc = rect.Height() - fHeight;
+  float fInc = pRect->Height() - fHeight;
   if (TextAlignmentVerticallyCentered(m_iAlignment))
     fInc /= 2.0f;
   else if (IsTextAlignmentTop(m_iAlignment))
     fInc = 0.0f;
 
-  rect.left += fStartPos;
-  rect.top += fInc;
-  rect.width = std::min(fWidth, rect.Width());
-  rect.height = fHeight;
+  pRect->left += fStartPos;
+  pRect->top += fInc;
+  pRect->width = std::min(fWidth, pRect->Width());
+  pRect->height = fHeight;
   if (m_Styles.last_line_height_)
-    rect.height -= m_fLineSpace - m_fFontSize;
+    pRect->height -= m_fLineSpace - m_fFontSize;
 }
 
 bool CFDE_TextOut::RetrieveLineWidth(CFX_BreakType dwBreakStatus,
-                                     float& fStartPos,
-                                     float& fWidth,
-                                     float& fHeight) {
+                                     float* pStartPos,
+                                     float* pWidth,
+                                     float* pHeight) {
   if (CFX_BreakTypeNoneOrPiece(dwBreakStatus))
     return false;
 
@@ -261,27 +253,28 @@
   for (int32_t i = 0; i < m_pTxtBreak->CountBreakPieces(); i++) {
     const CFX_BreakPiece* pPiece = m_pTxtBreak->GetBreakPieceUnstable(i);
     fLineWidth += static_cast<float>(pPiece->m_iWidth) / 20000.0f;
-    fStartPos =
-        std::min(fStartPos, static_cast<float>(pPiece->m_iStartPos) / 20000.0f);
+    *pStartPos = std::min(*pStartPos,
+                          static_cast<float>(pPiece->m_iStartPos) / 20000.0f);
   }
   m_pTxtBreak->ClearBreakPieces();
 
   if (dwBreakStatus == CFX_BreakType::Paragraph)
     m_pTxtBreak->Reset();
   if (!m_Styles.line_wrap_ && dwBreakStatus == CFX_BreakType::Line) {
-    fWidth += fLineWidth;
+    *pWidth += fLineWidth;
   } else {
-    fWidth = std::max(fWidth, fLineWidth);
-    fHeight += fLineStep;
+    *pWidth = std::max(*pWidth, fLineWidth);
+    *pHeight += fLineStep;
   }
   ++m_iTotalLines;
   return true;
 }
 
 void CFDE_TextOut::DrawLogicText(CFX_RenderDevice* device,
-                                 const WideStringView& str,
+                                 WideStringView str,
                                  const CFX_RectF& rect) {
-  ASSERT(m_pFont && m_fFontSize >= 1.0f);
+  ASSERT(m_pFont);
+  ASSERT(m_fFontSize >= 1.0f);
 
   if (str.IsEmpty())
     return;
@@ -303,7 +296,7 @@
   CFX_RectF rtClip = m_Matrix.TransformRect(CFX_RectF());
   device->SaveState();
   if (rtClip.Width() > 0.0f && rtClip.Height() > 0.0f)
-    device->SetClip_Rect(rtClip);
+    device->SetClip_Rect(rtClip.GetOuterRect());
 
   for (auto& line : m_ttoLines) {
     int32_t iPieces = line.GetSize();
@@ -312,10 +305,11 @@
       if (!pPiece)
         continue;
 
-      int32_t iCount = GetDisplayPos(pPiece);
-      if (iCount > 0) {
-        CFDE_TextOut::DrawString(device, m_TxtColor, m_pFont, m_CharPos.data(),
-                                 iCount, m_fFontSize, &m_Matrix);
+      size_t szCount = GetDisplayPos(pPiece);
+      if (szCount > 0) {
+        CFDE_TextOut::DrawString(device, m_TxtColor, m_pFont,
+                                 {m_CharPos.data(), szCount}, m_fFontSize,
+                                 m_Matrix);
       }
     }
   }
@@ -343,7 +337,7 @@
       continue;
 
     bool bEndofLine =
-        RetrievePieces(dwBreakStatus, iStartChar, iPieceWidths, false, rect);
+        RetrievePieces(dwBreakStatus, false, rect, &iStartChar, &iPieceWidths);
     if (bEndofLine &&
         (m_Styles.line_wrap_ || dwBreakStatus == CFX_BreakType::Paragraph ||
          dwBreakStatus == CFX_BreakType::Page)) {
@@ -361,32 +355,32 @@
 
   dwBreakStatus = m_pTxtBreak->EndBreak(CFX_BreakType::Paragraph);
   if (!CFX_BreakTypeNoneOrPiece(dwBreakStatus) && !bRet)
-    RetrievePieces(dwBreakStatus, iStartChar, iPieceWidths, false, rect);
+    RetrievePieces(dwBreakStatus, false, rect, &iStartChar, &iPieceWidths);
 
   m_pTxtBreak->ClearBreakPieces();
   m_pTxtBreak->Reset();
 }
 
 bool CFDE_TextOut::RetrievePieces(CFX_BreakType dwBreakStatus,
-                                  int32_t& iStartChar,
-                                  int32_t& iPieceWidths,
                                   bool bReload,
-                                  const CFX_RectF& rect) {
+                                  const CFX_RectF& rect,
+                                  int32_t* pStartChar,
+                                  int32_t* pPieceWidths) {
   float fLineStep = (m_fLineSpace > m_fFontSize) ? m_fLineSpace : m_fFontSize;
   bool bNeedReload = false;
-  int32_t iLineWidth = FXSYS_round(rect.Width() * 20000.0f);
+  int32_t iLineWidth = FXSYS_roundf(rect.Width() * 20000.0f);
   int32_t iCount = m_pTxtBreak->CountBreakPieces();
   for (int32_t i = 0; i < iCount; i++) {
     const CFX_BreakPiece* pPiece = m_pTxtBreak->GetBreakPieceUnstable(i);
     int32_t iPieceChars = pPiece->GetLength();
-    int32_t iChar = iStartChar;
+    int32_t iChar = *pStartChar;
     int32_t iWidth = 0;
     int32_t j = 0;
     for (; j < iPieceChars; j++) {
       const CFX_Char* pTC = pPiece->GetChar(j);
       int32_t iCurCharWidth = pTC->m_iCharWidth > 0 ? pTC->m_iCharWidth : 0;
       if (m_Styles.single_line_ || !m_Styles.line_wrap_) {
-        if (iLineWidth - iPieceWidths - iWidth < iCurCharWidth) {
+        if (iLineWidth - *pPieceWidths - iWidth < iCurCharWidth) {
           bNeedReload = true;
           break;
         }
@@ -399,7 +393,7 @@
       m_ttoLines[m_iCurLine].SetNewReload(true);
     } else if (j > 0) {
       FDE_TTOPIECE ttoPiece;
-      ttoPiece.iStartChar = iStartChar;
+      ttoPiece.iStartChar = *pStartChar;
       ttoPiece.iChars = j;
       ttoPiece.dwCharStyles = pPiece->m_dwCharStyles;
       ttoPiece.rtPiece = CFX_RectF(
@@ -411,8 +405,8 @@
 
       AppendPiece(ttoPiece, bNeedReload, (bReload && i == iCount - 1));
     }
-    iStartChar += iPieceChars;
-    iPieceWidths += iWidth;
+    *pStartChar += iPieceChars;
+    *pPieceWidths += iWidth;
   }
   m_pTxtBreak->ClearBreakPieces();
 
@@ -458,24 +452,23 @@
 }
 
 void CFDE_TextOut::ReloadLinePiece(CFDE_TTOLine* pLine, const CFX_RectF& rect) {
-  const wchar_t* pwsStr = m_wsText.c_str();
-  int32_t iPieceWidths = 0;
-
+  pdfium::span<const wchar_t> text_span = m_wsText.span();
   FDE_TTOPIECE* pPiece = pLine->GetPtrAt(0);
   int32_t iStartChar = pPiece->iStartChar;
   int32_t iPieceCount = pLine->GetSize();
+  int32_t iPieceWidths = 0;
   int32_t iPieceIndex = 0;
   CFX_BreakType dwBreakStatus = CFX_BreakType::None;
   m_fLinePos = pPiece->rtPiece.top;
   while (iPieceIndex < iPieceCount) {
-    int32_t iStar = iStartChar;
-    int32_t iEnd = pPiece->iChars + iStar;
-    while (iStar < iEnd) {
-      dwBreakStatus = m_pTxtBreak->AppendChar(*(pwsStr + iStar));
+    int32_t iStart = iStartChar;
+    int32_t iEnd = pPiece->iChars + iStart;
+    while (iStart < iEnd) {
+      dwBreakStatus = m_pTxtBreak->AppendChar(text_span[iStart]);
       if (!CFX_BreakTypeNoneOrPiece(dwBreakStatus))
-        RetrievePieces(dwBreakStatus, iStartChar, iPieceWidths, true, rect);
+        RetrievePieces(dwBreakStatus, true, rect, &iStartChar, &iPieceWidths);
 
-      ++iStar;
+      ++iStart;
     }
     ++iPieceIndex;
     pPiece = pLine->GetPtrAt(iPieceIndex);
@@ -483,7 +476,7 @@
 
   dwBreakStatus = m_pTxtBreak->EndBreak(CFX_BreakType::Paragraph);
   if (!CFX_BreakTypeNoneOrPiece(dwBreakStatus))
-    RetrievePieces(dwBreakStatus, iStartChar, iPieceWidths, true, rect);
+    RetrievePieces(dwBreakStatus, true, rect, &iStartChar, &iPieceWidths);
 
   m_pTxtBreak->Reset();
 }
@@ -512,13 +505,13 @@
   }
 }
 
-int32_t CFDE_TextOut::GetDisplayPos(FDE_TTOPIECE* pPiece) {
+size_t CFDE_TextOut::GetDisplayPos(FDE_TTOPIECE* pPiece) {
   ASSERT(pPiece->iChars >= 0);
 
   if (pdfium::CollectionSize<int32_t>(m_CharPos) < pPiece->iChars)
-    m_CharPos.resize(pPiece->iChars, FXTEXT_CHARPOS());
+    m_CharPos.resize(pPiece->iChars, TextCharPos());
 
-  FX_TXTRUN tr;
+  CFX_TxtBreak::Run tr;
   tr.wsStr = m_wsText + pPiece->iStartChar;
   tr.pWidths = &m_CharWidths[pPiece->iStartChar];
   tr.iLength = pPiece->iChars;
diff --git a/xfa/fde/cfde_textout.h b/xfa/fde/cfde_textout.h
index 6b6878e..bb65d28 100644
--- a/xfa/fde/cfde_textout.h
+++ b/xfa/fde/cfde_textout.h
@@ -11,26 +11,36 @@
 #include <memory>
 #include <vector>
 
-#include "core/fxcrt/cfx_char.h"
-#include "core/fxge/cfx_defaultrenderdevice.h"
-#include "core/fxge/cfx_renderdevice.h"
 #include "core/fxge/fx_dib.h"
+#include "third_party/base/span.h"
 #include "xfa/fde/cfde_data.h"
+#include "xfa/fgas/layout/cfx_char.h"
 
 class CFDE_RenderDevice;
 class CFGAS_GEFont;
 class CFX_RenderDevice;
 class CFX_TxtBreak;
+class TextCharPos;
+
+struct FDE_TTOPIECE {
+  FDE_TTOPIECE();
+  FDE_TTOPIECE(const FDE_TTOPIECE& that);
+  ~FDE_TTOPIECE();
+
+  int32_t iStartChar;
+  int32_t iChars;
+  uint32_t dwCharStyles;
+  CFX_RectF rtPiece;
+};
 
 class CFDE_TextOut {
  public:
   static bool DrawString(CFX_RenderDevice* device,
                          FX_ARGB color,
                          const RetainPtr<CFGAS_GEFont>& pFont,
-                         FXTEXT_CHARPOS* pCharPos,
-                         int32_t iCount,
+                         pdfium::span<TextCharPos> pCharPos,
                          float fFontSize,
-                         const CFX_Matrix* pMatrix);
+                         const CFX_Matrix& matrix);
 
   CFDE_TextOut();
   ~CFDE_TextOut();
@@ -44,10 +54,10 @@
   void SetMatrix(const CFX_Matrix& matrix) { m_Matrix = matrix; }
   void SetLineBreakTolerance(float fTolerance);
 
-  void CalcLogicSize(const WideString& str, CFX_SizeF& size);
-  void CalcLogicSize(const WideString& str, CFX_RectF& rect);
+  void CalcLogicSize(WideStringView str, CFX_SizeF* pSize);
+  void CalcLogicSize(WideStringView str, CFX_RectF* pRect);
   void DrawLogicText(CFX_RenderDevice* device,
-                     const WideStringView& str,
+                     WideStringView str,
                      const CFX_RectF& rect);
   int32_t GetTotalLines() const { return m_iTotalLines; }
 
@@ -71,40 +81,40 @@
   };
 
   bool RetrieveLineWidth(CFX_BreakType dwBreakStatus,
-                         float& fStartPos,
-                         float& fWidth,
-                         float& fHeight);
+                         float* pStartPos,
+                         float* pWidth,
+                         float* pHeight);
   void LoadText(const WideString& str, const CFX_RectF& rect);
 
   void Reload(const CFX_RectF& rect);
   void ReloadLinePiece(CFDE_TTOLine* pLine, const CFX_RectF& rect);
   bool RetrievePieces(CFX_BreakType dwBreakStatus,
-                      int32_t& iStartChar,
-                      int32_t& iPieceWidths,
                       bool bReload,
-                      const CFX_RectF& rect);
+                      const CFX_RectF& rect,
+                      int32_t* pStartChar,
+                      int32_t* pPieceWidths);
   void AppendPiece(const FDE_TTOPIECE& ttoPiece, bool bNeedReload, bool bEnd);
   void DoAlignment(const CFX_RectF& rect);
-  int32_t GetDisplayPos(FDE_TTOPIECE* pPiece);
+  size_t GetDisplayPos(FDE_TTOPIECE* pPiece);
 
-  std::unique_ptr<CFX_TxtBreak> m_pTxtBreak;
+  std::unique_ptr<CFX_TxtBreak> const m_pTxtBreak;
   RetainPtr<CFGAS_GEFont> m_pFont;
-  float m_fFontSize;
-  float m_fLineSpace;
-  float m_fLinePos;
-  float m_fTolerance;
-  FDE_TextAlignment m_iAlignment;
+  float m_fFontSize = 12.0f;
+  float m_fLineSpace = 12.0f;
+  float m_fLinePos = 0.0f;
+  float m_fTolerance = 0.0f;
+  FDE_TextAlignment m_iAlignment = FDE_TextAlignment::kTopLeft;
   FDE_TextStyle m_Styles;
   std::vector<int32_t> m_CharWidths;
-  FX_ARGB m_TxtColor;
-  uint32_t m_dwTxtBkStyles;
+  FX_ARGB m_TxtColor = 0xFF000000;
+  uint32_t m_dwTxtBkStyles = 0;
   WideString m_wsText;
   CFX_Matrix m_Matrix;
   std::deque<CFDE_TTOLine> m_ttoLines;
-  int32_t m_iCurLine;
-  int32_t m_iCurPiece;
-  int32_t m_iTotalLines;
-  std::vector<FXTEXT_CHARPOS> m_CharPos;
+  int32_t m_iCurLine = 0;
+  int32_t m_iCurPiece = 0;
+  int32_t m_iTotalLines = 0;
+  std::vector<TextCharPos> m_CharPos;
 };
 
 #endif  // XFA_FDE_CFDE_TEXTOUT_H_
diff --git a/xfa/fde/cfde_wordbreak_data.cpp b/xfa/fde/cfde_wordbreak_data.cpp
index 3c4864b..9331253 100644
--- a/xfa/fde/cfde_wordbreak_data.cpp
+++ b/xfa/fde/cfde_wordbreak_data.cpp
@@ -6,115 +6,81 @@
 
 #include "xfa/fde/cfde_wordbreak_data.h"
 
+#include "core/fxcrt/fx_memory.h"
+#include "core/fxcrt/fx_system.h"
+
 namespace {
 
-enum WordBreakValue : uint16_t {
-  kWordBreakValueNone = 1 << 0,
-  kWordBreakValueCR = 1 << 1,
-  kWordBreakValueLF = 1 << 2,
-  kWordBreakValueNewLine = 1 << 3,
-  kWordBreakValueExtend = 1 << 4,
-  kWordBreakValueFormat = 1 << 5,
-  kWordBreakValueKataKana = 1 << 6,
-  kWordBreakValueALetter = 1 << 7,
-  kWordBreakValueMidLetter = 1 << 8,
-  kWordBreakValueMidNum = 1 << 9,
-  kWordBreakValueMidNumLet = 1 << 10,
-  kWordBreakValueNumeric = 1 << 11,
-  kWordBreakValueExtendNumLet = 1 << 12,
+enum WordBreakMask : uint16_t {
+  kWordBreakMaskNone = 1 << static_cast<int>(WordBreakProperty::kNone),
+  kWordBreakMaskCR = 1 << static_cast<int>(WordBreakProperty::kCR),
+  kWordBreakMaskLF = 1 << static_cast<int>(WordBreakProperty::kLF),
+  kWordBreakMaskNewLine = 1 << static_cast<int>(WordBreakProperty::kNewLine),
+  kWordBreakMaskExtend = 1 << static_cast<int>(WordBreakProperty::kExtend),
+  kWordBreakMaskFormat = 1 << static_cast<int>(WordBreakProperty::kFormat),
+  kWordBreakMaskKataKana = 1 << static_cast<int>(WordBreakProperty::kKataKana),
+  kWordBreakMaskALetter = 1 << static_cast<int>(WordBreakProperty::kALetter),
+  kWordBreakMaskMidLetter = 1
+                            << static_cast<int>(WordBreakProperty::kMidLetter),
+  kWordBreakMaskMidNum = 1 << static_cast<int>(WordBreakProperty::kMidNum),
+  kWordBreakMaskMidNumLet = 1
+                            << static_cast<int>(WordBreakProperty::kMidNumLet),
+  kWordBreakMaskNumeric = 1 << static_cast<int>(WordBreakProperty::kNumeric),
+  kWordBreakMaskExtendNumLet =
+      1 << static_cast<int>(WordBreakProperty::kExtendNumLet),
 };
 
-static_assert(kWordBreakValueNone ==
-                  (1 << static_cast<int>(WordBreakProperty::kNone)),
-              "WordBreakValue must match");
-static_assert(kWordBreakValueCR ==
-                  (1 << static_cast<int>(WordBreakProperty::kCR)),
-              "WordBreakValue must match");
-static_assert(kWordBreakValueLF ==
-                  (1 << static_cast<int>(WordBreakProperty::kLF)),
-              "WordBreakValue must match");
-static_assert(kWordBreakValueNewLine ==
-                  (1 << static_cast<int>(WordBreakProperty::kNewLine)),
-              "WordBreakValue must match");
-static_assert(kWordBreakValueExtend ==
-                  (1 << static_cast<int>(WordBreakProperty::kExtend)),
-              "WordBreakValue must match");
-static_assert(kWordBreakValueFormat ==
-                  (1 << static_cast<int>(WordBreakProperty::kFormat)),
-              "WordBreakValue must match");
-static_assert(kWordBreakValueKataKana ==
-                  (1 << static_cast<int>(WordBreakProperty::kKataKana)),
-              "WordBreakValue must match");
-static_assert(kWordBreakValueALetter ==
-                  (1 << static_cast<int>(WordBreakProperty::kALetter)),
-              "WordBreakValue must match");
-static_assert(kWordBreakValueMidLetter ==
-                  (1 << static_cast<int>(WordBreakProperty::kMidLetter)),
-              "WordBreakValue must match");
-static_assert(kWordBreakValueMidNum ==
-                  (1 << static_cast<int>(WordBreakProperty::kMidNum)),
-              "WordBreakValue must match");
-static_assert(kWordBreakValueMidNumLet ==
-                  (1 << static_cast<int>(WordBreakProperty::kMidNumLet)),
-              "WordBreakValue must match");
-static_assert(kWordBreakValueNumeric ==
-                  (1 << static_cast<int>(WordBreakProperty::kNumeric)),
-              "WordBreakValue must match");
-static_assert(kWordBreakValueExtendNumLet ==
-                  (1 << static_cast<int>(WordBreakProperty::kExtendNumLet)),
-              "WordBreakValue must match");
-
-}  // namespace
-
-const uint16_t gs_FX_WordBreak_Table[] = {
+const uint16_t kWordBreakTable[] = {
     // WordBreakProperty::kNone
     0xFFFF,
 
     // WordBreakProperty::kCR
-    static_cast<uint16_t>(~(kWordBreakValueLF | kWordBreakValueCR)),
+    static_cast<uint16_t>(~(kWordBreakMaskLF | kWordBreakMaskCR)),
 
     // WordBreakProperty::kLF
-    static_cast<uint16_t>(~(kWordBreakValueLF)),
+    static_cast<uint16_t>(~(kWordBreakMaskLF)),
 
     // WordBreakProperty::kNewLine
-    static_cast<uint16_t>(~(kWordBreakValueLF)),
+    static_cast<uint16_t>(~(kWordBreakMaskLF)),
 
     // WordBreakProperty::kExtend
-    static_cast<uint16_t>(~(kWordBreakValueLF)),
+    static_cast<uint16_t>(~(kWordBreakMaskLF)),
 
     // WordBreakPropery:: kFormat
-    static_cast<uint16_t>(~(kWordBreakValueLF)),
+    static_cast<uint16_t>(~(kWordBreakMaskLF)),
 
     // WordBreakProperty::kKataKana
-    static_cast<uint16_t>(~(kWordBreakValueLF | kWordBreakValueKataKana |
-                            kWordBreakValueExtendNumLet)),
+    static_cast<uint16_t>(~(kWordBreakMaskLF | kWordBreakMaskKataKana |
+                            kWordBreakMaskExtendNumLet)),
 
     // WordBreakProperty::kALetter
-    static_cast<uint16_t>(~(kWordBreakValueLF | kWordBreakValueALetter |
-                            kWordBreakValueNumeric |
-                            kWordBreakValueExtendNumLet)),
+    static_cast<uint16_t>(~(kWordBreakMaskLF | kWordBreakMaskALetter |
+                            kWordBreakMaskNumeric |
+                            kWordBreakMaskExtendNumLet)),
 
     // WordBreakProperty::kMidLetter
-    static_cast<uint16_t>(~(kWordBreakValueLF)),
+    static_cast<uint16_t>(~(kWordBreakMaskLF)),
 
     // WordBreakProperty::kMidNum
-    static_cast<uint16_t>(~(kWordBreakValueLF)),
+    static_cast<uint16_t>(~(kWordBreakMaskLF)),
 
     // WordBreakProperty::kMidNumLet
-    static_cast<uint16_t>(~(kWordBreakValueLF)),
+    static_cast<uint16_t>(~(kWordBreakMaskLF)),
 
     // WordBreakProperty::kNumeric
-    static_cast<uint16_t>(~(kWordBreakValueLF | kWordBreakValueALetter |
-                            kWordBreakValueNumeric |
-                            kWordBreakValueExtendNumLet)),
+    static_cast<uint16_t>(~(kWordBreakMaskLF | kWordBreakMaskALetter |
+                            kWordBreakMaskNumeric |
+                            kWordBreakMaskExtendNumLet)),
 
     // WordBreakProperty::kExtendNumLet
-    static_cast<uint16_t>(~(kWordBreakValueLF | kWordBreakValueKataKana |
-                            kWordBreakValueALetter | kWordBreakValueNumeric |
-                            kWordBreakValueExtendNumLet)),
+    static_cast<uint16_t>(~(kWordBreakMaskLF | kWordBreakMaskKataKana |
+                            kWordBreakMaskALetter | kWordBreakMaskNumeric |
+                            kWordBreakMaskExtendNumLet)),
 };
 
-const uint8_t gs_FX_WordBreak_CodePointProperties[(0xFFFF - 1) / 2 + 1] = {
+// Table of |WordBreakProperty| for each of the possible uint16_t values,
+// packed as nibbles, with the low nibble first.
+const uint8_t kCodePointProperties[32768] = {
     0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00,
     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x90, 0xA0,
     0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0x89, 0x00, 0x00, 0x07, 0x77, 0x77, 0x77,
@@ -2847,3 +2813,22 @@
     0x00, 0x77, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     0x00, 0x00, 0x00, 0x00, 0x05, 0x55, 0x00, 0x00,
 };
+
+}  // namespace
+
+bool FX_CheckStateChangeForWordBreak(WordBreakProperty from,
+                                     WordBreakProperty to) {
+  ASSERT(static_cast<int>(from) < 13);
+  return !!(kWordBreakTable[static_cast<int>(from)] &
+            static_cast<uint16_t>(1 << static_cast<int>(to)));
+}
+
+WordBreakProperty FX_GetWordBreakProperty(wchar_t wcCodePoint) {
+  size_t index = static_cast<size_t>(wcCodePoint) / 2;
+  if (index >= FX_ArraySize(kCodePointProperties))
+    return WordBreakProperty::kNone;
+
+  uint8_t dwProperty = kCodePointProperties[index];
+  return static_cast<WordBreakProperty>((wcCodePoint & 1) ? (dwProperty & 0x0F)
+                                                          : (dwProperty >> 4));
+}
diff --git a/xfa/fde/cfde_wordbreak_data.h b/xfa/fde/cfde_wordbreak_data.h
index 28e26cc..1465f5c 100644
--- a/xfa/fde/cfde_wordbreak_data.h
+++ b/xfa/fde/cfde_wordbreak_data.h
@@ -10,6 +10,8 @@
 #include <stdint.h>
 
 enum class WordBreakProperty : uint8_t {
+  // Internal tables depend on constants computed from these values, so do
+  // not re-order.
   kNone = 0,
   kCR,
   kLF,
@@ -25,7 +27,8 @@
   kExtendNumLet,
 };
 
-extern const uint16_t gs_FX_WordBreak_Table[];
-extern const uint8_t gs_FX_WordBreak_CodePointProperties[];
+bool FX_CheckStateChangeForWordBreak(WordBreakProperty from,
+                                     WordBreakProperty to);
+WordBreakProperty FX_GetWordBreakProperty(wchar_t wcCodePoint);
 
 #endif  // XFA_FDE_CFDE_WORDBREAK_DATA_H_
diff --git a/xfa/fgas/BUILD.gn b/xfa/fgas/BUILD.gn
new file mode 100644
index 0000000..c4c68b2
--- /dev/null
+++ b/xfa/fgas/BUILD.gn
@@ -0,0 +1,61 @@
+# Copyright 2018 The 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.
+
+import("../../pdfium.gni")
+import("../../testing/test.gni")
+
+assert(pdf_enable_xfa)
+
+source_set("fgas") {
+  sources = [
+    "crt/cfgas_decimal.cpp",
+    "crt/cfgas_decimal.h",
+    "crt/cfgas_stringformatter.cpp",
+    "crt/cfgas_stringformatter.h",
+    "crt/locale_iface.h",
+    "crt/locale_mgr_iface.h",
+    "font/cfgas_defaultfontmanager.cpp",
+    "font/cfgas_defaultfontmanager.h",
+    "font/cfgas_fontmgr.cpp",
+    "font/cfgas_fontmgr.h",
+    "font/cfgas_gefont.cpp",
+    "font/cfgas_gefont.h",
+    "font/cfgas_pdffontmgr.cpp",
+    "font/cfgas_pdffontmgr.h",
+    "font/fgas_fontutils.cpp",
+    "font/fgas_fontutils.h",
+  ]
+  deps = [
+    "../../core/fpdfapi/font",
+    "../../core/fpdfapi/page",
+    "../../core/fpdfapi/parser",
+    "../../core/fxcrt",
+    "../../core/fxge",
+  ]
+  configs += [
+    "../../:pdfium_core_config",
+    "../:xfa_warnings",
+  ]
+  visibility = [ "../../*" ]
+
+  if (!is_win) {
+    sources += [
+      "font/cfx_fontsourceenum_file.cpp",
+      "font/cfx_fontsourceenum_file.h",
+    ]
+  }
+}
+
+pdfium_unittest_source_set("unittests") {
+  sources = [
+    "crt/cfgas_decimal_unittest.cpp",
+    "crt/cfgas_stringformatter_unittest.cpp",
+  ]
+  deps = [
+    ":fgas",
+    "../../core/fpdfapi/page",
+    "../fxfa/parser",
+  ]
+  pdfium_root_dir = "../../"
+}
diff --git a/xfa/fgas/crt/cfgas_decimal.cpp b/xfa/fgas/crt/cfgas_decimal.cpp
new file mode 100644
index 0000000..6a8a759
--- /dev/null
+++ b/xfa/fgas/crt/cfgas_decimal.cpp
@@ -0,0 +1,451 @@
+// 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
+
+#include "xfa/fgas/crt/cfgas_decimal.h"
+
+#include <algorithm>
+#include <limits>
+#include <utility>
+
+#include "core/fxcrt/fx_extension.h"
+
+#define FXMATH_DECIMAL_SCALELIMIT 0x1c
+#define FXMATH_DECIMAL_RSHIFT32BIT(x) ((x) >> 0x10 >> 0x10)
+#define FXMATH_DECIMAL_LSHIFT32BIT(x) ((x) << 0x10 << 0x10)
+
+namespace {
+
+inline uint8_t decimal_helper_div10(uint64_t& phi,
+                                    uint64_t& pmid,
+                                    uint64_t& plo) {
+  uint8_t retVal;
+  pmid += FXMATH_DECIMAL_LSHIFT32BIT(phi % 0xA);
+  phi /= 0xA;
+  plo += FXMATH_DECIMAL_LSHIFT32BIT(pmid % 0xA);
+  pmid /= 0xA;
+  retVal = plo % 0xA;
+  plo /= 0xA;
+  return retVal;
+}
+
+inline uint8_t decimal_helper_div10_any(uint64_t nums[], uint8_t numcount) {
+  uint8_t retVal = 0;
+  for (int i = numcount - 1; i > 0; i--) {
+    nums[i - 1] += FXMATH_DECIMAL_LSHIFT32BIT(nums[i] % 0xA);
+    nums[i] /= 0xA;
+  }
+  if (numcount) {
+    retVal = nums[0] % 0xA;
+    nums[0] /= 0xA;
+  }
+  return retVal;
+}
+
+inline void decimal_helper_mul10(uint64_t& phi, uint64_t& pmid, uint64_t& plo) {
+  plo *= 0xA;
+  pmid = pmid * 0xA + FXMATH_DECIMAL_RSHIFT32BIT(plo);
+  plo = (uint32_t)plo;
+  phi = phi * 0xA + FXMATH_DECIMAL_RSHIFT32BIT(pmid);
+  pmid = (uint32_t)pmid;
+}
+
+inline void decimal_helper_mul10_any(uint64_t nums[], uint8_t numcount) {
+  nums[0] *= 0xA;
+  for (int i = 1; i < numcount; i++) {
+    nums[i] = nums[i] * 0xA + FXMATH_DECIMAL_RSHIFT32BIT(nums[i - 1]);
+    nums[i - 1] = (uint32_t)nums[i - 1];
+  }
+}
+
+inline void decimal_helper_normalize(uint64_t& phi,
+                                     uint64_t& pmid,
+                                     uint64_t& plo) {
+  phi += FXMATH_DECIMAL_RSHIFT32BIT(pmid);
+  pmid = (uint32_t)pmid;
+  pmid += FXMATH_DECIMAL_RSHIFT32BIT(plo);
+  plo = (uint32_t)plo;
+  phi += FXMATH_DECIMAL_RSHIFT32BIT(pmid);
+  pmid = (uint32_t)pmid;
+}
+
+inline void decimal_helper_normalize_any(uint64_t nums[], uint8_t len) {
+  for (int i = len - 2; i > 0; i--) {
+    nums[i + 1] += FXMATH_DECIMAL_RSHIFT32BIT(nums[i]);
+    nums[i] = (uint32_t)nums[i];
+  }
+  for (int i = 0; i < len - 1; i++) {
+    nums[i + 1] += FXMATH_DECIMAL_RSHIFT32BIT(nums[i]);
+    nums[i] = (uint32_t)nums[i];
+  }
+}
+
+inline int8_t decimal_helper_raw_compare_any(uint64_t a[],
+                                             uint8_t al,
+                                             uint64_t b[],
+                                             uint8_t bl) {
+  int8_t retVal = 0;
+  for (int i = std::max(al - 1, bl - 1); i >= 0; i--) {
+    uint64_t l = (i >= al ? 0 : a[i]), r = (i >= bl ? 0 : b[i]);
+    retVal += (l > r ? 1 : (l < r ? -1 : 0));
+    if (retVal)
+      return retVal;
+  }
+  return retVal;
+}
+
+inline void decimal_helper_dec_any(uint64_t a[], uint8_t al) {
+  for (int i = 0; i < al; i++) {
+    if (a[i]--)
+      return;
+  }
+}
+
+inline void decimal_helper_inc_any(uint64_t a[], uint8_t al) {
+  for (int i = 0; i < al; i++) {
+    a[i]++;
+    if ((uint32_t)a[i] == a[i])
+      return;
+    a[i] = 0;
+  }
+}
+
+inline void decimal_helper_raw_mul(uint64_t a[],
+                                   uint8_t al,
+                                   uint64_t b[],
+                                   uint8_t bl,
+                                   uint64_t c[],
+                                   uint8_t cl) {
+  ASSERT(al + bl <= cl);
+  for (int i = 0; i < cl; i++)
+    c[i] = 0;
+
+  for (int i = 0; i < al; i++) {
+    for (int j = 0; j < bl; j++) {
+      uint64_t m = (uint64_t)a[i] * b[j];
+      c[i + j] += (uint32_t)m;
+      c[i + j + 1] += FXMATH_DECIMAL_RSHIFT32BIT(m);
+    }
+  }
+  for (int i = 0; i < cl - 1; i++) {
+    c[i + 1] += FXMATH_DECIMAL_RSHIFT32BIT(c[i]);
+    c[i] = (uint32_t)c[i];
+  }
+  for (int i = 0; i < cl; i++)
+    c[i] = (uint32_t)c[i];
+}
+
+inline void decimal_helper_raw_div(uint64_t a[],
+                                   uint8_t al,
+                                   uint64_t b[],
+                                   uint8_t bl,
+                                   uint64_t c[],
+                                   uint8_t cl) {
+  for (int i = 0; i < cl; i++)
+    c[i] = 0;
+
+  uint64_t left[16] = {0};
+  uint64_t right[16] = {0};
+  left[0] = 0;
+  for (int i = 0; i < al; i++)
+    right[i] = a[i];
+
+  uint64_t tmp[16];
+  while (decimal_helper_raw_compare_any(left, al, right, al) <= 0) {
+    uint64_t cur[16];
+    for (int i = 0; i < al; i++)
+      cur[i] = left[i] + right[i];
+
+    for (int i = al - 1; i >= 0; i--) {
+      if (i)
+        cur[i - 1] += FXMATH_DECIMAL_LSHIFT32BIT(cur[i] % 2);
+      cur[i] /= 2;
+    }
+
+    decimal_helper_raw_mul(cur, al, b, bl, tmp, 16);
+    switch (decimal_helper_raw_compare_any(tmp, 16, a, al)) {
+      case -1:
+        for (int i = 0; i < 16; i++)
+          left[i] = cur[i];
+
+        left[0]++;
+        decimal_helper_normalize_any(left, al);
+        break;
+      case 1:
+        for (int i = 0; i < 16; i++)
+          right[i] = cur[i];
+        decimal_helper_dec_any(right, al);
+        break;
+      case 0:
+        for (int i = 0; i < std::min(al, cl); i++)
+          c[i] = cur[i];
+        return;
+    }
+  }
+  for (int i = 0; i < std::min(al, cl); i++)
+    c[i] = left[i];
+}
+
+inline bool decimal_helper_outofrange(uint64_t a[], uint8_t al, uint8_t goal) {
+  for (int i = goal; i < al; i++) {
+    if (a[i])
+      return true;
+  }
+  return false;
+}
+
+inline void decimal_helper_shrinkintorange(uint64_t a[],
+                                           uint8_t al,
+                                           uint8_t goal,
+                                           uint8_t& scale) {
+  bool bRoundUp = false;
+  while (scale != 0 && (scale > FXMATH_DECIMAL_SCALELIMIT ||
+                        decimal_helper_outofrange(a, al, goal))) {
+    bRoundUp = decimal_helper_div10_any(a, al) >= 5;
+    scale--;
+  }
+  if (bRoundUp) {
+    decimal_helper_normalize_any(a, goal);
+    decimal_helper_inc_any(a, goal);
+  }
+}
+
+inline void decimal_helper_truncate(uint64_t& phi,
+                                    uint64_t& pmid,
+                                    uint64_t& plo,
+                                    uint8_t& scale,
+                                    uint8_t minscale = 0) {
+  while (scale > minscale) {
+    uint64_t thi = phi, tmid = pmid, tlo = plo;
+    if (decimal_helper_div10(thi, tmid, tlo) != 0)
+      break;
+
+    phi = thi;
+    pmid = tmid;
+    plo = tlo;
+    scale--;
+  }
+}
+
+}  // namespace
+
+CFGAS_Decimal::CFGAS_Decimal() = default;
+
+CFGAS_Decimal::CFGAS_Decimal(uint64_t val)
+    : m_uMid(static_cast<uint32_t>(FXMATH_DECIMAL_RSHIFT32BIT(val))),
+      m_uLo(static_cast<uint32_t>(val)) {}
+
+CFGAS_Decimal::CFGAS_Decimal(uint32_t val)
+    : m_uLo(static_cast<uint32_t>(val)) {}
+
+CFGAS_Decimal::CFGAS_Decimal(uint32_t lo,
+                             uint32_t mid,
+                             uint32_t hi,
+                             bool neg,
+                             uint8_t scale)
+    : m_uHi(hi),
+      m_uMid(mid),
+      m_uLo(lo),
+      m_bNeg(neg && IsNotZero()),
+      m_uScale(scale > FXMATH_DECIMAL_SCALELIMIT ? 0 : scale) {}
+
+CFGAS_Decimal::CFGAS_Decimal(int32_t val) {
+  if (val >= 0) {
+    *this = CFGAS_Decimal(static_cast<uint32_t>(val));
+  } else if (val == std::numeric_limits<int32_t>::min()) {
+    *this = CFGAS_Decimal(static_cast<uint32_t>(val));
+    SetNegate();
+  } else {
+    *this = CFGAS_Decimal(static_cast<uint32_t>(-val));
+    SetNegate();
+  }
+}
+
+CFGAS_Decimal::CFGAS_Decimal(float val, uint8_t scale) {
+  float newval = fabs(val);
+  float divisor = powf(2.0, 64.0f);
+  uint64_t bottom64 = static_cast<uint64_t>(fmodf(newval, divisor));
+  uint64_t top64 = static_cast<uint64_t>(newval / divisor);
+  uint64_t plo = bottom64 & 0xFFFFFFFF;
+  uint64_t pmid = bottom64 >> 32;
+  uint64_t phi = top64 & 0xFFFFFFFF;
+
+  newval = fmodf(newval, 1.0f);
+  for (uint8_t iter = 0; iter < scale; iter++) {
+    decimal_helper_mul10(phi, pmid, plo);
+    newval *= 10;
+    plo += static_cast<uint64_t>(newval);
+    newval = fmodf(newval, 1.0f);
+  }
+
+  plo += FXSYS_roundf(newval);
+  decimal_helper_normalize(phi, pmid, plo);
+  m_uHi = static_cast<uint32_t>(phi);
+  m_uMid = static_cast<uint32_t>(pmid);
+  m_uLo = static_cast<uint32_t>(plo);
+  m_bNeg = val < 0 && IsNotZero();
+  m_uScale = scale;
+}
+
+CFGAS_Decimal::CFGAS_Decimal(WideStringView strObj) {
+  const wchar_t* str = strObj.unterminated_c_str();
+  const wchar_t* strBound = str + strObj.GetLength();
+  bool pointmet = false;
+  bool negmet = false;
+  uint8_t scale = 0;
+  m_uHi = 0;
+  m_uMid = 0;
+  m_uLo = 0;
+  while (str != strBound && *str == ' ')
+    str++;
+  if (str != strBound && *str == '-') {
+    negmet = 1;
+    str++;
+  } else if (str != strBound && *str == '+') {
+    str++;
+  }
+
+  while (str != strBound && (FXSYS_IsDecimalDigit(*str) || *str == '.') &&
+         scale < FXMATH_DECIMAL_SCALELIMIT) {
+    if (*str == '.') {
+      if (!pointmet)
+        pointmet = 1;
+    } else {
+      m_uHi = m_uHi * 0xA + FXMATH_DECIMAL_RSHIFT32BIT((uint64_t)m_uMid * 0xA);
+      m_uMid = m_uMid * 0xA + FXMATH_DECIMAL_RSHIFT32BIT((uint64_t)m_uLo * 0xA);
+      m_uLo = m_uLo * 0xA + (*str - '0');
+      if (pointmet)
+        scale++;
+    }
+    str++;
+  }
+  m_bNeg = negmet && IsNotZero();
+  m_uScale = scale;
+}
+
+WideString CFGAS_Decimal::ToWideString() const {
+  WideString retString;
+  WideString tmpbuf;
+  uint64_t phi = m_uHi;
+  uint64_t pmid = m_uMid;
+  uint64_t plo = m_uLo;
+  while (phi || pmid || plo)
+    tmpbuf += decimal_helper_div10(phi, pmid, plo) + '0';
+
+  uint8_t outputlen = (uint8_t)tmpbuf.GetLength();
+  uint8_t scale = m_uScale;
+  while (scale >= outputlen) {
+    tmpbuf += '0';
+    outputlen++;
+  }
+  if (m_bNeg && IsNotZero())
+    retString += '-';
+
+  for (uint8_t idx = 0; idx < outputlen; idx++) {
+    if (idx == (outputlen - scale) && scale != 0)
+      retString += '.';
+    retString += tmpbuf[outputlen - 1 - idx];
+  }
+  return retString;
+}
+
+float CFGAS_Decimal::ToFloat() const {
+  return static_cast<float>(ToDouble());
+}
+
+double CFGAS_Decimal::ToDouble() const {
+  double pow = (double)(1 << 16) * (1 << 16);
+  double base = static_cast<double>(m_uHi) * pow * pow +
+                static_cast<double>(m_uMid) * pow + static_cast<double>(m_uLo);
+  return (m_bNeg ? -1 : 1) * base * powf(10.0f, -m_uScale);
+}
+
+void CFGAS_Decimal::SetScale(uint8_t newscale) {
+  uint8_t oldscale = m_uScale;
+  if (oldscale == newscale)
+    return;
+
+  uint64_t phi = m_uHi;
+  uint64_t pmid = m_uMid;
+  uint64_t plo = m_uLo;
+  if (newscale > oldscale) {
+    for (uint8_t iter = 0; iter < newscale - oldscale; iter++)
+      decimal_helper_mul10(phi, pmid, plo);
+
+    m_uHi = static_cast<uint32_t>(phi);
+    m_uMid = static_cast<uint32_t>(pmid);
+    m_uLo = static_cast<uint32_t>(plo);
+    m_bNeg = m_bNeg && IsNotZero();
+    m_uScale = newscale;
+  } else {
+    uint64_t point5_hi = 0;
+    uint64_t point5_mid = 0;
+    uint64_t point5_lo = 5;
+    for (uint8_t iter = 0; iter < oldscale - newscale - 1; iter++)
+      decimal_helper_mul10(point5_hi, point5_mid, point5_lo);
+
+    phi += point5_hi;
+    pmid += point5_mid;
+    plo += point5_lo;
+    decimal_helper_normalize(phi, pmid, plo);
+    for (uint8_t iter = 0; iter < oldscale - newscale; iter++)
+      decimal_helper_div10(phi, pmid, plo);
+  }
+  m_uHi = static_cast<uint32_t>(phi);
+  m_uMid = static_cast<uint32_t>(pmid);
+  m_uLo = static_cast<uint32_t>(plo);
+  m_bNeg = m_bNeg && IsNotZero();
+  m_uScale = newscale;
+}
+
+void CFGAS_Decimal::SetNegate() {
+  if (IsNotZero())
+    m_bNeg = !m_bNeg;
+}
+
+CFGAS_Decimal CFGAS_Decimal::operator*(const CFGAS_Decimal& val) const {
+  uint64_t a[3] = {m_uLo, m_uMid, m_uHi},
+           b[3] = {val.m_uLo, val.m_uMid, val.m_uHi};
+  uint64_t c[6];
+  decimal_helper_raw_mul(a, 3, b, 3, c, 6);
+  bool neg = m_bNeg ^ val.m_bNeg;
+  uint8_t scale = m_uScale + val.m_uScale;
+  decimal_helper_shrinkintorange(c, 6, 3, scale);
+  return CFGAS_Decimal(static_cast<uint32_t>(c[0]), static_cast<uint32_t>(c[1]),
+                       static_cast<uint32_t>(c[2]), neg, scale);
+}
+
+CFGAS_Decimal CFGAS_Decimal::operator/(const CFGAS_Decimal& val) const {
+  if (!val.IsNotZero())
+    return CFGAS_Decimal();
+
+  bool neg = m_bNeg ^ val.m_bNeg;
+  uint64_t a[7] = {m_uLo, m_uMid, m_uHi},
+           b[3] = {val.m_uLo, val.m_uMid, val.m_uHi}, c[7] = {0};
+  uint8_t scale = 0;
+  if (m_uScale < val.m_uScale) {
+    for (int i = val.m_uScale - m_uScale; i > 0; i--)
+      decimal_helper_mul10_any(a, 7);
+  } else {
+    scale = m_uScale - val.m_uScale;
+  }
+
+  uint8_t minscale = scale;
+  if (!IsNotZero())
+    return CFGAS_Decimal(0, 0, 0, 0, minscale);
+
+  while (!a[6]) {
+    decimal_helper_mul10_any(a, 7);
+    scale++;
+  }
+
+  decimal_helper_div10_any(a, 7);
+  scale--;
+  decimal_helper_raw_div(a, 6, b, 3, c, 7);
+  decimal_helper_shrinkintorange(c, 6, 3, scale);
+  decimal_helper_truncate(c[2], c[1], c[0], scale, minscale);
+  return CFGAS_Decimal(static_cast<uint32_t>(c[0]), static_cast<uint32_t>(c[1]),
+                       static_cast<uint32_t>(c[2]), neg, scale);
+}
diff --git a/xfa/fgas/crt/cfgas_decimal.h b/xfa/fgas/crt/cfgas_decimal.h
new file mode 100644
index 0000000..4751c5b
--- /dev/null
+++ b/xfa/fgas/crt/cfgas_decimal.h
@@ -0,0 +1,47 @@
+// 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_FGAS_CRT_CFGAS_DECIMAL_H_
+#define XFA_FGAS_CRT_CFGAS_DECIMAL_H_
+
+#include "core/fxcrt/fx_string.h"
+
+class CFGAS_Decimal {
+ public:
+  CFGAS_Decimal();
+  explicit CFGAS_Decimal(uint32_t val);
+  explicit CFGAS_Decimal(uint64_t val);
+  explicit CFGAS_Decimal(int32_t val);
+  CFGAS_Decimal(float val, uint8_t scale);
+  explicit CFGAS_Decimal(WideStringView str);
+
+  WideString ToWideString() const;
+  float ToFloat() const;
+  double ToDouble() const;
+
+  CFGAS_Decimal operator*(const CFGAS_Decimal& val) const;
+  CFGAS_Decimal operator/(const CFGAS_Decimal& val) const;
+
+  bool IsNotZero() const { return m_uHi || m_uMid || m_uLo; }
+  uint8_t GetScale() const { return m_uScale; }
+  void SetScale(uint8_t newScale);
+  void SetNegate();
+
+ private:
+  CFGAS_Decimal(uint32_t hi,
+                uint32_t mid,
+                uint32_t lo,
+                bool neg,
+                uint8_t scale);
+
+  uint32_t m_uHi = 0;
+  uint32_t m_uMid = 0;
+  uint32_t m_uLo = 0;
+  bool m_bNeg = false;
+  uint8_t m_uScale = 0;
+};
+
+#endif  // XFA_FGAS_CRT_CFGAS_DECIMAL_H_
diff --git a/xfa/fgas/crt/cfgas_decimal_unittest.cpp b/xfa/fgas/crt/cfgas_decimal_unittest.cpp
new file mode 100644
index 0000000..816045e
--- /dev/null
+++ b/xfa/fgas/crt/cfgas_decimal_unittest.cpp
@@ -0,0 +1,77 @@
+// Copyright 2019 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/fgas/crt/cfgas_decimal.h"
+
+#include <limits>
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+TEST(CFGAS_Decimal, Empty) {
+  CFGAS_Decimal empty;
+  EXPECT_EQ(L"0", empty.ToWideString());
+  EXPECT_EQ(0.0f, empty.ToFloat());
+  EXPECT_EQ(0.0, empty.ToDouble());
+}
+
+TEST(CFGAS_Decimal, FromInt32) {
+  CFGAS_Decimal big(std::numeric_limits<int32_t>::max());
+  CFGAS_Decimal small(std::numeric_limits<int32_t>::min());
+  EXPECT_STREQ(L"2147483647", big.ToWideString().c_str());
+  EXPECT_STREQ(L"-2147483648", small.ToWideString().c_str());
+}
+
+TEST(CFGAS_Decimal, FromUint32) {
+  CFGAS_Decimal big(std::numeric_limits<uint32_t>::max());
+  CFGAS_Decimal small(std::numeric_limits<uint32_t>::min());
+  EXPECT_STREQ(L"4294967295", big.ToWideString().c_str());
+  EXPECT_STREQ(L"0", small.ToWideString().c_str());
+}
+
+TEST(CFGAS_Decimal, FromUint64) {
+  CFGAS_Decimal big(std::numeric_limits<uint64_t>::max());
+  CFGAS_Decimal small(std::numeric_limits<uint64_t>::min());
+  EXPECT_STREQ(L"18446744073709551615", big.ToWideString().c_str());
+  EXPECT_STREQ(L"0", small.ToWideString().c_str());
+}
+
+TEST(CFGAS_Decimal, FromFloat) {
+  WideString big = CFGAS_Decimal(powf(2.0f, 95.0f), 0).ToWideString();
+  WideString big_expected = L"39614081257132168796771975168";
+
+  // Precision may not be the same on all platforms.
+  EXPECT_EQ(big_expected.GetLength(), big.GetLength());
+  EXPECT_STREQ(big_expected.First(8).c_str(), big.First(8).c_str());
+
+  WideString tiny = CFGAS_Decimal(1e20f, 0).ToWideString();
+  WideString tiny_expected = L"100000000000000000000";
+  EXPECT_EQ(tiny_expected.GetLength(), tiny.GetLength());
+  EXPECT_STREQ(tiny_expected.First(8).c_str(), tiny.First(8).c_str());
+
+  WideString teeny = CFGAS_Decimal(1e14f, 4).ToWideString();
+  WideString teeny_expected = L"100000000000000.0000";
+  EXPECT_EQ(teeny_expected.GetLength(), teeny.GetLength());
+  EXPECT_STREQ(teeny_expected.First(8).c_str(), teeny.First(8).c_str());
+}
+
+TEST(CFGAS_Decimal, FromFloatFractional) {
+  WideString case1 = CFGAS_Decimal(123.456f, 10).ToWideString();
+  WideString case1_expected = L"123.4560000000";
+
+  // Precision may not be the same on all platforms.
+  EXPECT_EQ(case1_expected.GetLength(), case1.GetLength());
+  EXPECT_STREQ(case1_expected.First(8).c_str(), case1.First(8).c_str());
+}
+
+TEST(CFGAS_Decimal, FromString) {
+  CFGAS_Decimal big(L"100000000000000000000000000");
+  CFGAS_Decimal small(L"-1000000000000000000000000");
+  EXPECT_STREQ(L"100000000000000000000000000", big.ToWideString().c_str());
+  EXPECT_STREQ(L"-1000000000000000000000000", small.ToWideString().c_str());
+}
+
+TEST(CFGAS_Decimal, FromString28Digits) {
+  CFGAS_Decimal frac(L"32109876543210.0123456890123");
+  EXPECT_STREQ(L"32109876543210.0123456890123", frac.ToWideString().c_str());
+}
diff --git a/xfa/fgas/crt/cfgas_formatstring.cpp b/xfa/fgas/crt/cfgas_formatstring.cpp
deleted file mode 100644
index b8f6eee..0000000
--- a/xfa/fgas/crt/cfgas_formatstring.cpp
+++ /dev/null
@@ -1,2345 +0,0 @@
-// Copyright 2014 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
-
-#include "xfa/fgas/crt/cfgas_formatstring.h"
-
-#include <algorithm>
-#include <vector>
-
-#include "core/fxcrt/cfx_decimal.h"
-#include "core/fxcrt/fx_extension.h"
-#include "core/fxcrt/xml/cxml_element.h"
-
-#define FX_LOCALECATEGORY_DateHash 0xbde9abde
-#define FX_LOCALECATEGORY_TimeHash 0x2d71b00f
-#define FX_LOCALECATEGORY_DateTimeHash 0x158c72ed
-#define FX_LOCALECATEGORY_NumHash 0x0b4ff870
-#define FX_LOCALECATEGORY_TextHash 0x2d08af85
-#define FX_LOCALECATEGORY_ZeroHash 0x568cb500
-#define FX_LOCALECATEGORY_NullHash 0x052931bb
-
-#define FX_NUMSTYLE_Percent 0x01
-#define FX_NUMSTYLE_Exponent 0x02
-#define FX_NUMSTYLE_DotVorv 0x04
-
-namespace {
-
-struct FX_LOCALESUBCATEGORYINFO {
-  uint32_t uHash;
-  const wchar_t* pName;
-  int32_t eSubCategory;
-};
-
-const FX_LOCALESUBCATEGORYINFO g_FXLocaleDateTimeSubCatData[] = {
-    {0x14da2125, L"default", FX_LOCALEDATETIMESUBCATEGORY_Default},
-    {0x9041d4b0, L"short", FX_LOCALEDATETIMESUBCATEGORY_Short},
-    {0xa084a381, L"medium", FX_LOCALEDATETIMESUBCATEGORY_Medium},
-    {0xcdce56b3, L"full", FX_LOCALEDATETIMESUBCATEGORY_Full},
-    {0xf6b4afb0, L"long", FX_LOCALEDATETIMESUBCATEGORY_Long},
-};
-const int32_t g_iFXLocaleDateTimeSubCatCount =
-    sizeof(g_FXLocaleDateTimeSubCatData) / sizeof(FX_LOCALESUBCATEGORYINFO);
-
-const FX_LOCALESUBCATEGORYINFO g_FXLocaleNumSubCatData[] = {
-    {0x46f95531, L"percent", FX_LOCALENUMPATTERN_Percent},
-    {0x4c4e8acb, L"currency", FX_LOCALENUMPATTERN_Currency},
-    {0x54034c2f, L"decimal", FX_LOCALENUMPATTERN_Decimal},
-    {0x7568e6ae, L"integer", FX_LOCALENUMPATTERN_Integer},
-};
-const int32_t g_iFXLocaleNumSubCatCount =
-    sizeof(g_FXLocaleNumSubCatData) / sizeof(FX_LOCALESUBCATEGORYINFO);
-
-struct FX_LOCALETIMEZONEINFO {
-  const wchar_t* name;
-  int16_t iHour;
-  int16_t iMinute;
-};
-
-const FX_LOCALETIMEZONEINFO g_FXLocaleTimeZoneData[] = {
-    {L"CDT", -5, 0}, {L"CST", -6, 0}, {L"EDT", -4, 0}, {L"EST", -5, 0},
-    {L"MDT", -6, 0}, {L"MST", -7, 0}, {L"PDT", -7, 0}, {L"PST", -8, 0},
-};
-
-const wchar_t gs_wsTimeSymbols[] = L"hHkKMSFAzZ";
-const wchar_t gs_wsDateSymbols[] = L"DJMEeGgYwW";
-const wchar_t gs_wsConstChars[] = L",-:/. ";
-
-int32_t ParseTimeZone(const wchar_t* pStr, int32_t iLen, FX_TIMEZONE* tz) {
-  tz->tzHour = 0;
-  tz->tzMinute = 0;
-  if (iLen < 0)
-    return 0;
-
-  int32_t iStart = 1;
-  int32_t iEnd = iStart + 2;
-  while (iStart < iLen && iStart < iEnd)
-    tz->tzHour = tz->tzHour * 10 + FXSYS_DecimalCharToInt(pStr[iStart++]);
-
-  if (iStart < iLen && pStr[iStart] == ':')
-    iStart++;
-
-  iEnd = iStart + 2;
-  while (iStart < iLen && iStart < iEnd)
-    tz->tzMinute = tz->tzMinute * 10 + FXSYS_DecimalCharToInt(pStr[iStart++]);
-
-  if (pStr[0] == '-')
-    tz->tzHour = -tz->tzHour;
-
-  return iStart;
-}
-
-int32_t ConvertHex(int32_t iKeyValue, wchar_t ch) {
-  if (FXSYS_isHexDigit(ch))
-    return iKeyValue * 16 + FXSYS_HexCharToInt(ch);
-  return iKeyValue;
-}
-
-WideString GetLiteralText(const wchar_t* pStrPattern,
-                          int32_t* iPattern,
-                          int32_t iLenPattern) {
-  WideString wsOutput;
-  if (pStrPattern[*iPattern] != '\'')
-    return wsOutput;
-
-  (*iPattern)++;
-  int32_t iQuote = 1;
-  while (*iPattern < iLenPattern) {
-    if (pStrPattern[*iPattern] == '\'') {
-      iQuote++;
-      if ((*iPattern + 1 >= iLenPattern) ||
-          ((pStrPattern[*iPattern + 1] != '\'') && (iQuote % 2 == 0))) {
-        break;
-      }
-      iQuote++;
-      (*iPattern)++;
-    } else if (pStrPattern[*iPattern] == '\\' &&
-               (*iPattern + 1 < iLenPattern) &&
-               pStrPattern[*iPattern + 1] == 'u') {
-      int32_t iKeyValue = 0;
-      *iPattern += 2;
-      int32_t i = 0;
-      while (*iPattern < iLenPattern && i++ < 4) {
-        wchar_t ch = pStrPattern[(*iPattern)++];
-        iKeyValue = ConvertHex(iKeyValue, ch);
-      }
-      if (iKeyValue != 0)
-        wsOutput += static_cast<wchar_t>(iKeyValue & 0x0000FFFF);
-
-      continue;
-    }
-    wsOutput += pStrPattern[(*iPattern)++];
-  }
-  return wsOutput;
-}
-
-WideString GetLiteralTextReverse(const wchar_t* pStrPattern,
-                                 int32_t* iPattern) {
-  WideString wsOutput;
-  if (pStrPattern[*iPattern] != '\'')
-    return wsOutput;
-
-  (*iPattern)--;
-  int32_t iQuote = 1;
-  while (*iPattern >= 0) {
-    if (pStrPattern[*iPattern] == '\'') {
-      iQuote++;
-      if (*iPattern - 1 >= 0 ||
-          ((pStrPattern[*iPattern - 1] != '\'') && (iQuote % 2 == 0))) {
-        break;
-      }
-      iQuote++;
-      (*iPattern)--;
-    } else if (pStrPattern[*iPattern] == '\\' &&
-               pStrPattern[*iPattern + 1] == 'u') {
-      (*iPattern)--;
-      int32_t iKeyValue = 0;
-      int32_t iLen = wsOutput.GetLength();
-      int32_t i = 1;
-      for (; i < iLen && i < 5; i++) {
-        wchar_t ch = wsOutput[i];
-        iKeyValue = ConvertHex(iKeyValue, ch);
-      }
-      if (iKeyValue != 0) {
-        wsOutput.Delete(0, i);
-        wsOutput = (wchar_t)(iKeyValue & 0x0000FFFF) + wsOutput;
-      }
-      continue;
-    }
-    wsOutput = pStrPattern[(*iPattern)--] + wsOutput;
-  }
-  return wsOutput;
-}
-
-bool GetNumericDotIndex(const WideString& wsNum,
-                        const WideString& wsDotSymbol,
-                        int32_t* iDotIndex) {
-  int32_t ccf = 0;
-  int32_t iLenf = wsNum.GetLength();
-  const wchar_t* pStr = wsNum.c_str();
-  int32_t iLenDot = wsDotSymbol.GetLength();
-  while (ccf < iLenf) {
-    if (pStr[ccf] == '\'') {
-      GetLiteralText(pStr, &ccf, iLenf);
-    } else if (ccf + iLenDot <= iLenf &&
-               !wcsncmp(pStr + ccf, wsDotSymbol.c_str(), iLenDot)) {
-      *iDotIndex = ccf;
-      return true;
-    }
-    ccf++;
-  }
-  auto result = wsNum.Find('.');
-  *iDotIndex = result.value_or(iLenf);
-  return result.has_value();
-}
-
-bool ExtractCountDigits(const wchar_t* str,
-                        int len,
-                        int count,
-                        int* cc,
-                        uint32_t* value) {
-  for (int i = count; i > 0; --i) {
-    if (*cc >= len)
-      return false;
-    if (!FXSYS_isDecimalDigit(str[*cc]))
-      return false;
-    *value = *value * 10 + FXSYS_DecimalCharToInt(str[(*cc)++]);
-  }
-  return true;
-}
-
-bool ExtractCountDigitsWithOptional(const wchar_t* str,
-                                    int len,
-                                    int count,
-                                    int* cc,
-                                    uint32_t* value) {
-  if (!ExtractCountDigits(str, len, count, cc, value))
-    return false;
-  ExtractCountDigits(str, len, 1, cc, value);
-  return true;
-}
-
-bool ParseLocaleDate(const WideString& wsDate,
-                     const WideString& wsDatePattern,
-                     IFX_Locale* pLocale,
-                     CFX_DateTime* datetime,
-                     int32_t* cc) {
-  uint32_t year = 1900;
-  uint32_t month = 1;
-  uint32_t day = 1;
-  int32_t ccf = 0;
-  const wchar_t* str = wsDate.c_str();
-  int32_t len = wsDate.GetLength();
-  const wchar_t* strf = wsDatePattern.c_str();
-  int32_t lenf = wsDatePattern.GetLength();
-  WideStringView wsDateSymbols(gs_wsDateSymbols);
-  while (*cc < len && ccf < lenf) {
-    if (strf[ccf] == '\'') {
-      WideString wsLiteral = GetLiteralText(strf, &ccf, lenf);
-      int32_t iLiteralLen = wsLiteral.GetLength();
-      if (*cc + iLiteralLen > len ||
-          wcsncmp(str + *cc, wsLiteral.c_str(), iLiteralLen)) {
-        return false;
-      }
-      *cc += iLiteralLen;
-      ccf++;
-      continue;
-    }
-    if (!wsDateSymbols.Contains(strf[ccf])) {
-      if (strf[ccf] != str[*cc])
-        return false;
-      (*cc)++;
-      ccf++;
-      continue;
-    }
-
-    WideString symbol;
-    symbol.Reserve(4);
-    symbol += strf[ccf++];
-    while (ccf < lenf && strf[ccf] == symbol[0])
-      symbol += strf[ccf++];
-
-    if (symbol == L"D" || symbol == L"DD") {
-      day = 0;
-      if (!ExtractCountDigitsWithOptional(str, len, 1, cc, &day))
-        return false;
-    } else if (symbol == L"J") {
-      uint32_t val = 0;
-      ExtractCountDigits(str, len, 3, cc, &val);
-    } else if (symbol == L"M" || symbol == L"MM") {
-      month = 0;
-      if (!ExtractCountDigitsWithOptional(str, len, 1, cc, &month))
-        return false;
-    } else if (symbol == L"MMM" || symbol == L"MMMM") {
-      for (uint16_t i = 0; i < 12; i++) {
-        WideString wsMonthName = pLocale->GetMonthName(i, symbol == L"MMM");
-        if (wsMonthName.IsEmpty())
-          continue;
-        if (!wcsncmp(wsMonthName.c_str(), str + *cc, wsMonthName.GetLength())) {
-          *cc += wsMonthName.GetLength();
-          month = i + 1;
-          break;
-        }
-      }
-    } else if (symbol == L"EEE" || symbol == L"EEEE") {
-      for (uint16_t i = 0; i < 7; i++) {
-        WideString wsDayName = pLocale->GetDayName(i, symbol == L"EEE");
-        if (wsDayName.IsEmpty())
-          continue;
-        if (!wcsncmp(wsDayName.c_str(), str + *cc, wsDayName.GetLength())) {
-          *cc += wsDayName.GetLength();
-          break;
-        }
-      }
-    } else if (symbol == L"YY" || symbol == L"YYYY") {
-      if (*cc + pdfium::base::checked_cast<int32_t>(symbol.GetLength()) > len)
-        return false;
-
-      year = 0;
-      if (!ExtractCountDigits(str, len, symbol.GetLength(), cc, &year))
-        return false;
-      if (symbol == L"YY") {
-        if (year <= 29)
-          year += 2000;
-        else
-          year += 1900;
-      }
-    } else if (symbol == L"G") {
-      *cc += 2;
-    } else if (symbol == L"JJJ" || symbol == L"E" || symbol == L"e" ||
-               symbol == L"w" || symbol == L"WW") {
-      *cc += symbol.GetLength();
-    }
-  }
-  if (*cc < len)
-    return false;
-
-  datetime->SetDate(year, month, day);
-  return !!(*cc);
-}
-
-void ResolveZone(FX_TIMEZONE tzDiff,
-                 IFX_Locale* pLocale,
-                 uint32_t* wHour,
-                 uint32_t* wMinute) {
-  int32_t iMinuteDiff = *wHour * 60 + *wMinute;
-  FX_TIMEZONE tzLocale = pLocale->GetTimeZone();
-  iMinuteDiff += tzLocale.tzHour * 60 +
-                 (tzLocale.tzHour < 0 ? -tzLocale.tzMinute : tzLocale.tzMinute);
-  iMinuteDiff -= tzDiff.tzHour * 60 +
-                 (tzDiff.tzHour < 0 ? -tzDiff.tzMinute : tzDiff.tzMinute);
-
-  iMinuteDiff %= 1440;
-  if (iMinuteDiff < 0)
-    iMinuteDiff += 1440;
-
-  *wHour = iMinuteDiff / 60;
-  *wMinute = iMinuteDiff % 60;
-}
-
-bool ParseLocaleTime(const WideString& wsTime,
-                     const WideString& wsTimePattern,
-                     IFX_Locale* pLocale,
-                     CFX_DateTime* datetime,
-                     int32_t* cc) {
-  uint32_t hour = 0;
-  uint32_t minute = 0;
-  uint32_t second = 0;
-  uint32_t millisecond = 0;
-  int32_t ccf = 0;
-  const wchar_t* str = wsTime.c_str();
-  int len = wsTime.GetLength();
-  const wchar_t* strf = wsTimePattern.c_str();
-  int lenf = wsTimePattern.GetLength();
-  bool bHasA = false;
-  bool bPM = false;
-  WideStringView wsTimeSymbols(gs_wsTimeSymbols);
-  while (*cc < len && ccf < lenf) {
-    if (strf[ccf] == '\'') {
-      WideString wsLiteral = GetLiteralText(strf, &ccf, lenf);
-      int32_t iLiteralLen = wsLiteral.GetLength();
-      if (*cc + iLiteralLen > len ||
-          wcsncmp(str + *cc, wsLiteral.c_str(), iLiteralLen)) {
-        return false;
-      }
-      *cc += iLiteralLen;
-      ccf++;
-      continue;
-    }
-    if (!wsTimeSymbols.Contains(strf[ccf])) {
-      if (strf[ccf] != str[*cc])
-        return false;
-      (*cc)++;
-      ccf++;
-      continue;
-    }
-
-    WideString symbol;
-    symbol.Reserve(4);
-    symbol += strf[ccf++];
-    while (ccf < lenf && strf[ccf] == symbol[0])
-      symbol += strf[ccf++];
-
-    if (symbol == L"k" || symbol == L"K" || symbol == L"h" || symbol == L"H") {
-      hour = 0;
-      if (!ExtractCountDigitsWithOptional(str, len, 1, cc, &hour))
-        return false;
-      if (symbol == L"K" && hour == 24)
-        hour = 0;
-    } else if (symbol == L"kk" || symbol == L"KK" || symbol == L"hh" ||
-               symbol == L"HH") {
-      hour = 0;
-      if (!ExtractCountDigits(str, len, 2, cc, &hour))
-        return false;
-      if (symbol == L"KK" && hour == 24)
-        hour = 0;
-    } else if (symbol == L"M") {
-      minute = 0;
-      if (!ExtractCountDigitsWithOptional(str, len, 1, cc, &minute))
-        return false;
-    } else if (symbol == L"MM") {
-      minute = 0;
-      if (!ExtractCountDigits(str, len, 2, cc, &minute))
-        return false;
-    } else if (symbol == L"S") {
-      second = 0;
-      if (!ExtractCountDigitsWithOptional(str, len, 1, cc, &second))
-        return false;
-    } else if (symbol == L"SS") {
-      second = 0;
-      if (!ExtractCountDigits(str, len, 2, cc, &second))
-        return false;
-    } else if (symbol == L"FFF") {
-      millisecond = 0;
-      if (!ExtractCountDigits(str, len, 3, cc, &millisecond))
-        return false;
-    } else if (symbol == L"A") {
-      WideString wsAM = pLocale->GetMeridiemName(true);
-      WideString wsPM = pLocale->GetMeridiemName(false);
-      if ((*cc + pdfium::base::checked_cast<int32_t>(wsAM.GetLength()) <=
-           len) &&
-          (WideStringView(str + *cc, wsAM.GetLength()) == wsAM)) {
-        *cc += wsAM.GetLength();
-        bHasA = true;
-      } else if ((*cc + pdfium::base::checked_cast<int32_t>(wsPM.GetLength()) <=
-                  len) &&
-                 (WideStringView(str + *cc, wsPM.GetLength()) == wsPM)) {
-        *cc += wsPM.GetLength();
-        bHasA = true;
-        bPM = true;
-      }
-    } else if (symbol == L"Z") {
-      if (*cc + 3 > len)
-        continue;
-
-      WideString tz(str[(*cc)++]);
-      tz += str[(*cc)++];
-      tz += str[(*cc)++];
-      if (tz == L"GMT") {
-        FX_TIMEZONE tzDiff;
-        tzDiff.tzHour = 0;
-        tzDiff.tzMinute = 0;
-        if (*cc < len && (str[*cc] == '-' || str[*cc] == '+'))
-          *cc += ParseTimeZone(str + *cc, len - *cc, &tzDiff);
-
-        ResolveZone(tzDiff, pLocale, &hour, &minute);
-      } else {
-        // Search the timezone list. There are only 8 of them, so linear scan.
-        for (size_t i = 0; i < FX_ArraySize(g_FXLocaleTimeZoneData); ++i) {
-          const FX_LOCALETIMEZONEINFO& info = g_FXLocaleTimeZoneData[i];
-          if (tz != info.name)
-            continue;
-
-          hour += info.iHour;
-          minute += info.iHour > 0 ? info.iMinute : -info.iMinute;
-          break;
-        }
-      }
-    } else if (symbol == L"z") {
-      if (str[*cc] != 'Z') {
-        FX_TIMEZONE tzDiff;
-        *cc += ParseTimeZone(str + *cc, len - *cc, &tzDiff);
-        ResolveZone(tzDiff, pLocale, &hour, &minute);
-      } else {
-        (*cc)++;
-      }
-    }
-  }
-  if (bHasA) {
-    if (bPM) {
-      hour += 12;
-      if (hour == 24)
-        hour = 12;
-    } else {
-      if (hour == 12)
-        hour = 0;
-    }
-  }
-  datetime->SetTime(hour, minute, second, millisecond);
-  return !!(*cc);
-}
-
-int32_t GetNumTrailingLimit(const WideString& wsFormat,
-                            int iDotPos,
-                            bool* bTrimTailZeros) {
-  if (iDotPos < 0)
-    return 0;
-
-  int32_t iCount = wsFormat.GetLength();
-  int32_t iTreading = 0;
-  for (iDotPos++; iDotPos < iCount; iDotPos++) {
-    wchar_t wc = wsFormat[iDotPos];
-    if (wc == L'z' || wc == L'9' || wc == 'Z') {
-      iTreading++;
-      *bTrimTailZeros = wc != L'9';
-    }
-  }
-  return iTreading;
-}
-
-bool IsLeapYear(uint32_t year) {
-  return (year % 4 == 0 && year % 100 != 0) || year % 400 == 0;
-}
-
-bool MonthHas30Days(uint32_t month) {
-  return month == 4 || month == 6 || month == 9 || month == 11;
-}
-
-bool MonthHas31Days(uint32_t month) {
-  return month != 2 && !MonthHas30Days(month);
-}
-
-// |month| is 1-based. e.g. 1 means January.
-uint16_t GetSolarMonthDays(uint16_t year, uint16_t month) {
-  if (month == 2)
-    return FX_IsLeapYear(year) ? 29 : 28;
-
-  return MonthHas30Days(month) ? 30 : 31;
-}
-
-uint16_t GetWeekDay(uint16_t year, uint16_t month, uint16_t day) {
-  static const uint16_t month_day[] = {0, 3, 3, 6, 1, 4, 6, 2, 5, 0, 3, 5};
-  uint16_t nDays =
-      (year - 1) % 7 + (year - 1) / 4 - (year - 1) / 100 + (year - 1) / 400;
-  nDays += month_day[month - 1] + day;
-  if (FX_IsLeapYear(year) && month > 2)
-    nDays++;
-  return nDays % 7;
-}
-
-uint16_t GetWeekOfMonth(uint16_t year, uint16_t month, uint16_t day) {
-  uint16_t week_day = GetWeekDay(year, month, 1);
-  uint16_t week_index = 0;
-  week_index += day / 7;
-  day = day % 7;
-  if (week_day + day > 7)
-    week_index++;
-  return week_index;
-}
-
-uint16_t GetWeekOfYear(uint16_t year, uint16_t month, uint16_t day) {
-  uint16_t nDays = 0;
-  for (uint16_t i = 1; i < month; i++)
-    nDays += GetSolarMonthDays(year, i);
-
-  nDays += day;
-  uint16_t week_day = GetWeekDay(year, 1, 1);
-  uint16_t week_index = 1;
-  week_index += nDays / 7;
-  nDays = nDays % 7;
-  if (week_day + nDays > 7)
-    week_index++;
-  return week_index;
-}
-
-WideString NumToString(size_t fmt_size, int32_t value) {
-  return WideString::Format(
-      fmt_size == 1 ? L"%d" : fmt_size == 2 ? L"%02d" : L"%03d", value);
-}
-
-WideString DateFormat(const WideString& wsDatePattern,
-                      IFX_Locale* pLocale,
-                      const CFX_DateTime& datetime) {
-  WideString wsResult;
-  int32_t year = datetime.GetYear();
-  uint8_t month = datetime.GetMonth();
-  uint8_t day = datetime.GetDay();
-  int32_t ccf = 0;
-  const wchar_t* strf = wsDatePattern.c_str();
-  int32_t lenf = wsDatePattern.GetLength();
-  WideStringView wsDateSymbols(gs_wsDateSymbols);
-  while (ccf < lenf) {
-    if (strf[ccf] == '\'') {
-      wsResult += GetLiteralText(strf, &ccf, lenf);
-      ccf++;
-      continue;
-    }
-    if (!wsDateSymbols.Contains(strf[ccf])) {
-      wsResult += strf[ccf++];
-      continue;
-    }
-
-    WideString symbol;
-    symbol.Reserve(4);
-    symbol += strf[ccf++];
-    while (ccf < lenf && strf[ccf] == symbol[0])
-      symbol += strf[ccf++];
-
-    if (symbol == L"D" || symbol == L"DD") {
-      wsResult += NumToString(symbol.GetLength(), day);
-    } else if (symbol == L"J" || symbol == L"JJJ") {
-      uint16_t nDays = 0;
-      for (int i = 1; i < month; i++)
-        nDays += GetSolarMonthDays(year, i);
-      nDays += day;
-      wsResult += NumToString(symbol.GetLength(), nDays);
-    } else if (symbol == L"M" || symbol == L"MM") {
-      wsResult += NumToString(symbol.GetLength(), month);
-    } else if (symbol == L"MMM" || symbol == L"MMMM") {
-      wsResult += pLocale->GetMonthName(month - 1, symbol == L"MMM");
-    } else if (symbol == L"E" || symbol == L"e") {
-      uint16_t wWeekDay = GetWeekDay(year, month, day);
-      wsResult += NumToString(
-          1, symbol == L"E" ? wWeekDay + 1 : (wWeekDay ? wWeekDay : 7));
-    } else if (symbol == L"EEE" || symbol == L"EEEE") {
-      wsResult +=
-          pLocale->GetDayName(GetWeekDay(year, month, day), symbol == L"EEE");
-    } else if (symbol == L"G") {
-      wsResult += pLocale->GetEraName(year > 0);
-    } else if (symbol == L"YY") {
-      wsResult += NumToString(2, year % 100);
-    } else if (symbol == L"YYYY") {
-      wsResult += NumToString(1, year);
-    } else if (symbol == L"w") {
-      wsResult += NumToString(1, GetWeekOfMonth(year, month, day));
-    } else if (symbol == L"WW") {
-      wsResult += NumToString(2, GetWeekOfYear(year, month, day));
-    }
-  }
-  return wsResult;
-}
-
-WideString TimeFormat(const WideString& wsTimePattern,
-                      IFX_Locale* pLocale,
-                      const CFX_DateTime& datetime) {
-  WideString wsResult;
-  uint8_t hour = datetime.GetHour();
-  uint8_t minute = datetime.GetMinute();
-  uint8_t second = datetime.GetSecond();
-  uint16_t millisecond = datetime.GetMillisecond();
-  int32_t ccf = 0;
-  const wchar_t* strf = wsTimePattern.c_str();
-  int32_t lenf = wsTimePattern.GetLength();
-  uint16_t wHour = hour;
-  bool bPM = false;
-  if (wsTimePattern.Contains('A')) {
-    if (wHour >= 12)
-      bPM = true;
-  }
-
-  WideStringView wsTimeSymbols(gs_wsTimeSymbols);
-  while (ccf < lenf) {
-    if (strf[ccf] == '\'') {
-      wsResult += GetLiteralText(strf, &ccf, lenf);
-      ccf++;
-      continue;
-    }
-    if (!wsTimeSymbols.Contains(strf[ccf])) {
-      wsResult += strf[ccf++];
-      continue;
-    }
-
-    WideString symbol;
-    symbol.Reserve(4);
-    symbol += strf[ccf++];
-    while (ccf < lenf && strf[ccf] == symbol[0])
-      symbol += strf[ccf++];
-
-    if (symbol == L"h" || symbol == L"hh") {
-      if (wHour > 12)
-        wHour -= 12;
-      wsResult += NumToString(symbol.GetLength(), wHour == 0 ? 12 : wHour);
-    } else if (symbol == L"K" || symbol == L"KK") {
-      wsResult += NumToString(symbol.GetLength(), wHour == 0 ? 24 : wHour);
-    } else if (symbol == L"k" || symbol == L"kk") {
-      if (wHour > 12)
-        wHour -= 12;
-      wsResult += NumToString(symbol.GetLength(), wHour);
-    } else if (symbol == L"H" || symbol == L"HH") {
-      wsResult += NumToString(symbol.GetLength(), wHour);
-    } else if (symbol == L"M" || symbol == L"MM") {
-      wsResult += NumToString(symbol.GetLength(), minute);
-    } else if (symbol == L"S" || symbol == L"SS") {
-      wsResult += NumToString(symbol.GetLength(), second);
-    } else if (symbol == L"FFF") {
-      wsResult += NumToString(3, millisecond);
-    } else if (symbol == L"A") {
-      wsResult += pLocale->GetMeridiemName(!bPM);
-    } else if (symbol == L"Z" || symbol == L"z") {
-      if (symbol == L"Z")
-        wsResult += L"GMT";
-
-      FX_TIMEZONE tz = pLocale->GetTimeZone();
-      if (tz.tzHour != 0 || tz.tzMinute != 0) {
-        wsResult += tz.tzHour < 0 ? L"-" : L"+";
-        wsResult +=
-            WideString::Format(L"%02d:%02d", abs(tz.tzHour), tz.tzMinute);
-      }
-    }
-  }
-  return wsResult;
-}
-
-WideString FormatDateTimeInternal(const CFX_DateTime& dt,
-                                  const WideString& wsDatePattern,
-                                  const WideString& wsTimePattern,
-                                  bool bDateFirst,
-                                  IFX_Locale* pLocale) {
-  WideString wsDateOut;
-  if (!wsDatePattern.IsEmpty())
-    wsDateOut = DateFormat(wsDatePattern, pLocale, dt);
-
-  WideString wsTimeOut;
-  if (!wsTimePattern.IsEmpty())
-    wsTimeOut = TimeFormat(wsTimePattern, pLocale, dt);
-
-  return bDateFirst ? wsDateOut + wsTimeOut : wsTimeOut + wsDateOut;
-}
-
-}  // namespace
-
-bool FX_DateFromCanonical(const WideString& wsDate, CFX_DateTime* datetime) {
-  const wchar_t* str = wsDate.c_str();
-  int len = wsDate.GetLength();
-  if (len > 10)
-    return false;
-
-  int cc = 0;
-  uint32_t year = 0;
-  if (!ExtractCountDigits(str, len, 4, &cc, &year))
-    return false;
-  if (year < 1900)
-    return false;
-  if (cc >= len) {
-    datetime->SetDate(year, 1, 1);
-    return true;
-  }
-
-  if (str[cc] == '-')
-    cc++;
-
-  uint32_t month = 0;
-  if (!ExtractCountDigits(str, len, 2, &cc, &month))
-    return false;
-  if (month > 12 || month < 1)
-    return false;
-  if (cc >= len) {
-    datetime->SetDate(year, month, 1);
-    return true;
-  }
-
-  if (str[cc] == '-')
-    cc++;
-
-  uint32_t day = 0;
-  if (!ExtractCountDigits(str, len, 2, &cc, &day))
-    return false;
-  if (day < 1)
-    return false;
-  if ((MonthHas31Days(month) && day > 31) ||
-      (MonthHas30Days(month) && day > 30)) {
-    return false;
-  }
-  if (month == 2 && day > (IsLeapYear(year) ? 29U : 28U))
-    return false;
-
-  datetime->SetDate(year, month, day);
-  return true;
-}
-
-bool FX_TimeFromCanonical(const WideStringView& wsTime,
-                          CFX_DateTime* datetime,
-                          IFX_Locale* pLocale) {
-  if (wsTime.GetLength() == 0)
-    return false;
-
-  const wchar_t* str = wsTime.unterminated_c_str();
-  int len = wsTime.GetLength();
-
-  int cc = 0;
-  uint32_t hour = 0;
-  if (!ExtractCountDigits(str, len, 2, &cc, &hour))
-    return false;
-  if (hour >= 24)
-    return false;
-  if (cc >= len) {
-    datetime->SetTime(hour, 0, 0, 0);
-    return true;
-  }
-
-  if (str[cc] == ':')
-    cc++;
-
-  uint32_t minute = 0;
-  if (!ExtractCountDigits(str, len, 2, &cc, &minute))
-    return false;
-  if (minute >= 60)
-    return false;
-
-  if (cc >= len) {
-    datetime->SetTime(hour, minute, 0, 0);
-    return true;
-  }
-
-  if (str[cc] == ':')
-    cc++;
-
-  uint32_t second = 0;
-  uint32_t millisecond = 0;
-  if (str[cc] != 'Z') {
-    if (!ExtractCountDigits(str, len, 2, &cc, &second))
-      return false;
-    if (second >= 60)
-      return false;
-    if (cc < len && str[cc] == '.') {
-      cc++;
-      if (!ExtractCountDigits(str, len, 3, &cc, &millisecond))
-        return false;
-    }
-  }
-
-  // Skip until we find a + or - for the time zone.
-  while (cc < len) {
-    if (str[cc] == '+' || str[cc] == '-')
-      break;
-    ++cc;
-  }
-
-  if (cc < len) {
-    FX_TIMEZONE tzDiff;
-    tzDiff.tzHour = 0;
-    tzDiff.tzMinute = 0;
-    if (str[cc] != 'Z')
-      cc += ParseTimeZone(str + cc, len - cc, &tzDiff);
-
-    ResolveZone(tzDiff, pLocale, &hour, &minute);
-  }
-
-  datetime->SetTime(hour, minute, second, millisecond);
-  return true;
-}
-
-CFGAS_FormatString::CFGAS_FormatString(CXFA_LocaleMgr* pLocaleMgr)
-    : m_pLocaleMgr(pLocaleMgr) {}
-
-CFGAS_FormatString::~CFGAS_FormatString() {}
-
-void CFGAS_FormatString::SplitFormatString(
-    const WideString& wsFormatString,
-    std::vector<WideString>* wsPatterns) {
-  int32_t iStrLen = wsFormatString.GetLength();
-  const wchar_t* pStr = wsFormatString.c_str();
-  const wchar_t* pToken = pStr;
-  const wchar_t* pEnd = pStr + iStrLen;
-  bool iQuote = false;
-  while (true) {
-    if (pStr >= pEnd) {
-      wsPatterns->push_back(WideString(pToken, pStr - pToken));
-      return;
-    }
-    if (*pStr == '\'') {
-      iQuote = !iQuote;
-    } else if (*pStr == L'|' && !iQuote) {
-      wsPatterns->push_back(WideString(pToken, pStr - pToken));
-      pToken = pStr + 1;
-    }
-    pStr++;
-  }
-}
-
-FX_LOCALECATEGORY CFGAS_FormatString::GetCategory(const WideString& wsPattern) {
-  FX_LOCALECATEGORY eCategory = FX_LOCALECATEGORY_Unknown;
-  int32_t ccf = 0;
-  int32_t iLenf = wsPattern.GetLength();
-  const wchar_t* pStr = wsPattern.c_str();
-  bool bBraceOpen = false;
-  WideStringView wsConstChars(gs_wsConstChars);
-  while (ccf < iLenf) {
-    if (pStr[ccf] == '\'') {
-      GetLiteralText(pStr, &ccf, iLenf);
-    } else if (!bBraceOpen && !wsConstChars.Contains(pStr[ccf])) {
-      WideString wsCategory(pStr[ccf]);
-      ccf++;
-      while (true) {
-        if (ccf == iLenf)
-          return eCategory;
-        if (pStr[ccf] == '.' || pStr[ccf] == '(')
-          break;
-        if (pStr[ccf] == '{') {
-          bBraceOpen = true;
-          break;
-        }
-        wsCategory += pStr[ccf];
-        ccf++;
-      }
-
-      uint32_t dwHash = FX_HashCode_GetW(wsCategory.AsStringView(), false);
-      if (dwHash == FX_LOCALECATEGORY_DateTimeHash)
-        return FX_LOCALECATEGORY_DateTime;
-      if (dwHash == FX_LOCALECATEGORY_TextHash)
-        return FX_LOCALECATEGORY_Text;
-      if (dwHash == FX_LOCALECATEGORY_NumHash)
-        return FX_LOCALECATEGORY_Num;
-      if (dwHash == FX_LOCALECATEGORY_ZeroHash)
-        return FX_LOCALECATEGORY_Zero;
-      if (dwHash == FX_LOCALECATEGORY_NullHash)
-        return FX_LOCALECATEGORY_Null;
-      if (dwHash == FX_LOCALECATEGORY_DateHash) {
-        if (eCategory == FX_LOCALECATEGORY_Time)
-          return FX_LOCALECATEGORY_DateTime;
-        eCategory = FX_LOCALECATEGORY_Date;
-      } else if (dwHash == FX_LOCALECATEGORY_TimeHash) {
-        if (eCategory == FX_LOCALECATEGORY_Date)
-          return FX_LOCALECATEGORY_DateTime;
-        eCategory = FX_LOCALECATEGORY_Time;
-      }
-    } else if (pStr[ccf] == '}') {
-      bBraceOpen = false;
-    }
-    ccf++;
-  }
-  return eCategory;
-}
-
-WideString CFGAS_FormatString::GetTextFormat(const WideString& wsPattern,
-                                             const WideStringView& wsCategory) {
-  int32_t ccf = 0;
-  int32_t iLenf = wsPattern.GetLength();
-  const wchar_t* pStr = wsPattern.c_str();
-  bool bBrackOpen = false;
-  WideStringView wsConstChars(gs_wsConstChars);
-  WideString wsPurgePattern;
-  while (ccf < iLenf) {
-    if (pStr[ccf] == '\'') {
-      int32_t iCurChar = ccf;
-      GetLiteralText(pStr, &ccf, iLenf);
-      wsPurgePattern += WideStringView(pStr + iCurChar, ccf - iCurChar + 1);
-    } else if (!bBrackOpen && !wsConstChars.Contains(pStr[ccf])) {
-      WideString wsSearchCategory(pStr[ccf]);
-      ccf++;
-      while (ccf < iLenf && pStr[ccf] != '{' && pStr[ccf] != '.' &&
-             pStr[ccf] != '(') {
-        wsSearchCategory += pStr[ccf];
-        ccf++;
-      }
-      if (wsSearchCategory != wsCategory)
-        continue;
-
-      while (ccf < iLenf) {
-        if (pStr[ccf] == '(') {
-          ccf++;
-          // Skip over the encoding name.
-          while (ccf < iLenf && pStr[ccf] != ')')
-            ccf++;
-        } else if (pStr[ccf] == '{') {
-          bBrackOpen = true;
-          break;
-        }
-        ccf++;
-      }
-    } else if (pStr[ccf] != '}') {
-      wsPurgePattern += pStr[ccf];
-    }
-    ccf++;
-  }
-  if (!bBrackOpen)
-    wsPurgePattern = wsPattern;
-
-  return wsPurgePattern;
-}
-
-IFX_Locale* CFGAS_FormatString::GetNumericFormat(const WideString& wsPattern,
-                                                 int32_t* iDotIndex,
-                                                 uint32_t* dwStyle,
-                                                 WideString* wsPurgePattern) {
-  *dwStyle = 0;
-  IFX_Locale* pLocale = nullptr;
-  int32_t ccf = 0;
-  int32_t iLenf = wsPattern.GetLength();
-  const wchar_t* pStr = wsPattern.c_str();
-  bool bFindDot = false;
-  bool bBrackOpen = false;
-  WideStringView wsConstChars(gs_wsConstChars);
-  while (ccf < iLenf) {
-    if (pStr[ccf] == '\'') {
-      int32_t iCurChar = ccf;
-      GetLiteralText(pStr, &ccf, iLenf);
-      *wsPurgePattern += WideStringView(pStr + iCurChar, ccf - iCurChar + 1);
-    } else if (!bBrackOpen && !wsConstChars.Contains(pStr[ccf])) {
-      WideString wsCategory(pStr[ccf]);
-      ccf++;
-      while (ccf < iLenf && pStr[ccf] != '{' && pStr[ccf] != '.' &&
-             pStr[ccf] != '(') {
-        wsCategory += pStr[ccf];
-        ccf++;
-      }
-      if (wsCategory != L"num") {
-        bBrackOpen = true;
-        ccf = 0;
-        continue;
-      }
-      while (ccf < iLenf) {
-        if (pStr[ccf] == '{') {
-          bBrackOpen = true;
-          break;
-        }
-        if (pStr[ccf] == '(') {
-          ccf++;
-          WideString wsLCID;
-          while (ccf < iLenf && pStr[ccf] != ')')
-            wsLCID += pStr[ccf++];
-
-          pLocale = m_pLocaleMgr->GetLocaleByName(wsLCID);
-        } else if (pStr[ccf] == '.') {
-          WideString wsSubCategory;
-          ccf++;
-          while (ccf < iLenf && pStr[ccf] != '(' && pStr[ccf] != '{')
-            wsSubCategory += pStr[ccf++];
-
-          uint32_t dwSubHash =
-              FX_HashCode_GetW(wsSubCategory.AsStringView(), false);
-          FX_LOCALENUMSUBCATEGORY eSubCategory = FX_LOCALENUMPATTERN_Decimal;
-          for (int32_t i = 0; i < g_iFXLocaleNumSubCatCount; i++) {
-            if (g_FXLocaleNumSubCatData[i].uHash == dwSubHash) {
-              eSubCategory = (FX_LOCALENUMSUBCATEGORY)g_FXLocaleNumSubCatData[i]
-                                 .eSubCategory;
-              break;
-            }
-          }
-          if (!pLocale)
-            pLocale = m_pLocaleMgr->GetDefLocale();
-
-          ASSERT(pLocale);
-
-          wsSubCategory = pLocale->GetNumPattern(eSubCategory);
-          auto result = wsSubCategory.Find('.');
-          if (result.has_value() && result.value() != 0) {
-            *iDotIndex += wsPurgePattern->GetLength();
-            bFindDot = true;
-            *dwStyle |= FX_NUMSTYLE_DotVorv;
-          }
-          *wsPurgePattern += wsSubCategory;
-          if (eSubCategory == FX_LOCALENUMPATTERN_Percent)
-            *dwStyle |= FX_NUMSTYLE_Percent;
-
-          continue;
-        }
-        ccf++;
-      }
-    } else if (pStr[ccf] == 'E') {
-      *dwStyle |= FX_NUMSTYLE_Exponent;
-      *wsPurgePattern += pStr[ccf];
-    } else if (pStr[ccf] == '%') {
-      *dwStyle |= FX_NUMSTYLE_Percent;
-      *wsPurgePattern += pStr[ccf];
-    } else if (pStr[ccf] != '}') {
-      *wsPurgePattern += pStr[ccf];
-    }
-    if (!bFindDot) {
-      if (pStr[ccf] == '.' || pStr[ccf] == 'V' || pStr[ccf] == 'v') {
-        bFindDot = true;
-        *iDotIndex = wsPurgePattern->GetLength() - 1;
-        *dwStyle |= FX_NUMSTYLE_DotVorv;
-      }
-    }
-    ccf++;
-  }
-  if (!bFindDot)
-    *iDotIndex = wsPurgePattern->GetLength();
-  if (!pLocale)
-    pLocale = m_pLocaleMgr->GetDefLocale();
-  return pLocale;
-}
-
-bool CFGAS_FormatString::ParseText(const WideString& wsSrcText,
-                                   const WideString& wsPattern,
-                                   WideString* wsValue) {
-  wsValue->clear();
-  if (wsSrcText.IsEmpty() || wsPattern.IsEmpty())
-    return false;
-
-  WideString wsTextFormat = GetTextFormat(wsPattern, L"text");
-  if (wsTextFormat.IsEmpty())
-    return false;
-
-  int32_t iText = 0;
-  int32_t iPattern = 0;
-  const wchar_t* pStrText = wsSrcText.c_str();
-  int32_t iLenText = wsSrcText.GetLength();
-  const wchar_t* pStrPattern = wsTextFormat.c_str();
-  int32_t iLenPattern = wsTextFormat.GetLength();
-  while (iPattern < iLenPattern && iText < iLenText) {
-    switch (pStrPattern[iPattern]) {
-      case '\'': {
-        WideString wsLiteral =
-            GetLiteralText(pStrPattern, &iPattern, iLenPattern);
-        int32_t iLiteralLen = wsLiteral.GetLength();
-        if (iText + iLiteralLen > iLenText ||
-            wcsncmp(pStrText + iText, wsLiteral.c_str(), iLiteralLen)) {
-          *wsValue = wsSrcText;
-          return false;
-        }
-        iText += iLiteralLen;
-        iPattern++;
-        break;
-      }
-      case 'A':
-        if (FXSYS_iswalpha(pStrText[iText])) {
-          *wsValue += pStrText[iText];
-          iText++;
-        }
-        iPattern++;
-        break;
-      case 'X':
-        *wsValue += pStrText[iText];
-        iText++;
-        iPattern++;
-        break;
-      case 'O':
-      case '0':
-        if (FXSYS_isDecimalDigit(pStrText[iText]) ||
-            FXSYS_iswalpha(pStrText[iText])) {
-          *wsValue += pStrText[iText];
-          iText++;
-        }
-        iPattern++;
-        break;
-      case '9':
-        if (FXSYS_isDecimalDigit(pStrText[iText])) {
-          *wsValue += pStrText[iText];
-          iText++;
-        }
-        iPattern++;
-        break;
-      default:
-        if (pStrPattern[iPattern] != pStrText[iText]) {
-          *wsValue = wsSrcText;
-          return false;
-        }
-        iPattern++;
-        iText++;
-        break;
-    }
-  }
-  return iPattern == iLenPattern && iText == iLenText;
-}
-
-bool CFGAS_FormatString::ParseNum(const WideString& wsSrcNum,
-                                  const WideString& wsPattern,
-                                  WideString* wsValue) {
-  wsValue->clear();
-  if (wsSrcNum.IsEmpty() || wsPattern.IsEmpty())
-    return false;
-
-  int32_t dot_index_f = -1;
-  uint32_t dwFormatStyle = 0;
-  WideString wsNumFormat;
-  IFX_Locale* pLocale =
-      GetNumericFormat(wsPattern, &dot_index_f, &dwFormatStyle, &wsNumFormat);
-  if (!pLocale || wsNumFormat.IsEmpty())
-    return false;
-
-  int32_t iExponent = 0;
-  WideString wsDotSymbol =
-      pLocale->GetNumbericSymbol(FX_LOCALENUMSYMBOL_Decimal);
-  WideString wsGroupSymbol =
-      pLocale->GetNumbericSymbol(FX_LOCALENUMSYMBOL_Grouping);
-  int32_t iGroupLen = wsGroupSymbol.GetLength();
-  WideString wsMinus = pLocale->GetNumbericSymbol(FX_LOCALENUMSYMBOL_Minus);
-  int32_t iMinusLen = wsMinus.GetLength();
-  const wchar_t* str = wsSrcNum.c_str();
-  int len = wsSrcNum.GetLength();
-  const wchar_t* strf = wsNumFormat.c_str();
-  int lenf = wsNumFormat.GetLength();
-  bool bHavePercentSymbol = false;
-  bool bNeg = false;
-  bool bReverseParse = false;
-  int32_t dot_index = 0;
-
-  // If we're looking for a '.', 'V' or 'v' and the input string does not
-  // have a dot index for one of those, then we disable parsing the decimal.
-  if (!GetNumericDotIndex(wsSrcNum, wsDotSymbol, &dot_index) &&
-      (dwFormatStyle & FX_NUMSTYLE_DotVorv))
-    bReverseParse = true;
-
-  // This parse is broken into two parts based on the '.' in the number
-  // (or 'V' or 'v'). |dot_index_f| is the location of the dot in the format and
-  // |dot_index| is the location of the dot in the number.
-  //
-  // This first while() starts at the '.' and walks backwards to the start of
-  // the number. The second while() walks from the dot forwards to the end of
-  // the decimal.
-
-  int ccf = dot_index_f - 1;
-  int cc = dot_index - 1;
-  while (ccf >= 0 && cc >= 0) {
-    switch (strf[ccf]) {
-      case '\'': {
-        WideString wsLiteral = GetLiteralTextReverse(strf, &ccf);
-        int32_t iLiteralLen = wsLiteral.GetLength();
-        cc -= iLiteralLen - 1;
-        if (cc < 0 || wcsncmp(str + cc, wsLiteral.c_str(), iLiteralLen))
-          return false;
-
-        cc--;
-        ccf--;
-        break;
-      }
-      case '9':
-        if (!FXSYS_isDecimalDigit(str[cc]))
-          return false;
-
-        wsValue->InsertAtFront(str[cc]);
-        cc--;
-        ccf--;
-        break;
-      case 'z':
-      case 'Z':
-        if (strf[ccf] == 'z' || str[cc] != ' ') {
-          if (FXSYS_isDecimalDigit(str[cc])) {
-            wsValue->InsertAtFront(str[cc]);
-            cc--;
-          }
-        } else {
-          cc--;
-        }
-        ccf--;
-        break;
-      case 'S':
-      case 's':
-        if (str[cc] == '+' || (strf[ccf] == 'S' && str[cc] == ' ')) {
-          cc--;
-        } else {
-          cc -= iMinusLen - 1;
-          if (cc < 0 || wcsncmp(str + cc, wsMinus.c_str(), iMinusLen))
-            return false;
-
-          cc--;
-          bNeg = true;
-        }
-        ccf--;
-        break;
-      case 'E': {
-        bool bExpSign = false;
-        while (cc >= 0) {
-          if (str[cc] == 'E' || str[cc] == 'e')
-            break;
-          if (FXSYS_isDecimalDigit(str[cc])) {
-            iExponent = iExponent + FXSYS_DecimalCharToInt(str[cc]) * 10;
-            cc--;
-            continue;
-          }
-          if (str[cc] == '+') {
-            cc--;
-            continue;
-          }
-          if (cc - iMinusLen + 1 > 0 && !wcsncmp(str + (cc - iMinusLen + 1),
-                                                 wsMinus.c_str(), iMinusLen)) {
-            bExpSign = true;
-            cc -= iMinusLen;
-            continue;
-          }
-
-          return false;
-        }
-        cc--;
-        iExponent = bExpSign ? -iExponent : iExponent;
-        ccf--;
-        break;
-      }
-      case '$': {
-        WideString wsSymbol =
-            pLocale->GetNumbericSymbol(FX_LOCALENUMSYMBOL_CurrencySymbol);
-        int32_t iSymbolLen = wsSymbol.GetLength();
-        cc -= iSymbolLen - 1;
-        if (cc < 0 || wcsncmp(str + cc, wsSymbol.c_str(), iSymbolLen))
-          return false;
-
-        cc--;
-        ccf--;
-        break;
-      }
-      case 'r':
-      case 'R':
-        if (ccf - 1 >= 0 && ((strf[ccf] == 'R' && strf[ccf - 1] == 'C') ||
-                             (strf[ccf] == 'r' && strf[ccf - 1] == 'c'))) {
-          if (strf[ccf] == 'R' && str[cc] == ' ') {
-            cc -= 2;
-          } else if (str[cc] == 'R' && cc - 1 >= 0 && str[cc - 1] == 'C') {
-            bNeg = true;
-            cc -= 2;
-          }
-          ccf -= 2;
-        } else {
-          ccf--;
-        }
-        break;
-      case 'b':
-      case 'B':
-        if (ccf - 1 >= 0 && ((strf[ccf] == 'B' && strf[ccf - 1] == 'D') ||
-                             (strf[ccf] == 'b' && strf[ccf - 1] == 'd'))) {
-          if (strf[ccf] == 'B' && str[cc] == ' ') {
-            cc -= 2;
-          } else if (str[cc] == 'B' && cc - 1 >= 0 && str[cc - 1] == 'D') {
-            bNeg = true;
-            cc -= 2;
-          }
-          ccf -= 2;
-        } else {
-          ccf--;
-        }
-        break;
-      case '%': {
-        WideString wsSymbol =
-            pLocale->GetNumbericSymbol(FX_LOCALENUMSYMBOL_Percent);
-        int32_t iSysmbolLen = wsSymbol.GetLength();
-        cc -= iSysmbolLen - 1;
-        if (cc < 0 || wcsncmp(str + cc, wsSymbol.c_str(), iSysmbolLen))
-          return false;
-
-        cc--;
-        ccf--;
-        bHavePercentSymbol = true;
-        break;
-      }
-      case '.':
-      case 'V':
-      case 'v':
-      case '8':
-        return false;
-      case ',': {
-        if (cc >= 0) {
-          cc -= iGroupLen - 1;
-          if (cc >= 0 &&
-              wcsncmp(str + cc, wsGroupSymbol.c_str(), iGroupLen) == 0) {
-            cc--;
-          } else {
-            cc += iGroupLen - 1;
-          }
-        }
-        ccf--;
-        break;
-      }
-      case '(':
-      case ')':
-        if (str[cc] == strf[ccf])
-          bNeg = true;
-        else if (str[cc] != L' ')
-          return false;
-
-        cc--;
-        ccf--;
-        break;
-      default:
-        if (strf[ccf] != str[cc])
-          return false;
-
-        cc--;
-        ccf--;
-    }
-  }
-  if (cc >= 0) {
-    if (str[cc] == '-') {
-      bNeg = true;
-      cc--;
-    }
-    if (cc >= 0)
-      return false;
-  }
-  if (dot_index < len && (dwFormatStyle & FX_NUMSTYLE_DotVorv))
-    *wsValue += '.';
-  if (!bReverseParse) {
-    ccf = dot_index_f + 1;
-    cc = (dot_index == len) ? len : dot_index + 1;
-    while (cc < len && ccf < lenf) {
-      switch (strf[ccf]) {
-        case '\'': {
-          WideString wsLiteral = GetLiteralText(strf, &ccf, lenf);
-          int32_t iLiteralLen = wsLiteral.GetLength();
-          if (cc + iLiteralLen > len ||
-              wcsncmp(str + cc, wsLiteral.c_str(), iLiteralLen)) {
-            return false;
-          }
-          cc += iLiteralLen;
-          ccf++;
-          break;
-        }
-        case '9':
-          if (!FXSYS_isDecimalDigit(str[cc]))
-            return false;
-
-          *wsValue += str[cc];
-          cc++;
-          ccf++;
-          break;
-        case 'z':
-        case 'Z':
-          if (strf[ccf] == 'z' || str[cc] != ' ') {
-            if (FXSYS_isDecimalDigit(str[cc])) {
-              *wsValue += str[cc];
-              cc++;
-            }
-          } else {
-            cc++;
-          }
-          ccf++;
-          break;
-        case 'S':
-        case 's':
-          if (str[cc] == '+' || (strf[ccf] == 'S' && str[cc] == ' ')) {
-            cc++;
-          } else {
-            if (cc + iMinusLen > len ||
-                wcsncmp(str + cc, wsMinus.c_str(), iMinusLen)) {
-              return false;
-            }
-            bNeg = true;
-            cc += iMinusLen;
-          }
-          ccf++;
-          break;
-        case 'E': {
-          if (cc >= len || (str[cc] != 'E' && str[cc] != 'e'))
-            return false;
-
-          bool bExpSign = false;
-          cc++;
-          if (cc < len) {
-            if (str[cc] == '+') {
-              cc++;
-            } else if (str[cc] == '-') {
-              bExpSign = true;
-              cc++;
-            }
-          }
-          while (cc < len) {
-            if (!FXSYS_isDecimalDigit(str[cc]))
-              break;
-
-            iExponent = iExponent * 10 + FXSYS_DecimalCharToInt(str[cc]);
-            cc++;
-          }
-          iExponent = bExpSign ? -iExponent : iExponent;
-          ccf++;
-          break;
-        }
-        case '$': {
-          WideString wsSymbol =
-              pLocale->GetNumbericSymbol(FX_LOCALENUMSYMBOL_CurrencySymbol);
-          int32_t iSymbolLen = wsSymbol.GetLength();
-          if (cc + iSymbolLen > len ||
-              wcsncmp(str + cc, wsSymbol.c_str(), iSymbolLen)) {
-            return false;
-          }
-          cc += iSymbolLen;
-          ccf++;
-          break;
-        }
-        case 'c':
-        case 'C':
-          if (ccf + 1 < lenf && ((strf[ccf] == 'C' && strf[ccf + 1] == 'R') ||
-                                 (strf[ccf] == 'c' && strf[ccf + 1] == 'r'))) {
-            if (strf[ccf] == 'C' && str[cc] == ' ') {
-              cc++;
-            } else if (str[cc] == 'C' && cc + 1 < len && str[cc + 1] == 'R') {
-              bNeg = true;
-              cc += 2;
-            }
-            ccf += 2;
-          }
-          break;
-        case 'd':
-        case 'D':
-          if (ccf + 1 < lenf && ((strf[ccf] == 'D' && strf[ccf + 1] == 'B') ||
-                                 (strf[ccf] == 'd' && strf[ccf + 1] == 'b'))) {
-            if (strf[ccf] == 'D' && str[cc] == ' ') {
-              cc++;
-            } else if (str[cc] == 'D' && cc + 1 < len && str[cc + 1] == 'B') {
-              bNeg = true;
-              cc += 2;
-            }
-            ccf += 2;
-          }
-          break;
-        case '.':
-        case 'V':
-        case 'v':
-          return false;
-        case '%': {
-          WideString wsSymbol =
-              pLocale->GetNumbericSymbol(FX_LOCALENUMSYMBOL_Percent);
-          int32_t iSysmbolLen = wsSymbol.GetLength();
-          if (cc + iSysmbolLen <= len &&
-              !wcsncmp(str + cc, wsSymbol.c_str(), iSysmbolLen)) {
-            cc += iSysmbolLen;
-          }
-          ccf++;
-          bHavePercentSymbol = true;
-        } break;
-        case '8': {
-          while (ccf < lenf && strf[ccf] == '8')
-            ccf++;
-
-          while (cc < len && FXSYS_isDecimalDigit(str[cc])) {
-            *wsValue += str[cc];
-            cc++;
-          }
-        } break;
-        case ',': {
-          if (cc + iGroupLen <= len &&
-              wcsncmp(str + cc, wsGroupSymbol.c_str(), iGroupLen) == 0) {
-            cc += iGroupLen;
-          }
-          ccf++;
-          break;
-        }
-        case '(':
-        case ')':
-          if (str[cc] == strf[ccf])
-            bNeg = true;
-          else if (str[cc] != L' ')
-            return false;
-
-          cc++;
-          ccf++;
-          break;
-        default:
-          if (strf[ccf] != str[cc])
-            return false;
-
-          cc++;
-          ccf++;
-      }
-    }
-    if (cc != len)
-      return false;
-  }
-  if (iExponent || bHavePercentSymbol) {
-    CFX_Decimal decimal = CFX_Decimal(wsValue->AsStringView());
-    if (iExponent) {
-      decimal = decimal *
-                CFX_Decimal(FXSYS_pow(10, static_cast<float>(iExponent)), 3);
-    }
-    if (bHavePercentSymbol)
-      decimal = decimal / CFX_Decimal(100);
-
-    *wsValue = decimal;
-  }
-  if (bNeg)
-    wsValue->InsertAtFront(L'-');
-
-  return true;
-}
-
-FX_DATETIMETYPE CFGAS_FormatString::GetDateTimeFormat(
-    const WideString& wsPattern,
-    IFX_Locale** pLocale,
-    WideString* wsDatePattern,
-    WideString* wsTimePattern) {
-  *pLocale = nullptr;
-  WideString wsTempPattern;
-  FX_LOCALECATEGORY eCategory = FX_LOCALECATEGORY_Unknown;
-  int32_t ccf = 0;
-  int32_t iLenf = wsPattern.GetLength();
-  const wchar_t* pStr = wsPattern.c_str();
-  int32_t iFindCategory = 0;
-  bool bBraceOpen = false;
-  WideStringView wsConstChars(gs_wsConstChars);
-  while (ccf < iLenf) {
-    if (pStr[ccf] == '\'') {
-      int32_t iCurChar = ccf;
-      GetLiteralText(pStr, &ccf, iLenf);
-      wsTempPattern += WideStringView(pStr + iCurChar, ccf - iCurChar + 1);
-    } else if (!bBraceOpen && iFindCategory != 3 &&
-               !wsConstChars.Contains(pStr[ccf])) {
-      WideString wsCategory(pStr[ccf]);
-      ccf++;
-      while (ccf < iLenf && pStr[ccf] != '{' && pStr[ccf] != '.' &&
-             pStr[ccf] != '(') {
-        if (pStr[ccf] == 'T') {
-          *wsDatePattern = wsPattern.Left(ccf);
-          *wsTimePattern = wsPattern.Right(wsPattern.GetLength() - ccf);
-          wsTimePattern->SetAt(0, ' ');
-          if (!*pLocale)
-            *pLocale = m_pLocaleMgr->GetDefLocale();
-
-          return FX_DATETIMETYPE_DateTime;
-        }
-        wsCategory += pStr[ccf];
-        ccf++;
-      }
-      if (!(iFindCategory & 1) && wsCategory == L"date") {
-        iFindCategory |= 1;
-        eCategory = FX_LOCALECATEGORY_Date;
-        if (iFindCategory & 2)
-          iFindCategory = 4;
-      } else if (!(iFindCategory & 2) && wsCategory == L"time") {
-        iFindCategory |= 2;
-        eCategory = FX_LOCALECATEGORY_Time;
-      } else if (wsCategory == L"datetime") {
-        iFindCategory = 3;
-        eCategory = FX_LOCALECATEGORY_DateTime;
-      } else {
-        continue;
-      }
-      while (ccf < iLenf) {
-        if (pStr[ccf] == '{') {
-          bBraceOpen = true;
-          break;
-        }
-        if (pStr[ccf] == '(') {
-          ccf++;
-          WideString wsLCID;
-          while (ccf < iLenf && pStr[ccf] != ')')
-            wsLCID += pStr[ccf++];
-
-          *pLocale = m_pLocaleMgr->GetLocaleByName(wsLCID);
-        } else if (pStr[ccf] == '.') {
-          WideString wsSubCategory;
-          ccf++;
-          while (ccf < iLenf && pStr[ccf] != '(' && pStr[ccf] != '{')
-            wsSubCategory += pStr[ccf++];
-
-          uint32_t dwSubHash =
-              FX_HashCode_GetW(wsSubCategory.AsStringView(), false);
-          FX_LOCALEDATETIMESUBCATEGORY eSubCategory =
-              FX_LOCALEDATETIMESUBCATEGORY_Medium;
-          for (int32_t i = 0; i < g_iFXLocaleDateTimeSubCatCount; i++) {
-            if (g_FXLocaleDateTimeSubCatData[i].uHash == dwSubHash) {
-              eSubCategory =
-                  (FX_LOCALEDATETIMESUBCATEGORY)g_FXLocaleDateTimeSubCatData[i]
-                      .eSubCategory;
-              break;
-            }
-          }
-          if (!*pLocale)
-            *pLocale = m_pLocaleMgr->GetDefLocale();
-          ASSERT(*pLocale);
-
-          switch (eCategory) {
-            case FX_LOCALECATEGORY_Date:
-              *wsDatePattern =
-                  wsTempPattern + (*pLocale)->GetDatePattern(eSubCategory);
-              break;
-            case FX_LOCALECATEGORY_Time:
-              *wsTimePattern =
-                  wsTempPattern + (*pLocale)->GetTimePattern(eSubCategory);
-              break;
-            case FX_LOCALECATEGORY_DateTime:
-              *wsDatePattern =
-                  wsTempPattern + (*pLocale)->GetDatePattern(eSubCategory);
-              *wsTimePattern = (*pLocale)->GetTimePattern(eSubCategory);
-              break;
-            default:
-              break;
-          }
-          wsTempPattern.clear();
-          continue;
-        }
-        ccf++;
-      }
-    } else if (pStr[ccf] == '}') {
-      bBraceOpen = false;
-      if (!wsTempPattern.IsEmpty()) {
-        if (eCategory == FX_LOCALECATEGORY_Time)
-          *wsTimePattern = wsTempPattern;
-        else if (eCategory == FX_LOCALECATEGORY_Date)
-          *wsDatePattern = wsTempPattern;
-
-        wsTempPattern.clear();
-      }
-    } else {
-      wsTempPattern += pStr[ccf];
-    }
-    ccf++;
-  }
-
-  if (!wsTempPattern.IsEmpty()) {
-    if (eCategory == FX_LOCALECATEGORY_Date)
-      *wsDatePattern += wsTempPattern;
-    else
-      *wsTimePattern += wsTempPattern;
-  }
-  if (!*pLocale)
-    *pLocale = m_pLocaleMgr->GetDefLocale();
-  if (!iFindCategory) {
-    wsTimePattern->clear();
-    *wsDatePattern = wsPattern;
-  }
-  return (FX_DATETIMETYPE)iFindCategory;
-}
-
-bool CFGAS_FormatString::ParseDateTime(const WideString& wsSrcDateTime,
-                                       const WideString& wsPattern,
-                                       FX_DATETIMETYPE eDateTimeType,
-                                       CFX_DateTime* dtValue) {
-  dtValue->Reset();
-  if (wsSrcDateTime.IsEmpty() || wsPattern.IsEmpty())
-    return false;
-
-  WideString wsDatePattern;
-  WideString wsTimePattern;
-  IFX_Locale* pLocale = nullptr;
-  FX_DATETIMETYPE eCategory =
-      GetDateTimeFormat(wsPattern, &pLocale, &wsDatePattern, &wsTimePattern);
-  if (!pLocale)
-    return false;
-  if (eCategory == FX_DATETIMETYPE_Unknown)
-    eCategory = eDateTimeType;
-  if (eCategory == FX_DATETIMETYPE_Unknown)
-    return false;
-  if (eCategory == FX_DATETIMETYPE_TimeDate) {
-    int32_t iStart = 0;
-    if (!ParseLocaleTime(wsSrcDateTime, wsTimePattern, pLocale, dtValue,
-                         &iStart)) {
-      return false;
-    }
-    if (!ParseLocaleDate(wsSrcDateTime, wsDatePattern, pLocale, dtValue,
-                         &iStart)) {
-      return false;
-    }
-  } else {
-    int32_t iStart = 0;
-    if ((eCategory & FX_DATETIMETYPE_Date) &&
-        !ParseLocaleDate(wsSrcDateTime, wsDatePattern, pLocale, dtValue,
-                         &iStart)) {
-      return false;
-    }
-    if ((eCategory & FX_DATETIMETYPE_Time) &&
-        !ParseLocaleTime(wsSrcDateTime, wsTimePattern, pLocale, dtValue,
-                         &iStart)) {
-      return false;
-    }
-  }
-  return true;
-}
-
-bool CFGAS_FormatString::ParseZero(const WideString& wsSrcText,
-                                   const WideString& wsPattern) {
-  WideString wsTextFormat = GetTextFormat(wsPattern, L"zero");
-
-  int32_t iText = 0;
-  int32_t iPattern = 0;
-  const wchar_t* pStrText = wsSrcText.c_str();
-  int32_t iLenText = wsSrcText.GetLength();
-  const wchar_t* pStrPattern = wsTextFormat.c_str();
-  int32_t iLenPattern = wsTextFormat.GetLength();
-  while (iPattern < iLenPattern && iText < iLenText) {
-    if (pStrPattern[iPattern] == '\'') {
-      WideString wsLiteral =
-          GetLiteralText(pStrPattern, &iPattern, iLenPattern);
-      int32_t iLiteralLen = wsLiteral.GetLength();
-      if (iText + iLiteralLen > iLenText ||
-          wcsncmp(pStrText + iText, wsLiteral.c_str(), iLiteralLen)) {
-        return false;
-      }
-      iText += iLiteralLen;
-      iPattern++;
-      continue;
-    }
-    if (pStrPattern[iPattern] != pStrText[iText])
-      return false;
-
-    iText++;
-    iPattern++;
-  }
-  return iPattern == iLenPattern && iText == iLenText;
-}
-
-bool CFGAS_FormatString::ParseNull(const WideString& wsSrcText,
-                                   const WideString& wsPattern) {
-  WideString wsTextFormat = GetTextFormat(wsPattern, L"null");
-
-  int32_t iText = 0;
-  int32_t iPattern = 0;
-  const wchar_t* pStrText = wsSrcText.c_str();
-  int32_t iLenText = wsSrcText.GetLength();
-  const wchar_t* pStrPattern = wsTextFormat.c_str();
-  int32_t iLenPattern = wsTextFormat.GetLength();
-  while (iPattern < iLenPattern && iText < iLenText) {
-    if (pStrPattern[iPattern] == '\'') {
-      WideString wsLiteral =
-          GetLiteralText(pStrPattern, &iPattern, iLenPattern);
-      int32_t iLiteralLen = wsLiteral.GetLength();
-      if (iText + iLiteralLen > iLenText ||
-          wcsncmp(pStrText + iText, wsLiteral.c_str(), iLiteralLen)) {
-        return false;
-      }
-      iText += iLiteralLen;
-      iPattern++;
-      continue;
-    }
-    if (pStrPattern[iPattern] != pStrText[iText])
-      return false;
-
-    iText++;
-    iPattern++;
-  }
-  return iPattern == iLenPattern && iText == iLenText;
-}
-
-bool CFGAS_FormatString::FormatText(const WideString& wsSrcText,
-                                    const WideString& wsPattern,
-                                    WideString* wsOutput) {
-  if (wsPattern.IsEmpty())
-    return false;
-
-  int32_t iLenText = wsSrcText.GetLength();
-  if (iLenText == 0)
-    return false;
-
-  WideString wsTextFormat = GetTextFormat(wsPattern, L"text");
-
-  int32_t iText = 0;
-  int32_t iPattern = 0;
-  const wchar_t* pStrText = wsSrcText.c_str();
-  const wchar_t* pStrPattern = wsTextFormat.c_str();
-  int32_t iLenPattern = wsTextFormat.GetLength();
-  while (iPattern < iLenPattern) {
-    switch (pStrPattern[iPattern]) {
-      case '\'': {
-        *wsOutput += GetLiteralText(pStrPattern, &iPattern, iLenPattern);
-        iPattern++;
-        break;
-      }
-      case 'A':
-        if (iText >= iLenText || !FXSYS_iswalpha(pStrText[iText]))
-          return false;
-
-        *wsOutput += pStrText[iText++];
-        iPattern++;
-        break;
-      case 'X':
-        if (iText >= iLenText)
-          return false;
-
-        *wsOutput += pStrText[iText++];
-        iPattern++;
-        break;
-      case 'O':
-      case '0':
-        if (iText >= iLenText || (!FXSYS_isDecimalDigit(pStrText[iText]) &&
-                                  !FXSYS_iswalpha(pStrText[iText]))) {
-          return false;
-        }
-        *wsOutput += pStrText[iText++];
-        iPattern++;
-        break;
-      case '9':
-        if (iText >= iLenText || !FXSYS_isDecimalDigit(pStrText[iText]))
-          return false;
-
-        *wsOutput += pStrText[iText++];
-        iPattern++;
-        break;
-      default:
-        *wsOutput += pStrPattern[iPattern++];
-        break;
-    }
-  }
-  return iText == iLenText;
-}
-
-bool CFGAS_FormatString::FormatStrNum(const WideStringView& wsInputNum,
-                                      const WideString& wsPattern,
-                                      WideString* wsOutput) {
-  if (wsInputNum.IsEmpty() || wsPattern.IsEmpty())
-    return false;
-
-  int32_t dot_index_f = -1;
-  uint32_t dwNumStyle = 0;
-  WideString wsNumFormat;
-  IFX_Locale* pLocale =
-      GetNumericFormat(wsPattern, &dot_index_f, &dwNumStyle, &wsNumFormat);
-  if (!pLocale || wsNumFormat.IsEmpty())
-    return false;
-
-  int32_t cc = 0, ccf = 0;
-  const wchar_t* strf = wsNumFormat.c_str();
-  int lenf = wsNumFormat.GetLength();
-  WideString wsSrcNum(wsInputNum);
-  wsSrcNum.TrimLeft('0');
-  if (wsSrcNum.IsEmpty() || wsSrcNum[0] == '.')
-    wsSrcNum.InsertAtFront('0');
-
-  CFX_Decimal decimal = CFX_Decimal(wsSrcNum.AsStringView());
-  if (dwNumStyle & FX_NUMSTYLE_Percent) {
-    decimal = decimal * CFX_Decimal(100);
-    wsSrcNum = decimal;
-  }
-
-  int32_t exponent = 0;
-  if (dwNumStyle & FX_NUMSTYLE_Exponent) {
-    int fixed_count = 0;
-    while (ccf < dot_index_f) {
-      switch (strf[ccf]) {
-        case '\'':
-          GetLiteralText(strf, &ccf, dot_index_f);
-          break;
-        case '9':
-        case 'z':
-        case 'Z':
-          fixed_count++;
-          break;
-      }
-      ccf++;
-    }
-
-    int threshold = 1;
-    while (fixed_count > 1) {
-      threshold *= 10;
-      fixed_count--;
-    }
-    if (decimal != CFX_Decimal(0)) {
-      if (decimal < CFX_Decimal(threshold)) {
-        decimal = decimal * CFX_Decimal(10);
-        exponent = -1;
-        while (decimal < CFX_Decimal(threshold)) {
-          decimal = decimal * CFX_Decimal(10);
-          exponent -= 1;
-        }
-      } else if (decimal > CFX_Decimal(threshold)) {
-        threshold *= 10;
-        while (decimal > CFX_Decimal(threshold)) {
-          decimal = decimal / CFX_Decimal(10);
-          exponent += 1;
-        }
-      }
-    }
-  }
-
-  bool bTrimTailZeros = false;
-  int32_t iTreading =
-      GetNumTrailingLimit(wsNumFormat, dot_index_f, &bTrimTailZeros);
-  int32_t scale = decimal.GetScale();
-  if (iTreading < scale) {
-    decimal.SetScale(iTreading);
-    wsSrcNum = decimal;
-  }
-  if (bTrimTailZeros && scale > 0 && iTreading > 0) {
-    wsSrcNum.TrimRight(L"0");
-    wsSrcNum.TrimRight(L".");
-  }
-
-  WideString wsGroupSymbol =
-      pLocale->GetNumbericSymbol(FX_LOCALENUMSYMBOL_Grouping);
-  bool bNeg = false;
-  if (wsSrcNum[0] == '-') {
-    bNeg = true;
-    wsSrcNum.Delete(0, 1);
-  }
-
-  bool bAddNeg = false;
-  const wchar_t* str = wsSrcNum.c_str();
-  int len = wsSrcNum.GetLength();
-  auto dot_index = wsSrcNum.Find('.');
-  if (!dot_index.has_value())
-    dot_index = len;
-
-  ccf = dot_index_f - 1;
-  cc = dot_index.value() - 1;
-  while (ccf >= 0) {
-    switch (strf[ccf]) {
-      case '9':
-        if (cc >= 0) {
-          if (!FXSYS_isDecimalDigit(str[cc]))
-            return false;
-
-          wsOutput->InsertAtFront(str[cc]);
-          cc--;
-        } else {
-          wsOutput->InsertAtFront(L'0');
-        }
-        ccf--;
-        break;
-      case 'z':
-        if (cc >= 0) {
-          if (!FXSYS_isDecimalDigit(str[cc]))
-            return false;
-          if (str[0] != '0')
-            wsOutput->InsertAtFront(str[cc]);
-
-          cc--;
-        }
-        ccf--;
-        break;
-      case 'Z':
-        if (cc >= 0) {
-          if (!FXSYS_isDecimalDigit(str[cc]))
-            return false;
-
-          wsOutput->InsertAtFront(str[0] == '0' ? L' ' : str[cc]);
-          cc--;
-        } else {
-          wsOutput->InsertAtFront(L' ');
-        }
-        ccf--;
-        break;
-      case 'S':
-        if (bNeg) {
-          *wsOutput =
-              pLocale->GetNumbericSymbol(FX_LOCALENUMSYMBOL_Minus) + *wsOutput;
-          bAddNeg = true;
-        } else {
-          wsOutput->InsertAtFront(L' ');
-        }
-        ccf--;
-        break;
-      case 's':
-        if (bNeg) {
-          *wsOutput =
-              pLocale->GetNumbericSymbol(FX_LOCALENUMSYMBOL_Minus) + *wsOutput;
-          bAddNeg = true;
-        }
-        ccf--;
-        break;
-      case 'E': {
-        *wsOutput = WideString::Format(L"E%+d", exponent) + *wsOutput;
-        ccf--;
-        break;
-      }
-      case '$': {
-        *wsOutput =
-            pLocale->GetNumbericSymbol(FX_LOCALENUMSYMBOL_CurrencySymbol) +
-            *wsOutput;
-        ccf--;
-        break;
-      }
-      case 'r':
-        if (ccf - 1 >= 0 && strf[ccf - 1] == 'c') {
-          if (bNeg)
-            *wsOutput = L"CR" + *wsOutput;
-
-          ccf -= 2;
-          bAddNeg = true;
-        }
-        break;
-      case 'R':
-        if (ccf - 1 >= 0 && strf[ccf - 1] == 'C') {
-          *wsOutput = bNeg ? L"CR" : L"  " + *wsOutput;
-          ccf -= 2;
-          bAddNeg = true;
-        }
-        break;
-      case 'b':
-        if (ccf - 1 >= 0 && strf[ccf - 1] == 'd') {
-          if (bNeg)
-            *wsOutput = L"db" + *wsOutput;
-
-          ccf -= 2;
-          bAddNeg = true;
-        }
-        break;
-      case 'B':
-        if (ccf - 1 >= 0 && strf[ccf - 1] == 'D') {
-          *wsOutput = bNeg ? L"DB" : L"  " + *wsOutput;
-          ccf -= 2;
-          bAddNeg = true;
-        }
-        break;
-      case '%': {
-        *wsOutput =
-            pLocale->GetNumbericSymbol(FX_LOCALENUMSYMBOL_Percent) + *wsOutput;
-        ccf--;
-        break;
-      }
-      case ',':
-        if (cc >= 0)
-          *wsOutput = wsGroupSymbol + *wsOutput;
-
-        ccf--;
-        break;
-      case '(':
-        wsOutput->InsertAtFront(bNeg ? L'(' : L' ');
-        bAddNeg = true;
-        ccf--;
-        break;
-      case ')':
-        wsOutput->InsertAtFront(bNeg ? L')' : L' ');
-        ccf--;
-        break;
-      case '\'':
-        *wsOutput = GetLiteralTextReverse(strf, &ccf) + *wsOutput;
-        ccf--;
-        break;
-      default:
-        wsOutput->InsertAtFront(strf[ccf]);
-        ccf--;
-    }
-  }
-
-  if (cc >= 0) {
-    int nPos = dot_index.value() % 3;
-    wsOutput->clear();
-    for (int32_t i = 0;
-         i < pdfium::base::checked_cast<int32_t>(dot_index.value()); i++) {
-      if (i % 3 == nPos && i != 0)
-        *wsOutput += wsGroupSymbol;
-      *wsOutput += wsSrcNum[i];
-    }
-    if (pdfium::base::checked_cast<int32_t>(dot_index.value()) < len) {
-      *wsOutput += pLocale->GetNumbericSymbol(FX_LOCALENUMSYMBOL_Decimal);
-      *wsOutput += wsSrcNum.Right(len - dot_index.value() - 1);
-    }
-    if (bNeg) {
-      *wsOutput =
-          pLocale->GetNumbericSymbol(FX_LOCALENUMSYMBOL_Minus) + *wsOutput;
-    }
-    return false;
-  }
-  if (dot_index_f ==
-      pdfium::base::checked_cast<int32_t>(wsNumFormat.GetLength())) {
-    if (!bAddNeg && bNeg) {
-      *wsOutput =
-          pLocale->GetNumbericSymbol(FX_LOCALENUMSYMBOL_Minus) + *wsOutput;
-    }
-    return true;
-  }
-
-  WideString wsDotSymbol =
-      pLocale->GetNumbericSymbol(FX_LOCALENUMSYMBOL_Decimal);
-  if (strf[dot_index_f] == 'V') {
-    *wsOutput += wsDotSymbol;
-  } else if (strf[dot_index_f] == '.') {
-    if (pdfium::base::checked_cast<int32_t>(dot_index.value()) < len)
-      *wsOutput += wsDotSymbol;
-    else if (strf[dot_index_f + 1] == '9' || strf[dot_index_f + 1] == 'Z')
-      *wsOutput += wsDotSymbol;
-  }
-
-  ccf = dot_index_f + 1;
-  cc = dot_index.value() + 1;
-  while (ccf < lenf) {
-    switch (strf[ccf]) {
-      case '\'':
-        *wsOutput += GetLiteralText(strf, &ccf, lenf);
-        ccf++;
-        break;
-      case '9':
-        if (cc < len) {
-          if (!FXSYS_isDecimalDigit(str[cc]))
-            return false;
-
-          *wsOutput += str[cc];
-          cc++;
-        } else {
-          *wsOutput += L'0';
-        }
-        ccf++;
-        break;
-      case 'z':
-        if (cc < len) {
-          if (!FXSYS_isDecimalDigit(str[cc]))
-            return false;
-
-          *wsOutput += str[cc];
-          cc++;
-        }
-        ccf++;
-        break;
-      case 'Z':
-        if (cc < len) {
-          if (!FXSYS_isDecimalDigit(str[cc]))
-            return false;
-
-          *wsOutput += str[cc];
-          cc++;
-        } else {
-          *wsOutput += L'0';
-        }
-        ccf++;
-        break;
-      case 'E': {
-        *wsOutput += WideString::Format(L"E%+d", exponent);
-        ccf++;
-        break;
-      }
-      case '$':
-        *wsOutput +=
-            pLocale->GetNumbericSymbol(FX_LOCALENUMSYMBOL_CurrencySymbol);
-        ccf++;
-        break;
-      case 'c':
-        if (ccf + 1 < lenf && strf[ccf + 1] == 'r') {
-          if (bNeg)
-            *wsOutput += L"CR";
-
-          ccf += 2;
-          bAddNeg = true;
-        }
-        break;
-      case 'C':
-        if (ccf + 1 < lenf && strf[ccf + 1] == 'R') {
-          *wsOutput += bNeg ? L"CR" : L"  ";
-          ccf += 2;
-          bAddNeg = true;
-        }
-        break;
-      case 'd':
-        if (ccf + 1 < lenf && strf[ccf + 1] == 'b') {
-          if (bNeg)
-            *wsOutput += L"db";
-
-          ccf += 2;
-          bAddNeg = true;
-        }
-        break;
-      case 'D':
-        if (ccf + 1 < lenf && strf[ccf + 1] == 'B') {
-          *wsOutput += bNeg ? L"DB" : L"  ";
-          ccf += 2;
-          bAddNeg = true;
-        }
-        break;
-      case '%':
-        *wsOutput += pLocale->GetNumbericSymbol(FX_LOCALENUMSYMBOL_Percent);
-        ccf++;
-        break;
-      case '8':
-        while (ccf < lenf && strf[ccf] == '8')
-          ccf++;
-        while (cc < len && FXSYS_isDecimalDigit(str[cc])) {
-          *wsOutput += str[cc];
-          cc++;
-        }
-        break;
-      case ',':
-        *wsOutput += wsGroupSymbol;
-        ccf++;
-        break;
-      case '(':
-        *wsOutput += bNeg ? '(' : ' ';
-        bAddNeg = true;
-        ccf++;
-        break;
-      case ')':
-        *wsOutput += bNeg ? ')' : ' ';
-        ccf++;
-        break;
-      default:
-        ccf++;
-    }
-  }
-  if (!bAddNeg && bNeg) {
-    *wsOutput = pLocale->GetNumbericSymbol(FX_LOCALENUMSYMBOL_Minus) +
-                (*wsOutput)[0] + wsOutput->Right(wsOutput->GetLength() - 1);
-  }
-  return true;
-}
-
-bool CFGAS_FormatString::FormatNum(const WideString& wsSrcNum,
-                                   const WideString& wsPattern,
-                                   WideString* wsOutput) {
-  if (wsSrcNum.IsEmpty() || wsPattern.IsEmpty())
-    return false;
-  return FormatStrNum(wsSrcNum.AsStringView(), wsPattern, wsOutput);
-}
-
-bool CFGAS_FormatString::FormatDateTime(const WideString& wsSrcDateTime,
-                                        const WideString& wsPattern,
-                                        FX_DATETIMETYPE eDateTimeType,
-                                        WideString* wsOutput) {
-  if (wsSrcDateTime.IsEmpty() || wsPattern.IsEmpty())
-    return false;
-
-  WideString wsDatePattern;
-  WideString wsTimePattern;
-  IFX_Locale* pLocale = nullptr;
-  FX_DATETIMETYPE eCategory =
-      GetDateTimeFormat(wsPattern, &pLocale, &wsDatePattern, &wsTimePattern);
-  if (!pLocale)
-    return false;
-
-  if (eCategory == FX_DATETIMETYPE_Unknown) {
-    if (eDateTimeType == FX_DATETIMETYPE_Time) {
-      wsTimePattern = wsDatePattern;
-      wsDatePattern.clear();
-    }
-    eCategory = eDateTimeType;
-  }
-  if (eCategory == FX_DATETIMETYPE_Unknown)
-    return false;
-
-  CFX_DateTime dt;
-  auto iT = wsSrcDateTime.Find(L"T");
-  if (!iT.has_value()) {
-    if (eCategory == FX_DATETIMETYPE_Date &&
-        FX_DateFromCanonical(wsSrcDateTime, &dt)) {
-      *wsOutput = FormatDateTimeInternal(dt, wsDatePattern, wsTimePattern, true,
-                                         pLocale);
-      return true;
-    }
-    if (eCategory == FX_DATETIMETYPE_Time &&
-        FX_TimeFromCanonical(wsSrcDateTime.AsStringView(), &dt, pLocale)) {
-      *wsOutput = FormatDateTimeInternal(dt, wsDatePattern, wsTimePattern, true,
-                                         pLocale);
-      return true;
-    }
-  } else {
-    WideString wsSrcDate(wsSrcDateTime.c_str(), iT.value());
-    WideStringView wsSrcTime(wsSrcDateTime.c_str() + iT.value() + 1,
-                             wsSrcDateTime.GetLength() - iT.value() - 1);
-    if (wsSrcDate.IsEmpty() || wsSrcTime.IsEmpty())
-      return false;
-    if (FX_DateFromCanonical(wsSrcDate, &dt) &&
-        FX_TimeFromCanonical(wsSrcTime, &dt, pLocale)) {
-      *wsOutput = FormatDateTimeInternal(dt, wsDatePattern, wsTimePattern,
-                                         eCategory != FX_DATETIMETYPE_TimeDate,
-                                         pLocale);
-      return true;
-    }
-  }
-  return false;
-}
-
-bool CFGAS_FormatString::FormatZero(const WideString& wsPattern,
-                                    WideString* wsOutput) {
-  if (wsPattern.IsEmpty())
-    return false;
-
-  WideString wsTextFormat = GetTextFormat(wsPattern, L"zero");
-  int32_t iPattern = 0;
-  const wchar_t* pStrPattern = wsTextFormat.c_str();
-  int32_t iLenPattern = wsTextFormat.GetLength();
-  while (iPattern < iLenPattern) {
-    if (pStrPattern[iPattern] == '\'') {
-      *wsOutput += GetLiteralText(pStrPattern, &iPattern, iLenPattern);
-      iPattern++;
-    } else {
-      *wsOutput += pStrPattern[iPattern++];
-    }
-  }
-  return true;
-}
-
-bool CFGAS_FormatString::FormatNull(const WideString& wsPattern,
-                                    WideString* wsOutput) {
-  if (wsPattern.IsEmpty())
-    return false;
-
-  WideString wsTextFormat = GetTextFormat(wsPattern, L"null");
-  int32_t iPattern = 0;
-  const wchar_t* pStrPattern = wsTextFormat.c_str();
-  int32_t iLenPattern = wsTextFormat.GetLength();
-  while (iPattern < iLenPattern) {
-    if (pStrPattern[iPattern] == '\'') {
-      *wsOutput += GetLiteralText(pStrPattern, &iPattern, iLenPattern);
-      iPattern++;
-      continue;
-    }
-    *wsOutput += pStrPattern[iPattern++];
-  }
-  return true;
-}
diff --git a/xfa/fgas/crt/cfgas_formatstring.h b/xfa/fgas/crt/cfgas_formatstring.h
deleted file mode 100644
index 5eae25d..0000000
--- a/xfa/fgas/crt/cfgas_formatstring.h
+++ /dev/null
@@ -1,73 +0,0 @@
-// 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_FGAS_CRT_CFGAS_FORMATSTRING_H_
-#define XFA_FGAS_CRT_CFGAS_FORMATSTRING_H_
-
-#include <vector>
-
-#include "core/fxcrt/ifx_locale.h"
-#include "xfa/fxfa/parser/cxfa_localemgr.h"
-
-bool FX_DateFromCanonical(const WideString& wsDate, CFX_DateTime* datetime);
-bool FX_TimeFromCanonical(const WideStringView& wsTime,
-                          CFX_DateTime* datetime,
-                          IFX_Locale* pLocale);
-
-class CFGAS_FormatString {
- public:
-  explicit CFGAS_FormatString(CXFA_LocaleMgr* pLocaleMgr);
-  ~CFGAS_FormatString();
-
-  void SplitFormatString(const WideString& wsFormatString,
-                         std::vector<WideString>* wsPatterns);
-  FX_LOCALECATEGORY GetCategory(const WideString& wsPattern);
-
-  bool ParseText(const WideString& wsSrcText,
-                 const WideString& wsPattern,
-                 WideString* wsValue);
-  bool ParseNum(const WideString& wsSrcNum,
-                const WideString& wsPattern,
-                WideString* wsValue);
-  bool ParseDateTime(const WideString& wsSrcDateTime,
-                     const WideString& wsPattern,
-                     FX_DATETIMETYPE eDateTimeType,
-                     CFX_DateTime* dtValue);
-  bool ParseZero(const WideString& wsSrcText, const WideString& wsPattern);
-  bool ParseNull(const WideString& wsSrcText, const WideString& wsPattern);
-
-  bool FormatText(const WideString& wsSrcText,
-                  const WideString& wsPattern,
-                  WideString* wsOutput);
-  bool FormatNum(const WideString& wsSrcNum,
-                 const WideString& wsPattern,
-                 WideString* wsOutput);
-  bool FormatDateTime(const WideString& wsSrcDateTime,
-                      const WideString& wsPattern,
-                      FX_DATETIMETYPE eDateTimeType,
-                      WideString* wsOutput);
-  bool FormatZero(const WideString& wsPattern, WideString* wsOutput);
-  bool FormatNull(const WideString& wsPattern, WideString* wsOutput);
-
- private:
-  WideString GetTextFormat(const WideString& wsPattern,
-                           const WideStringView& wsCategory);
-  IFX_Locale* GetNumericFormat(const WideString& wsPattern,
-                               int32_t* iDotIndex,
-                               uint32_t* dwStyle,
-                               WideString* wsPurgePattern);
-  bool FormatStrNum(const WideStringView& wsInputNum,
-                    const WideString& wsPattern,
-                    WideString* wsOutput);
-  FX_DATETIMETYPE GetDateTimeFormat(const WideString& wsPattern,
-                                    IFX_Locale** pLocale,
-                                    WideString* wsDatePattern,
-                                    WideString* wsTimePattern);
-
-  CXFA_LocaleMgr* m_pLocaleMgr;
-};
-
-#endif  // XFA_FGAS_CRT_CFGAS_FORMATSTRING_H_
diff --git a/xfa/fgas/crt/cfgas_stringformatter.cpp b/xfa/fgas/crt/cfgas_stringformatter.cpp
new file mode 100644
index 0000000..1c640b9
--- /dev/null
+++ b/xfa/fgas/crt/cfgas_stringformatter.cpp
@@ -0,0 +1,2265 @@
+// Copyright 2014 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
+
+#include "xfa/fgas/crt/cfgas_stringformatter.h"
+
+#include <algorithm>
+#include <limits>
+#include <utility>
+#include <vector>
+
+#include "core/fxcrt/fx_extension.h"
+#include "core/fxcrt/fx_safe_types.h"
+#include "third_party/base/stl_util.h"
+#include "xfa/fgas/crt/cfgas_decimal.h"
+
+// NOTE: Code uses the convention for backwards-looping with unsigned types
+// that exploits the well-defined behaviour for unsigned underflow (and hence
+// the standard x < size() can be used in all cases to validate indices).
+
+#define FX_LOCALECATEGORY_DateHash 0xbde9abde
+#define FX_LOCALECATEGORY_TimeHash 0x2d71b00f
+#define FX_LOCALECATEGORY_DateTimeHash 0x158c72ed
+#define FX_LOCALECATEGORY_NumHash 0x0b4ff870
+#define FX_LOCALECATEGORY_TextHash 0x2d08af85
+#define FX_LOCALECATEGORY_ZeroHash 0x568cb500
+#define FX_LOCALECATEGORY_NullHash 0x052931bb
+
+#define FX_NUMSTYLE_Percent 0x01
+#define FX_NUMSTYLE_Exponent 0x02
+#define FX_NUMSTYLE_DotVorv 0x04
+
+namespace {
+
+struct LocaleDateTimeSubCategoryWithHash {
+  uint32_t uHash;  // Hashed as wide string.
+  FX_LOCALEDATETIMESUBCATEGORY eSubCategory;
+};
+
+struct LocaleNumberSubCategoryWithHash {
+  uint32_t uHash;  // Hashed as wide string.
+  FX_LOCALENUMSUBCATEGORY eSubCategory;
+};
+
+#undef SUBC
+#define SUBC(a, b, c) a, c
+
+const LocaleDateTimeSubCategoryWithHash g_FXLocaleDateTimeSubCatData[] = {
+    {SUBC(0x14da2125, "default", FX_LOCALEDATETIMESUBCATEGORY_Default)},
+    {SUBC(0x9041d4b0, "short", FX_LOCALEDATETIMESUBCATEGORY_Short)},
+    {SUBC(0xa084a381, "medium", FX_LOCALEDATETIMESUBCATEGORY_Medium)},
+    {SUBC(0xcdce56b3, "full", FX_LOCALEDATETIMESUBCATEGORY_Full)},
+    {SUBC(0xf6b4afb0, "long", FX_LOCALEDATETIMESUBCATEGORY_Long)},
+};
+
+const LocaleNumberSubCategoryWithHash g_FXLocaleNumSubCatData[] = {
+    {SUBC(0x46f95531, "percent", FX_LOCALENUMPATTERN_Percent)},
+    {SUBC(0x4c4e8acb, "currency", FX_LOCALENUMPATTERN_Currency)},
+    {SUBC(0x54034c2f, "decimal", FX_LOCALENUMPATTERN_Decimal)},
+    {SUBC(0x7568e6ae, "integer", FX_LOCALENUMPATTERN_Integer)},
+};
+
+#undef SUBC
+
+struct FX_LOCALETIMEZONEINFO {
+  const wchar_t* name;
+  int16_t iHour;
+  int16_t iMinute;
+};
+
+const FX_LOCALETIMEZONEINFO g_FXLocaleTimeZoneData[] = {
+    {L"CDT", -5, 0}, {L"CST", -6, 0}, {L"EDT", -4, 0}, {L"EST", -5, 0},
+    {L"MDT", -6, 0}, {L"MST", -7, 0}, {L"PDT", -7, 0}, {L"PST", -8, 0},
+};
+
+const wchar_t kTimeSymbols[] = L"hHkKMSFAzZ";
+const wchar_t kDateSymbols[] = L"DJMEeGgYwW";
+const wchar_t kConstChars[] = L",-:/. ";
+
+size_t ParseTimeZone(pdfium::span<const wchar_t> spStr, FX_TIMEZONE* tz) {
+  tz->tzHour = 0;
+  tz->tzMinute = 0;
+  if (spStr.empty())
+    return 0;
+
+  // Keep index by 0 close to empty() check above for optimizer's sake.
+  const bool bNegative = (spStr[0] == '-');
+
+  size_t iStart = 1;
+  size_t iEnd = iStart + 2;
+  while (iStart < spStr.size() && iStart < iEnd)
+    tz->tzHour = tz->tzHour * 10 + FXSYS_DecimalCharToInt(spStr[iStart++]);
+
+  if (iStart < spStr.size() && spStr[iStart] == ':')
+    iStart++;
+
+  iEnd = iStart + 2;
+  while (iStart < spStr.size() && iStart < iEnd)
+    tz->tzMinute = tz->tzMinute * 10 + FXSYS_DecimalCharToInt(spStr[iStart++]);
+
+  if (bNegative)
+    tz->tzHour = -tz->tzHour;
+
+  return iStart;
+}
+
+int32_t ConvertHex(int32_t iKeyValue, wchar_t ch) {
+  if (FXSYS_IsHexDigit(ch))
+    return iKeyValue * 16 + FXSYS_HexCharToInt(ch);
+  return iKeyValue;
+}
+
+WideString GetLiteralText(pdfium::span<const wchar_t> spStrPattern,
+                          size_t* iPattern) {
+  WideString wsOutput;
+  if (*iPattern >= spStrPattern.size() || spStrPattern[*iPattern] != '\'')
+    return wsOutput;
+
+  (*iPattern)++;
+  int32_t iQuote = 1;
+  while (*iPattern < spStrPattern.size()) {
+    if (spStrPattern[*iPattern] == '\'') {
+      iQuote++;
+      if ((*iPattern + 1 >= spStrPattern.size()) ||
+          ((spStrPattern[*iPattern + 1] != '\'') && (iQuote % 2 == 0))) {
+        break;
+      }
+      iQuote++;
+      (*iPattern)++;
+    } else if (spStrPattern[*iPattern] == '\\' &&
+               (*iPattern + 1 < spStrPattern.size()) &&
+               spStrPattern[*iPattern + 1] == 'u') {
+      int32_t iKeyValue = 0;
+      *iPattern += 2;
+      for (int32_t i = 0; *iPattern < spStrPattern.size() && i < 4; ++i) {
+        wchar_t ch = spStrPattern[(*iPattern)++];
+        iKeyValue = ConvertHex(iKeyValue, ch);
+      }
+      if (iKeyValue != 0)
+        wsOutput += static_cast<wchar_t>(iKeyValue & 0x0000FFFF);
+
+      continue;
+    }
+    wsOutput += spStrPattern[(*iPattern)++];
+  }
+  return wsOutput;
+}
+
+WideString GetLiteralTextReverse(pdfium::span<const wchar_t> spStrPattern,
+                                 size_t* iPattern) {
+  WideString wsOutput;
+  if (*iPattern >= spStrPattern.size() || spStrPattern[*iPattern] != '\'')
+    return wsOutput;
+
+  (*iPattern)--;
+  int32_t iQuote = 1;
+
+  while (*iPattern < spStrPattern.size()) {
+    if (spStrPattern[*iPattern] == '\'') {
+      iQuote++;
+      if (*iPattern - 1 >= spStrPattern.size() ||
+          ((spStrPattern[*iPattern - 1] != '\'') && (iQuote % 2 == 0))) {
+        break;
+      }
+      iQuote++;
+      (*iPattern)--;
+    } else if (spStrPattern[*iPattern] == '\\' &&
+               *iPattern + 1 < spStrPattern.size() &&
+               spStrPattern[*iPattern + 1] == 'u') {
+      (*iPattern)--;
+      int32_t iKeyValue = 0;
+      int32_t iLen = wsOutput.GetLength();
+      int32_t i = 1;
+      for (; i < iLen && i < 5; i++) {
+        wchar_t ch = wsOutput[i];
+        iKeyValue = ConvertHex(iKeyValue, ch);
+      }
+      if (iKeyValue != 0) {
+        wsOutput.Delete(0, i);
+        wsOutput = (wchar_t)(iKeyValue & 0x0000FFFF) + wsOutput;
+      }
+      continue;
+    }
+    wsOutput = spStrPattern[(*iPattern)--] + wsOutput;
+  }
+  return wsOutput;
+}
+
+bool GetNumericDotIndex(const WideString& wsNum,
+                        const WideString& wsDotSymbol,
+                        size_t* iDotIndex) {
+  pdfium::span<const wchar_t> spNum = wsNum.span();
+  pdfium::span<const wchar_t> spDotSymbol = wsDotSymbol.span();
+  for (size_t ccf = 0; ccf < spNum.size(); ++ccf) {
+    if (spNum[ccf] == '\'') {
+      GetLiteralText(spNum, &ccf);
+      continue;
+    }
+    if (ccf + spDotSymbol.size() <= spNum.size() &&
+        wcsncmp(&spNum[ccf], spDotSymbol.data(), spDotSymbol.size()) == 0) {
+      *iDotIndex = ccf;
+      return true;
+    }
+  }
+  auto result = wsNum.Find('.');
+  *iDotIndex = result.value_or(spNum.size());
+  return result.has_value();
+}
+
+bool ExtractCountDigits(pdfium::span<const wchar_t> spStr,
+                        size_t count,
+                        size_t* cc,
+                        uint32_t* value) {
+  for (size_t i = 0; i < count; ++i) {
+    if (*cc >= spStr.size() || !FXSYS_IsDecimalDigit(spStr[*cc]))
+      return false;
+    *value = *value * 10 + FXSYS_DecimalCharToInt(spStr[(*cc)++]);
+  }
+  return true;
+}
+
+bool ExtractCountDigitsWithOptional(pdfium::span<const wchar_t> spStr,
+                                    int count,
+                                    size_t* cc,
+                                    uint32_t* value) {
+  if (!ExtractCountDigits(spStr, count, cc, value))
+    return false;
+  ExtractCountDigits(spStr, 1, cc, value);
+  return true;
+}
+
+bool ParseLocaleDate(const WideString& wsDate,
+                     const WideString& wsDatePattern,
+                     LocaleIface* pLocale,
+                     CFX_DateTime* datetime,
+                     size_t* cc) {
+  uint32_t year = 1900;
+  uint32_t month = 1;
+  uint32_t day = 1;
+  size_t ccf = 0;
+  pdfium::span<const wchar_t> spDate = wsDate.span();
+  pdfium::span<const wchar_t> spDatePattern = wsDatePattern.span();
+  while (*cc < spDate.size() && ccf < spDatePattern.size()) {
+    if (spDatePattern[ccf] == '\'') {
+      WideString wsLiteral = GetLiteralText(spDatePattern, &ccf);
+      int32_t iLiteralLen = wsLiteral.GetLength();
+      if (*cc + iLiteralLen > spDate.size() ||
+          wcsncmp(spDate.data() + *cc, wsLiteral.c_str(), iLiteralLen) != 0) {
+        return false;
+      }
+      *cc += iLiteralLen;
+      ccf++;
+      continue;
+    }
+    if (!pdfium::ContainsValue(kDateSymbols, spDatePattern[ccf])) {
+      if (spDatePattern[ccf] != spDate[*cc])
+        return false;
+      (*cc)++;
+      ccf++;
+      continue;
+    }
+
+    WideString symbol;
+    symbol.Reserve(4);
+    symbol += spDatePattern[ccf++];
+    while (ccf < spDatePattern.size() && spDatePattern[ccf] == symbol[0]) {
+      symbol += spDatePattern[ccf++];
+    }
+    if (symbol.EqualsASCII("D") || symbol.EqualsASCII("DD")) {
+      day = 0;
+      if (!ExtractCountDigitsWithOptional(spDate, 1, cc, &day))
+        return false;
+    } else if (symbol.EqualsASCII("J")) {
+      uint32_t val = 0;
+      ExtractCountDigits(spDate, 3, cc, &val);
+    } else if (symbol.EqualsASCII("M") || symbol.EqualsASCII("MM")) {
+      month = 0;
+      if (!ExtractCountDigitsWithOptional(spDate, 1, cc, &month))
+        return false;
+    } else if (symbol.EqualsASCII("MMM") || symbol.EqualsASCII("MMMM")) {
+      for (uint16_t i = 0; i < 12; i++) {
+        WideString wsMonthName =
+            pLocale->GetMonthName(i, symbol.EqualsASCII("MMM"));
+        if (wsMonthName.IsEmpty())
+          continue;
+        if (wcsncmp(wsMonthName.c_str(), spDate.data() + *cc,
+                    wsMonthName.GetLength()) == 0) {
+          *cc += wsMonthName.GetLength();
+          month = i + 1;
+          break;
+        }
+      }
+    } else if (symbol.EqualsASCII("EEE") || symbol.EqualsASCII("EEEE")) {
+      for (uint16_t i = 0; i < 7; i++) {
+        WideString wsDayName =
+            pLocale->GetDayName(i, symbol.EqualsASCII("EEE"));
+        if (wsDayName.IsEmpty())
+          continue;
+        if (wcsncmp(wsDayName.c_str(), spDate.data() + *cc,
+                    wsDayName.GetLength()) == 0) {
+          *cc += wsDayName.GetLength();
+          break;
+        }
+      }
+    } else if (symbol.EqualsASCII("YY") || symbol.EqualsASCII("YYYY")) {
+      if (*cc + symbol.GetLength() > spDate.size())
+        return false;
+
+      year = 0;
+      if (!ExtractCountDigits(spDate, symbol.GetLength(), cc, &year))
+        return false;
+      if (symbol.EqualsASCII("YY")) {
+        if (year <= 29)
+          year += 2000;
+        else
+          year += 1900;
+      }
+    } else if (symbol.EqualsASCII("G")) {
+      *cc += 2;
+    } else if (symbol.EqualsASCII("JJJ") || symbol.EqualsASCIINoCase("E") ||
+               symbol.EqualsASCII("w") || symbol.EqualsASCII("WW")) {
+      *cc += symbol.GetLength();
+    }
+  }
+  if (*cc < spDate.size())
+    return false;
+
+  datetime->SetDate(year, month, day);
+  return !!(*cc);
+}
+
+void ResolveZone(FX_TIMEZONE tzDiff,
+                 const LocaleIface* pLocale,
+                 uint32_t* wHour,
+                 uint32_t* wMinute) {
+  int32_t iMinuteDiff = *wHour * 60 + *wMinute;
+  FX_TIMEZONE tzLocale = pLocale->GetTimeZone();
+  iMinuteDiff += tzLocale.tzHour * 60 +
+                 (tzLocale.tzHour < 0 ? -tzLocale.tzMinute : tzLocale.tzMinute);
+  iMinuteDiff -= tzDiff.tzHour * 60 +
+                 (tzDiff.tzHour < 0 ? -tzDiff.tzMinute : tzDiff.tzMinute);
+
+  iMinuteDiff %= 1440;
+  if (iMinuteDiff < 0)
+    iMinuteDiff += 1440;
+
+  *wHour = iMinuteDiff / 60;
+  *wMinute = iMinuteDiff % 60;
+}
+
+bool ParseLocaleTime(const WideString& wsTime,
+                     const WideString& wsTimePattern,
+                     LocaleIface* pLocale,
+                     CFX_DateTime* datetime,
+                     size_t* cc) {
+  uint32_t hour = 0;
+  uint32_t minute = 0;
+  uint32_t second = 0;
+  uint32_t millisecond = 0;
+  size_t ccf = 0;
+  pdfium::span<const wchar_t> spTime = wsTime.span();
+  pdfium::span<const wchar_t> spTimePattern = wsTimePattern.span();
+  bool bHasA = false;
+  bool bPM = false;
+  while (*cc < spTime.size() && ccf < spTimePattern.size()) {
+    if (spTimePattern[ccf] == '\'') {
+      WideString wsLiteral = GetLiteralText(spTimePattern, &ccf);
+      int32_t iLiteralLen = wsLiteral.GetLength();
+      if (*cc + iLiteralLen > spTime.size() ||
+          wcsncmp(spTime.data() + *cc, wsLiteral.c_str(), iLiteralLen) != 0) {
+        return false;
+      }
+      *cc += iLiteralLen;
+      ccf++;
+      continue;
+    }
+    if (!pdfium::ContainsValue(kTimeSymbols, spTimePattern[ccf])) {
+      if (spTimePattern[ccf] != spTime[*cc])
+        return false;
+      (*cc)++;
+      ccf++;
+      continue;
+    }
+
+    WideString symbol;
+    symbol.Reserve(4);
+    symbol += spTimePattern[ccf++];
+    while (ccf < spTimePattern.size() && spTimePattern[ccf] == symbol[0])
+      symbol += spTimePattern[ccf++];
+
+    if (symbol.EqualsASCIINoCase("k") || symbol.EqualsASCIINoCase("h")) {
+      hour = 0;
+      if (!ExtractCountDigitsWithOptional(spTime, 1, cc, &hour))
+        return false;
+      if (symbol.EqualsASCII("K") && hour == 24)
+        hour = 0;
+    } else if (symbol.EqualsASCIINoCase("kk") ||
+               symbol.EqualsASCIINoCase("hh")) {
+      hour = 0;
+      if (!ExtractCountDigits(spTime, 2, cc, &hour))
+        return false;
+      if (symbol.EqualsASCII("KK") && hour == 24)
+        hour = 0;
+    } else if (symbol.EqualsASCII("M")) {
+      minute = 0;
+      if (!ExtractCountDigitsWithOptional(spTime, 1, cc, &minute))
+        return false;
+    } else if (symbol.EqualsASCII("MM")) {
+      minute = 0;
+      if (!ExtractCountDigits(spTime, 2, cc, &minute))
+        return false;
+    } else if (symbol.EqualsASCII("S")) {
+      second = 0;
+      if (!ExtractCountDigitsWithOptional(spTime, 1, cc, &second))
+        return false;
+    } else if (symbol.EqualsASCII("SS")) {
+      second = 0;
+      if (!ExtractCountDigits(spTime, 2, cc, &second))
+        return false;
+    } else if (symbol.EqualsASCII("FFF")) {
+      millisecond = 0;
+      if (!ExtractCountDigits(spTime, 3, cc, &millisecond))
+        return false;
+    } else if (symbol.EqualsASCII("A")) {
+      WideString wsAM = pLocale->GetMeridiemName(true);
+      WideString wsPM = pLocale->GetMeridiemName(false);
+      if (*cc + wsAM.GetLength() <= spTime.size() &&
+          WideStringView(spTime.data() + *cc, wsAM.GetLength()) == wsAM) {
+        *cc += wsAM.GetLength();
+        bHasA = true;
+      } else if (*cc + wsPM.GetLength() <= spTime.size() &&
+                 WideStringView(spTime.data() + *cc, wsPM.GetLength()) ==
+                     wsPM) {
+        *cc += wsPM.GetLength();
+        bHasA = true;
+        bPM = true;
+      }
+    } else if (symbol.EqualsASCII("Z")) {
+      if (*cc + 3 > spTime.size())
+        continue;
+
+      WideString tz(spTime[(*cc)++]);
+      tz += spTime[(*cc)++];
+      tz += spTime[(*cc)++];
+      if (tz.EqualsASCII("GMT")) {
+        FX_TIMEZONE tzDiff;
+        tzDiff.tzHour = 0;
+        tzDiff.tzMinute = 0;
+        if (*cc < spTime.size() && (spTime[*cc] == '-' || spTime[*cc] == '+')) {
+          *cc += ParseTimeZone(spTime.subspan(*cc), &tzDiff);
+        }
+        ResolveZone(tzDiff, pLocale, &hour, &minute);
+      } else {
+        // Search the timezone list. There are only 8 of them, so linear scan.
+        for (size_t i = 0; i < FX_ArraySize(g_FXLocaleTimeZoneData); ++i) {
+          const FX_LOCALETIMEZONEINFO& info = g_FXLocaleTimeZoneData[i];
+          if (tz != info.name)
+            continue;
+
+          hour += info.iHour;
+          minute += info.iHour > 0 ? info.iMinute : -info.iMinute;
+          break;
+        }
+      }
+    } else if (symbol.EqualsASCII("z")) {
+      if (spTime[*cc] != 'Z') {
+        FX_TIMEZONE tzDiff;
+        *cc += ParseTimeZone(spTime.subspan(*cc), &tzDiff);
+        ResolveZone(tzDiff, pLocale, &hour, &minute);
+      } else {
+        (*cc)++;
+      }
+    }
+  }
+  if (bHasA) {
+    if (bPM) {
+      hour += 12;
+      if (hour == 24)
+        hour = 12;
+    } else {
+      if (hour == 12)
+        hour = 0;
+    }
+  }
+  datetime->SetTime(hour, minute, second, millisecond);
+  return !!(*cc);
+}
+
+size_t GetNumTrailingLimit(const WideString& wsFormat,
+                           size_t iDotPos,
+                           bool* bTrimTailZeros) {
+  const pdfium::span<const wchar_t> spFormat = wsFormat.span();
+  size_t iTrailing = 0;
+  for (++iDotPos; iDotPos < spFormat.size(); ++iDotPos) {
+    wchar_t wc = spFormat[iDotPos];
+    if (wc == L'z' || wc == L'9' || wc == 'Z') {
+      iTrailing++;
+      *bTrimTailZeros = wc != L'9';
+    }
+  }
+  return iTrailing;
+}
+
+bool IsLeapYear(uint32_t year) {
+  return (year % 4 == 0 && year % 100 != 0) || year % 400 == 0;
+}
+
+bool MonthHas30Days(uint32_t month) {
+  return month == 4 || month == 6 || month == 9 || month == 11;
+}
+
+bool MonthHas31Days(uint32_t month) {
+  return month != 2 && !MonthHas30Days(month);
+}
+
+// |month| is 1-based. e.g. 1 means January.
+uint16_t GetSolarMonthDays(uint16_t year, uint16_t month) {
+  if (month == 2)
+    return FX_IsLeapYear(year) ? 29 : 28;
+
+  return MonthHas30Days(month) ? 30 : 31;
+}
+
+uint16_t GetWeekDay(uint16_t year, uint16_t month, uint16_t day) {
+  static const uint8_t kMonthDay[] = {0, 3, 3, 6, 1, 4, 6, 2, 5, 0, 3, 5};
+  uint16_t nDays =
+      (year - 1) % 7 + (year - 1) / 4 - (year - 1) / 100 + (year - 1) / 400;
+  nDays += kMonthDay[month - 1] + day;
+  if (FX_IsLeapYear(year) && month > 2)
+    nDays++;
+  return nDays % 7;
+}
+
+uint16_t GetWeekOfMonth(uint16_t year, uint16_t month, uint16_t day) {
+  uint16_t week_day = GetWeekDay(year, month, 1);
+  uint16_t week_index = 0;
+  week_index += day / 7;
+  day = day % 7;
+  if (week_day + day > 7)
+    week_index++;
+  return week_index;
+}
+
+uint16_t GetWeekOfYear(uint16_t year, uint16_t month, uint16_t day) {
+  uint16_t nDays = 0;
+  for (uint16_t i = 1; i < month; i++)
+    nDays += GetSolarMonthDays(year, i);
+
+  nDays += day;
+  uint16_t week_day = GetWeekDay(year, 1, 1);
+  uint16_t week_index = 1;
+  week_index += nDays / 7;
+  nDays = nDays % 7;
+  if (week_day + nDays > 7)
+    week_index++;
+  return week_index;
+}
+
+WideString NumToString(size_t fmt_size, int32_t value) {
+  return WideString::Format(
+      fmt_size == 1 ? L"%d" : fmt_size == 2 ? L"%02d" : L"%03d", value);
+}
+
+WideString DateFormat(const WideString& wsDatePattern,
+                      LocaleIface* pLocale,
+                      const CFX_DateTime& datetime) {
+  WideString wsResult;
+  int32_t year = datetime.GetYear();
+  uint8_t month = datetime.GetMonth();
+  uint8_t day = datetime.GetDay();
+  size_t ccf = 0;
+  pdfium::span<const wchar_t> spDatePattern = wsDatePattern.span();
+  while (ccf < spDatePattern.size()) {
+    if (spDatePattern[ccf] == '\'') {
+      wsResult += GetLiteralText(spDatePattern, &ccf);
+      ccf++;
+      continue;
+    }
+    if (!pdfium::ContainsValue(kDateSymbols, spDatePattern[ccf])) {
+      wsResult += spDatePattern[ccf++];
+      continue;
+    }
+    WideString symbol;
+    symbol.Reserve(4);
+    symbol += spDatePattern[ccf++];
+    while (ccf < spDatePattern.size() && spDatePattern[ccf] == symbol[0])
+      symbol += spDatePattern[ccf++];
+
+    if (symbol.EqualsASCII("D") || symbol.EqualsASCII("DD")) {
+      wsResult += NumToString(symbol.GetLength(), day);
+    } else if (symbol.EqualsASCII("J") || symbol.EqualsASCII("JJJ")) {
+      uint16_t nDays = 0;
+      for (int i = 1; i < month; i++)
+        nDays += GetSolarMonthDays(year, i);
+      nDays += day;
+      wsResult += NumToString(symbol.GetLength(), nDays);
+    } else if (symbol.EqualsASCII("M") || symbol.EqualsASCII("MM")) {
+      wsResult += NumToString(symbol.GetLength(), month);
+    } else if (symbol.EqualsASCII("MMM") || symbol.EqualsASCII("MMMM")) {
+      wsResult += pLocale->GetMonthName(month - 1, symbol.EqualsASCII("MMM"));
+    } else if (symbol.EqualsASCIINoCase("e")) {
+      uint16_t wWeekDay = GetWeekDay(year, month, day);
+      wsResult +=
+          NumToString(1, symbol.EqualsASCII("E") ? wWeekDay + 1
+                                                 : (wWeekDay ? wWeekDay : 7));
+    } else if (symbol.EqualsASCII("EEE") || symbol.EqualsASCII("EEEE")) {
+      wsResult += pLocale->GetDayName(GetWeekDay(year, month, day),
+                                      symbol.EqualsASCII("EEE"));
+    } else if (symbol.EqualsASCII("G")) {
+      wsResult += pLocale->GetEraName(year > 0);
+    } else if (symbol.EqualsASCII("YY")) {
+      wsResult += NumToString(2, year % 100);
+    } else if (symbol.EqualsASCII("YYYY")) {
+      wsResult += NumToString(1, year);
+    } else if (symbol.EqualsASCII("w")) {
+      wsResult += NumToString(1, GetWeekOfMonth(year, month, day));
+    } else if (symbol.EqualsASCII("WW")) {
+      wsResult += NumToString(2, GetWeekOfYear(year, month, day));
+    }
+  }
+  return wsResult;
+}
+
+WideString TimeFormat(const WideString& wsTimePattern,
+                      LocaleIface* pLocale,
+                      const CFX_DateTime& datetime) {
+  WideString wsResult;
+  uint8_t hour = datetime.GetHour();
+  uint8_t minute = datetime.GetMinute();
+  uint8_t second = datetime.GetSecond();
+  uint16_t millisecond = datetime.GetMillisecond();
+  size_t ccf = 0;
+  pdfium::span<const wchar_t> spTimePattern = wsTimePattern.span();
+  uint16_t wHour = hour;
+  bool bPM = false;
+  if (wsTimePattern.Contains('A')) {
+    if (wHour >= 12)
+      bPM = true;
+  }
+
+  while (ccf < spTimePattern.size()) {
+    if (spTimePattern[ccf] == '\'') {
+      wsResult += GetLiteralText(spTimePattern, &ccf);
+      ccf++;
+      continue;
+    }
+    if (!pdfium::ContainsValue(kTimeSymbols, spTimePattern[ccf])) {
+      wsResult += spTimePattern[ccf++];
+      continue;
+    }
+
+    WideString symbol;
+    symbol.Reserve(4);
+    symbol += spTimePattern[ccf++];
+    while (ccf < spTimePattern.size() && spTimePattern[ccf] == symbol[0])
+      symbol += spTimePattern[ccf++];
+
+    if (symbol.EqualsASCII("h") || symbol.EqualsASCII("hh")) {
+      if (wHour > 12)
+        wHour -= 12;
+      wsResult += NumToString(symbol.GetLength(), wHour == 0 ? 12 : wHour);
+    } else if (symbol.EqualsASCII("K") || symbol.EqualsASCII("KK")) {
+      wsResult += NumToString(symbol.GetLength(), wHour == 0 ? 24 : wHour);
+    } else if (symbol.EqualsASCII("k") || symbol.EqualsASCII("kk")) {
+      if (wHour > 12)
+        wHour -= 12;
+      wsResult += NumToString(symbol.GetLength(), wHour);
+    } else if (symbol.EqualsASCII("H") || symbol.EqualsASCII("HH")) {
+      wsResult += NumToString(symbol.GetLength(), wHour);
+    } else if (symbol.EqualsASCII("M") || symbol.EqualsASCII("MM")) {
+      wsResult += NumToString(symbol.GetLength(), minute);
+    } else if (symbol.EqualsASCII("S") || symbol.EqualsASCII("SS")) {
+      wsResult += NumToString(symbol.GetLength(), second);
+    } else if (symbol.EqualsASCII("FFF")) {
+      wsResult += NumToString(3, millisecond);
+    } else if (symbol.EqualsASCII("A")) {
+      wsResult += pLocale->GetMeridiemName(!bPM);
+    } else if (symbol.EqualsASCIINoCase("z")) {
+      if (symbol.EqualsASCII("Z"))
+        wsResult += L"GMT";
+      FX_TIMEZONE tz = pLocale->GetTimeZone();
+      if (tz.tzHour != 0 || tz.tzMinute != 0) {
+        wsResult += tz.tzHour < 0 ? L"-" : L"+";
+        wsResult +=
+            WideString::Format(L"%02d:%02d", abs(tz.tzHour), tz.tzMinute);
+      }
+    }
+  }
+  return wsResult;
+}
+
+WideString FormatDateTimeInternal(const CFX_DateTime& dt,
+                                  const WideString& wsDatePattern,
+                                  const WideString& wsTimePattern,
+                                  bool bDateFirst,
+                                  LocaleIface* pLocale) {
+  WideString wsDateOut;
+  if (!wsDatePattern.IsEmpty())
+    wsDateOut = DateFormat(wsDatePattern, pLocale, dt);
+
+  WideString wsTimeOut;
+  if (!wsTimePattern.IsEmpty())
+    wsTimeOut = TimeFormat(wsTimePattern, pLocale, dt);
+
+  return bDateFirst ? wsDateOut + wsTimeOut : wsTimeOut + wsDateOut;
+}
+
+}  // namespace
+
+bool FX_DateFromCanonical(pdfium::span<const wchar_t> spDate,
+                          CFX_DateTime* datetime) {
+  if (spDate.size() > 10)
+    return false;
+
+  size_t cc = 0;
+  uint32_t year = 0;
+  if (!ExtractCountDigits(spDate, 4, &cc, &year))
+    return false;
+  if (year < 1900)
+    return false;
+  if (cc >= spDate.size()) {
+    datetime->SetDate(year, 1, 1);
+    return true;
+  }
+
+  if (spDate[cc] == '-')
+    cc++;
+
+  uint32_t month = 0;
+  if (!ExtractCountDigits(spDate, 2, &cc, &month) || month < 1 || month > 12)
+    return false;
+
+  if (cc >= spDate.size()) {
+    datetime->SetDate(year, month, 1);
+    return true;
+  }
+
+  if (spDate[cc] == '-')
+    cc++;
+
+  uint32_t day = 0;
+  if (!ExtractCountDigits(spDate, 2, &cc, &day))
+    return false;
+  if (day < 1)
+    return false;
+  if ((MonthHas31Days(month) && day > 31) ||
+      (MonthHas30Days(month) && day > 30)) {
+    return false;
+  }
+  if (month == 2 && day > (IsLeapYear(year) ? 29U : 28U))
+    return false;
+
+  datetime->SetDate(year, month, day);
+  return true;
+}
+
+bool FX_TimeFromCanonical(const LocaleIface* pLocale,
+                          pdfium::span<const wchar_t> spTime,
+                          CFX_DateTime* datetime) {
+  if (spTime.empty())
+    return false;
+
+  size_t cc = 0;
+  uint32_t hour = 0;
+  if (!ExtractCountDigits(spTime, 2, &cc, &hour) || hour >= 24)
+    return false;
+
+  if (cc >= spTime.size()) {
+    datetime->SetTime(hour, 0, 0, 0);
+    return true;
+  }
+
+  if (spTime[cc] == ':')
+    cc++;
+
+  uint32_t minute = 0;
+  if (!ExtractCountDigits(spTime, 2, &cc, &minute) || minute >= 60)
+    return false;
+
+  if (cc >= spTime.size()) {
+    datetime->SetTime(hour, minute, 0, 0);
+    return true;
+  }
+
+  if (spTime[cc] == ':')
+    cc++;
+
+  uint32_t second = 0;
+  uint32_t millisecond = 0;
+  if (cc < spTime.size() && spTime[cc] != 'Z') {
+    if (!ExtractCountDigits(spTime, 2, &cc, &second) || second >= 60)
+      return false;
+
+    if (cc < spTime.size() && spTime[cc] == '.') {
+      cc++;
+      if (!ExtractCountDigits(spTime, 3, &cc, &millisecond))
+        return false;
+    }
+  }
+
+  // Skip until we find a + or - for the time zone.
+  while (cc < spTime.size()) {
+    if (spTime[cc] == '+' || spTime[cc] == '-')
+      break;
+    ++cc;
+  }
+
+  if (cc < spTime.size()) {
+    FX_TIMEZONE tzDiff;
+    tzDiff.tzHour = 0;
+    tzDiff.tzMinute = 0;
+    if (spTime[cc] != 'Z')
+      cc += ParseTimeZone(spTime.subspan(cc), &tzDiff);
+    ResolveZone(tzDiff, pLocale, &hour, &minute);
+  }
+
+  datetime->SetTime(hour, minute, second, millisecond);
+  return true;
+}
+
+CFGAS_StringFormatter::CFGAS_StringFormatter(LocaleMgrIface* pLocaleMgr,
+                                             const WideString& wsPattern)
+    : m_pLocaleMgr(pLocaleMgr),
+      m_wsPattern(wsPattern),
+      m_spPattern(m_wsPattern.span()) {}
+
+CFGAS_StringFormatter::~CFGAS_StringFormatter() = default;
+
+// static
+std::vector<WideString> CFGAS_StringFormatter::SplitOnBars(
+    const WideString& wsFormatString) {
+  std::vector<WideString> wsPatterns;
+  pdfium::span<const wchar_t> spFormatString = wsFormatString.span();
+  size_t index = 0;
+  size_t token = 0;
+  bool bQuote = false;
+  for (; index < spFormatString.size(); ++index) {
+    if (spFormatString[index] == '\'') {
+      bQuote = !bQuote;
+    } else if (spFormatString[index] == L'|' && !bQuote) {
+      wsPatterns.emplace_back(spFormatString.data() + token, index - token);
+      token = index + 1;
+    }
+  }
+  wsPatterns.emplace_back(spFormatString.data() + token, index - token);
+  return wsPatterns;
+}
+
+FX_LOCALECATEGORY CFGAS_StringFormatter::GetCategory() const {
+  FX_LOCALECATEGORY eCategory = FX_LOCALECATEGORY_Unknown;
+  size_t ccf = 0;
+  bool bBraceOpen = false;
+  while (ccf < m_spPattern.size()) {
+    if (m_spPattern[ccf] == '\'') {
+      GetLiteralText(m_spPattern, &ccf);
+    } else if (!bBraceOpen &&
+               !pdfium::ContainsValue(kConstChars, m_spPattern[ccf])) {
+      WideString wsCategory(m_spPattern[ccf]);
+      ccf++;
+      while (true) {
+        if (ccf >= m_spPattern.size())
+          return eCategory;
+        if (m_spPattern[ccf] == '.' || m_spPattern[ccf] == '(')
+          break;
+        if (m_spPattern[ccf] == '{') {
+          bBraceOpen = true;
+          break;
+        }
+        wsCategory += m_spPattern[ccf];
+        ccf++;
+      }
+      uint32_t dwHash = FX_HashCode_GetW(wsCategory.AsStringView(), false);
+      if (dwHash == FX_LOCALECATEGORY_DateTimeHash)
+        return FX_LOCALECATEGORY_DateTime;
+      if (dwHash == FX_LOCALECATEGORY_TextHash)
+        return FX_LOCALECATEGORY_Text;
+      if (dwHash == FX_LOCALECATEGORY_NumHash)
+        return FX_LOCALECATEGORY_Num;
+      if (dwHash == FX_LOCALECATEGORY_ZeroHash)
+        return FX_LOCALECATEGORY_Zero;
+      if (dwHash == FX_LOCALECATEGORY_NullHash)
+        return FX_LOCALECATEGORY_Null;
+      if (dwHash == FX_LOCALECATEGORY_DateHash) {
+        if (eCategory == FX_LOCALECATEGORY_Time)
+          return FX_LOCALECATEGORY_DateTime;
+        eCategory = FX_LOCALECATEGORY_Date;
+      } else if (dwHash == FX_LOCALECATEGORY_TimeHash) {
+        if (eCategory == FX_LOCALECATEGORY_Date)
+          return FX_LOCALECATEGORY_DateTime;
+        eCategory = FX_LOCALECATEGORY_Time;
+      }
+    } else if (m_spPattern[ccf] == '}') {
+      bBraceOpen = false;
+    }
+    ccf++;
+  }
+  return eCategory;
+}
+
+WideString CFGAS_StringFormatter::GetTextFormat(
+    WideStringView wsCategory) const {
+  size_t ccf = 0;
+  bool bBrackOpen = false;
+  WideString wsPurgePattern;
+  while (ccf < m_spPattern.size()) {
+    if (m_spPattern[ccf] == '\'') {
+      int32_t iCurChar = ccf;
+      GetLiteralText(m_spPattern, &ccf);
+      wsPurgePattern +=
+          WideStringView(m_spPattern.data() + iCurChar, ccf - iCurChar + 1);
+    } else if (!bBrackOpen &&
+               !pdfium::ContainsValue(kConstChars, m_spPattern[ccf])) {
+      WideString wsSearchCategory(m_spPattern[ccf]);
+      ccf++;
+      while (ccf < m_spPattern.size() && m_spPattern[ccf] != '{' &&
+             m_spPattern[ccf] != '.' && m_spPattern[ccf] != '(') {
+        wsSearchCategory += m_spPattern[ccf];
+        ccf++;
+      }
+      if (wsSearchCategory != wsCategory)
+        continue;
+
+      while (ccf < m_spPattern.size()) {
+        if (m_spPattern[ccf] == '(') {
+          ccf++;
+          // Skip over the encoding name.
+          while (ccf < m_spPattern.size() && m_spPattern[ccf] != ')')
+            ccf++;
+        } else if (m_spPattern[ccf] == '{') {
+          bBrackOpen = true;
+          break;
+        }
+        ccf++;
+      }
+    } else if (m_spPattern[ccf] != '}') {
+      wsPurgePattern += m_spPattern[ccf];
+    }
+    ccf++;
+  }
+  if (!bBrackOpen)
+    wsPurgePattern = m_wsPattern;
+
+  return wsPurgePattern;
+}
+
+LocaleIface* CFGAS_StringFormatter::GetNumericFormat(
+    size_t* iDotIndex,
+    uint32_t* dwStyle,
+    WideString* wsPurgePattern) const {
+  *dwStyle = 0;
+  LocaleIface* pLocale = nullptr;
+  size_t ccf = 0;
+  bool bFindDot = false;
+  bool bBrackOpen = false;
+  while (ccf < m_spPattern.size()) {
+    if (m_spPattern[ccf] == '\'') {
+      int32_t iCurChar = ccf;
+      GetLiteralText(m_spPattern, &ccf);
+      *wsPurgePattern +=
+          WideStringView(m_spPattern.data() + iCurChar, ccf - iCurChar + 1);
+    } else if (!bBrackOpen &&
+               !pdfium::ContainsValue(kConstChars, m_spPattern[ccf])) {
+      WideString wsCategory(m_spPattern[ccf]);
+      ccf++;
+      while (ccf < m_spPattern.size() && m_spPattern[ccf] != '{' &&
+             m_spPattern[ccf] != '.' && m_spPattern[ccf] != '(') {
+        wsCategory += m_spPattern[ccf];
+        ccf++;
+      }
+      if (!wsCategory.EqualsASCII("num")) {
+        bBrackOpen = true;
+        ccf = 0;
+        continue;
+      }
+      while (ccf < m_spPattern.size()) {
+        if (m_spPattern[ccf] == '{') {
+          bBrackOpen = true;
+          break;
+        }
+        if (m_spPattern[ccf] == '(') {
+          ccf++;
+          WideString wsLCID;
+          while (ccf < m_spPattern.size() && m_spPattern[ccf] != ')')
+            wsLCID += m_spPattern[ccf++];
+
+          pLocale = m_pLocaleMgr->GetLocaleByName(wsLCID);
+        } else if (m_spPattern[ccf] == '.') {
+          WideString wsSubCategory;
+          ccf++;
+          while (ccf < m_spPattern.size() && m_spPattern[ccf] != '(' &&
+                 m_spPattern[ccf] != '{') {
+            wsSubCategory += m_spPattern[ccf++];
+          }
+          uint32_t dwSubHash =
+              FX_HashCode_GetW(wsSubCategory.AsStringView(), false);
+          FX_LOCALENUMSUBCATEGORY eSubCategory = FX_LOCALENUMPATTERN_Decimal;
+          for (const auto& data : g_FXLocaleNumSubCatData) {
+            if (data.uHash == dwSubHash) {
+              eSubCategory = data.eSubCategory;
+              break;
+            }
+          }
+          if (!pLocale)
+            pLocale = m_pLocaleMgr->GetDefLocale();
+
+          ASSERT(pLocale);
+
+          wsSubCategory = pLocale->GetNumPattern(eSubCategory);
+          auto result = wsSubCategory.Find('.');
+          if (result.has_value() && result.value() != 0) {
+            if (!bFindDot)
+              *iDotIndex = wsPurgePattern->GetLength() + result.value();
+            bFindDot = true;
+            *dwStyle |= FX_NUMSTYLE_DotVorv;
+          }
+          *wsPurgePattern += wsSubCategory;
+          if (eSubCategory == FX_LOCALENUMPATTERN_Percent)
+            *dwStyle |= FX_NUMSTYLE_Percent;
+
+          continue;
+        }
+        ccf++;
+      }
+    } else if (m_spPattern[ccf] == 'E') {
+      *dwStyle |= FX_NUMSTYLE_Exponent;
+      *wsPurgePattern += m_spPattern[ccf];
+    } else if (m_spPattern[ccf] == '%') {
+      *dwStyle |= FX_NUMSTYLE_Percent;
+      *wsPurgePattern += m_spPattern[ccf];
+    } else if (m_spPattern[ccf] != '}') {
+      *wsPurgePattern += m_spPattern[ccf];
+    }
+    if (!bFindDot && ccf < m_spPattern.size() &&
+        (m_spPattern[ccf] == '.' || m_spPattern[ccf] == 'V' ||
+         m_spPattern[ccf] == 'v')) {
+      bFindDot = true;
+      *iDotIndex = wsPurgePattern->GetLength() - 1;
+      *dwStyle |= FX_NUMSTYLE_DotVorv;
+    }
+    ccf++;
+  }
+  if (!bFindDot)
+    *iDotIndex = wsPurgePattern->GetLength();
+  if (!pLocale)
+    pLocale = m_pLocaleMgr->GetDefLocale();
+  return pLocale;
+}
+
+bool CFGAS_StringFormatter::ParseText(const WideString& wsSrcText,
+                                      WideString* wsValue) const {
+  wsValue->clear();
+  if (wsSrcText.IsEmpty() || m_spPattern.empty())
+    return false;
+
+  WideString wsTextFormat = GetTextFormat(L"text");
+  if (wsTextFormat.IsEmpty())
+    return false;
+
+  pdfium::span<const wchar_t> spSrcText = wsSrcText.span();
+  pdfium::span<const wchar_t> spTextFormat = wsTextFormat.span();
+
+  size_t iText = 0;
+  size_t iPattern = 0;
+  while (iPattern < spTextFormat.size() && iText < spSrcText.size()) {
+    switch (spTextFormat[iPattern]) {
+      case '\'': {
+        WideString wsLiteral = GetLiteralText(spTextFormat, &iPattern);
+        int32_t iLiteralLen = wsLiteral.GetLength();
+        if (iText + iLiteralLen > spSrcText.size() ||
+            wcsncmp(spSrcText.data() + iText, wsLiteral.c_str(), iLiteralLen) !=
+                0) {
+          *wsValue = wsSrcText;
+          return false;
+        }
+        iText += iLiteralLen;
+        iPattern++;
+        break;
+      }
+      case 'A':
+        if (FXSYS_iswalpha(spSrcText[iText])) {
+          *wsValue += spSrcText[iText];
+          iText++;
+        }
+        iPattern++;
+        break;
+      case 'X':
+        *wsValue += spSrcText[iText];
+        iText++;
+        iPattern++;
+        break;
+      case 'O':
+      case '0':
+        if (FXSYS_IsDecimalDigit(spSrcText[iText]) ||
+            FXSYS_iswalpha(spSrcText[iText])) {
+          *wsValue += spSrcText[iText];
+          iText++;
+        }
+        iPattern++;
+        break;
+      case '9':
+        if (FXSYS_IsDecimalDigit(spSrcText[iText])) {
+          *wsValue += spSrcText[iText];
+          iText++;
+        }
+        iPattern++;
+        break;
+      default:
+        if (spTextFormat[iPattern] != spSrcText[iText]) {
+          *wsValue = wsSrcText;
+          return false;
+        }
+        iPattern++;
+        iText++;
+        break;
+    }
+  }
+  return iPattern == spTextFormat.size() && iText == spSrcText.size();
+}
+
+bool CFGAS_StringFormatter::ParseNum(const WideString& wsSrcNum,
+                                     WideString* wsValue) const {
+  wsValue->clear();
+  if (wsSrcNum.IsEmpty() || m_spPattern.empty())
+    return false;
+
+  size_t dot_index_f = m_spPattern.size();
+  uint32_t dwFormatStyle = 0;
+  WideString wsNumFormat;
+  LocaleIface* pLocale =
+      GetNumericFormat(&dot_index_f, &dwFormatStyle, &wsNumFormat);
+  if (!pLocale || wsNumFormat.IsEmpty())
+    return false;
+
+  int32_t iExponent = 0;
+  WideString wsDotSymbol = pLocale->GetDecimalSymbol();
+  WideString wsGroupSymbol = pLocale->GetGroupingSymbol();
+  int32_t iGroupLen = wsGroupSymbol.GetLength();
+  WideString wsMinus = pLocale->GetMinusSymbol();
+  int32_t iMinusLen = wsMinus.GetLength();
+
+  pdfium::span<const wchar_t> spSrcNum = wsSrcNum.span();
+  pdfium::span<const wchar_t> spNumFormat = wsNumFormat.span();
+
+  bool bHavePercentSymbol = false;
+  bool bNeg = false;
+  bool bReverseParse = false;
+  size_t dot_index = 0;
+
+  // If we're looking for a '.', 'V' or 'v' and the input string does not
+  // have a dot index for one of those, then we disable parsing the decimal.
+  if (!GetNumericDotIndex(wsSrcNum, wsDotSymbol, &dot_index) &&
+      (dwFormatStyle & FX_NUMSTYLE_DotVorv))
+    bReverseParse = true;
+
+  // This parse is broken into two parts based on the '.' in the number
+  // (or 'V' or 'v'). |dot_index_f| is the location of the dot in the format and
+  // |dot_index| is the location of the dot in the number.
+  //
+  // This first while() starts at the '.' and walks backwards to the start of
+  // the number. The second while() walks from the dot forwards to the end of
+  // the decimal.
+
+  size_t cc = dot_index - 1;
+  size_t ccf = dot_index_f - 1;
+  while (ccf < spNumFormat.size() && cc < spSrcNum.size()) {
+    switch (spNumFormat[ccf]) {
+      case '\'': {
+        WideString wsLiteral = GetLiteralTextReverse(spNumFormat, &ccf);
+        int32_t iLiteralLen = wsLiteral.GetLength();
+        cc -= iLiteralLen - 1;
+        if (cc >= spSrcNum.size() ||
+            wcsncmp(spSrcNum.data() + cc, wsLiteral.c_str(), iLiteralLen) !=
+                0) {
+          return false;
+        }
+        cc--;
+        ccf--;
+        break;
+      }
+      case '9':
+        if (!FXSYS_IsDecimalDigit(spSrcNum[cc]))
+          return false;
+
+        wsValue->InsertAtFront(spSrcNum[cc]);
+        cc--;
+        ccf--;
+        break;
+      case 'z':
+      case 'Z':
+        if (spNumFormat[ccf] == 'z' || spSrcNum[cc] != ' ') {
+          if (FXSYS_IsDecimalDigit(spSrcNum[cc])) {
+            wsValue->InsertAtFront(spSrcNum[cc]);
+            cc--;
+          }
+        } else {
+          cc--;
+        }
+        ccf--;
+        break;
+      case 'S':
+      case 's':
+        if (spSrcNum[cc] == '+' ||
+            (spNumFormat[ccf] == 'S' && spSrcNum[cc] == ' ')) {
+          cc--;
+        } else {
+          cc -= iMinusLen - 1;
+          if (cc >= spSrcNum.size() ||
+              wcsncmp(spSrcNum.data() + cc, wsMinus.c_str(), iMinusLen) != 0) {
+            return false;
+          }
+          cc--;
+          bNeg = true;
+        }
+        ccf--;
+        break;
+      case 'E': {
+        iExponent = 0;
+        bool bExpSign = false;
+        while (cc < spSrcNum.size()) {
+          if (spSrcNum[cc] == 'E' || spSrcNum[cc] == 'e')
+            break;
+          if (FXSYS_IsDecimalDigit(spSrcNum[cc])) {
+            if (iExponent > std::numeric_limits<int>::max() / 10)
+              return false;
+            iExponent = iExponent + FXSYS_DecimalCharToInt(spSrcNum[cc]) * 10;
+            cc--;
+            continue;
+          }
+          if (spSrcNum[cc] == '+') {
+            cc--;
+            continue;
+          }
+          if (cc - iMinusLen + 1 <= spSrcNum.size() &&
+              wcsncmp(spSrcNum.data() + (cc - iMinusLen + 1), wsMinus.c_str(),
+                      iMinusLen) == 0) {
+            bExpSign = true;
+            cc -= iMinusLen;
+            continue;
+          }
+
+          return false;
+        }
+        cc--;
+        iExponent = bExpSign ? -iExponent : iExponent;
+        ccf--;
+        break;
+      }
+      case '$': {
+        WideString wsSymbol = pLocale->GetCurrencySymbol();
+        int32_t iSymbolLen = wsSymbol.GetLength();
+        cc -= iSymbolLen - 1;
+        if (cc >= spSrcNum.size() ||
+            wcsncmp(spSrcNum.data() + cc, wsSymbol.c_str(), iSymbolLen) != 0) {
+          return false;
+        }
+        cc--;
+        ccf--;
+        break;
+      }
+      case 'r':
+      case 'R':
+        if (ccf - 1 < spNumFormat.size() &&
+            ((spNumFormat[ccf] == 'R' && spNumFormat[ccf - 1] == 'C') ||
+             (spNumFormat[ccf] == 'r' && spNumFormat[ccf - 1] == 'c'))) {
+          if (spNumFormat[ccf] == 'R' && spSrcNum[cc] == ' ') {
+            cc -= 2;
+          } else if (spSrcNum[cc] == 'R' && cc - 1 < spSrcNum.size() &&
+                     spSrcNum[cc - 1] == 'C') {
+            bNeg = true;
+            cc -= 2;
+          }
+          ccf -= 2;
+        } else {
+          ccf--;
+        }
+        break;
+      case 'b':
+      case 'B':
+        if (ccf - 1 < spNumFormat.size() &&
+            ((spNumFormat[ccf] == 'B' && spNumFormat[ccf - 1] == 'D') ||
+             (spNumFormat[ccf] == 'b' && spNumFormat[ccf - 1] == 'd'))) {
+          if (spNumFormat[ccf] == 'B' && spSrcNum[cc] == ' ') {
+            cc -= 2;
+          } else if (spSrcNum[cc] == 'B' && cc - 1 < spSrcNum.size() &&
+                     spSrcNum[cc - 1] == 'D') {
+            bNeg = true;
+            cc -= 2;
+          }
+          ccf -= 2;
+        } else {
+          ccf--;
+        }
+        break;
+      case '%': {
+        WideString wsSymbol = pLocale->GetPercentSymbol();
+        int32_t iSysmbolLen = wsSymbol.GetLength();
+        cc -= iSysmbolLen - 1;
+        if (cc >= spSrcNum.size() ||
+            wcsncmp(spSrcNum.data() + cc, wsSymbol.c_str(), iSysmbolLen) != 0) {
+          return false;
+        }
+        cc--;
+        ccf--;
+        bHavePercentSymbol = true;
+        break;
+      }
+      case '.':
+      case 'V':
+      case 'v':
+      case '8':
+        return false;
+      case ',': {
+        if (cc < spSrcNum.size()) {
+          cc -= iGroupLen - 1;
+          if (cc < spSrcNum.size() &&
+              wcsncmp(spSrcNum.data() + cc, wsGroupSymbol.c_str(), iGroupLen) ==
+                  0) {
+            cc--;
+          } else {
+            cc += iGroupLen - 1;
+          }
+        }
+        ccf--;
+        break;
+      }
+      case '(':
+      case ')':
+        if (spSrcNum[cc] == spNumFormat[ccf])
+          bNeg = true;
+        else if (spSrcNum[cc] != L' ')
+          return false;
+
+        cc--;
+        ccf--;
+        break;
+      default:
+        if (spNumFormat[ccf] != spSrcNum[cc])
+          return false;
+
+        cc--;
+        ccf--;
+    }
+  }
+  if (cc < spSrcNum.size()) {
+    if (spSrcNum[cc] == '-') {
+      bNeg = true;
+      cc--;
+    }
+    if (cc < spSrcNum.size())
+      return false;
+  }
+  if ((dwFormatStyle & FX_NUMSTYLE_DotVorv) && dot_index < spSrcNum.size())
+    *wsValue += '.';
+
+  if (!bReverseParse) {
+    cc = (dot_index == spSrcNum.size()) ? spSrcNum.size() : dot_index + 1;
+    for (ccf = dot_index_f + 1;
+         cc < spSrcNum.size() && ccf < spNumFormat.size(); ++ccf) {
+      switch (spNumFormat[ccf]) {
+        case '\'': {
+          WideString wsLiteral = GetLiteralText(spNumFormat, &ccf);
+          int32_t iLiteralLen = wsLiteral.GetLength();
+          if (cc + iLiteralLen > spSrcNum.size() ||
+              wcsncmp(spSrcNum.data() + cc, wsLiteral.c_str(), iLiteralLen) !=
+                  0) {
+            return false;
+          }
+          cc += iLiteralLen;
+          break;
+        }
+        case '9':
+          if (!FXSYS_IsDecimalDigit(spSrcNum[cc]))
+            return false;
+
+          *wsValue += spSrcNum[cc];
+          cc++;
+          break;
+        case 'z':
+        case 'Z':
+          if (spNumFormat[ccf] == 'z' || spSrcNum[cc] != ' ') {
+            if (FXSYS_IsDecimalDigit(spSrcNum[cc])) {
+              *wsValue += spSrcNum[cc];
+              cc++;
+            }
+          } else {
+            cc++;
+          }
+          break;
+        case 'S':
+        case 's':
+          if (spSrcNum[cc] == '+' ||
+              (spNumFormat[ccf] == 'S' && spSrcNum[cc] == ' ')) {
+            cc++;
+          } else {
+            if (cc + iMinusLen > spSrcNum.size() ||
+                wcsncmp(spSrcNum.data() + cc, wsMinus.c_str(), iMinusLen) !=
+                    0) {
+              return false;
+            }
+            bNeg = true;
+            cc += iMinusLen;
+          }
+          break;
+        case 'E': {
+          if (cc >= spSrcNum.size() ||
+              (spSrcNum[cc] != 'E' && spSrcNum[cc] != 'e')) {
+            return false;
+          }
+          iExponent = 0;
+          bool bExpSign = false;
+          cc++;
+          if (cc < spSrcNum.size()) {
+            if (spSrcNum[cc] == '+') {
+              cc++;
+            } else if (spSrcNum[cc] == '-') {
+              bExpSign = true;
+              cc++;
+            }
+          }
+          while (cc < spSrcNum.size()) {
+            if (!FXSYS_IsDecimalDigit(spSrcNum[cc]))
+              break;
+            int digit = FXSYS_DecimalCharToInt(spSrcNum[cc]);
+            if (iExponent > (std::numeric_limits<int>::max() - digit) / 10)
+              return false;
+            iExponent = iExponent * 10 + digit;
+            cc++;
+          }
+          iExponent = bExpSign ? -iExponent : iExponent;
+          break;
+        }
+        case '$': {
+          WideString wsSymbol = pLocale->GetCurrencySymbol();
+          int32_t iSymbolLen = wsSymbol.GetLength();
+          if (cc + iSymbolLen > spSrcNum.size() ||
+              wcsncmp(spSrcNum.data() + cc, wsSymbol.c_str(), iSymbolLen) !=
+                  0) {
+            return false;
+          }
+          cc += iSymbolLen;
+          break;
+        }
+        case 'c':
+        case 'C':
+          if (ccf + 1 < spNumFormat.size() &&
+              ((spNumFormat[ccf] == 'C' && spNumFormat[ccf + 1] == 'R') ||
+               (spNumFormat[ccf] == 'c' && spNumFormat[ccf + 1] == 'r'))) {
+            if (spNumFormat[ccf] == 'C' && spSrcNum[cc] == ' ') {
+              cc++;
+            } else if (spSrcNum[cc] == 'C' && cc + 1 < spSrcNum.size() &&
+                       spSrcNum[cc + 1] == 'R') {
+              bNeg = true;
+              cc += 2;
+            }
+            ccf++;
+          }
+          break;
+        case 'd':
+        case 'D':
+          if (ccf + 1 < spNumFormat.size() &&
+              ((spNumFormat[ccf] == 'D' && spNumFormat[ccf + 1] == 'B') ||
+               (spNumFormat[ccf] == 'd' && spNumFormat[ccf + 1] == 'b'))) {
+            if (spNumFormat[ccf] == 'D' && spSrcNum[cc] == ' ') {
+              cc++;
+            } else if (spSrcNum[cc] == 'D' && cc + 1 < spSrcNum.size() &&
+                       spSrcNum[cc + 1] == 'B') {
+              bNeg = true;
+              cc += 2;
+            }
+            ccf++;
+          }
+          break;
+        case '.':
+        case 'V':
+        case 'v':
+          return false;
+        case '%': {
+          WideString wsSymbol = pLocale->GetPercentSymbol();
+          int32_t iSysmbolLen = wsSymbol.GetLength();
+          if (cc + iSysmbolLen <= spSrcNum.size() &&
+              wcsncmp(spSrcNum.data() + cc, wsSymbol.c_str(), iSysmbolLen) ==
+                  0) {
+            cc += iSysmbolLen;
+          }
+          bHavePercentSymbol = true;
+        } break;
+        case '8': {
+          while (ccf + 1 < spNumFormat.size() && spNumFormat[ccf + 1] == '8')
+            ccf++;
+
+          while (cc < spSrcNum.size() && FXSYS_IsDecimalDigit(spSrcNum[cc])) {
+            *wsValue += spSrcNum[cc];
+            cc++;
+          }
+        } break;
+        case ',': {
+          if (cc + iGroupLen <= spSrcNum.size() &&
+              wcsncmp(spSrcNum.data() + cc, wsGroupSymbol.c_str(), iGroupLen) ==
+                  0) {
+            cc += iGroupLen;
+          }
+          break;
+        }
+        case '(':
+        case ')':
+          if (spSrcNum[cc] == spNumFormat[ccf])
+            bNeg = true;
+          else if (spSrcNum[cc] != L' ')
+            return false;
+
+          cc++;
+          break;
+        default:
+          if (spNumFormat[ccf] != spSrcNum[cc])
+            return false;
+
+          cc++;
+      }
+    }
+    if (cc != spSrcNum.size())
+      return false;
+  }
+  if (iExponent || bHavePercentSymbol) {
+    CFGAS_Decimal decimal = CFGAS_Decimal(wsValue->AsStringView());
+    if (iExponent) {
+      decimal = decimal *
+                CFGAS_Decimal(FXSYS_pow(10, static_cast<float>(iExponent)), 3);
+    }
+    if (bHavePercentSymbol)
+      decimal = decimal / CFGAS_Decimal(100);
+
+    *wsValue = decimal.ToWideString();
+  }
+  if (bNeg)
+    wsValue->InsertAtFront(L'-');
+
+  return true;
+}
+
+FX_DATETIMETYPE CFGAS_StringFormatter::GetDateTimeFormat(
+    LocaleIface** pLocale,
+    WideString* wsDatePattern,
+    WideString* wsTimePattern) const {
+  *pLocale = nullptr;
+  WideString wsTempPattern;
+  FX_LOCALECATEGORY eCategory = FX_LOCALECATEGORY_Unknown;
+  size_t ccf = 0;
+  int32_t iFindCategory = 0;
+  bool bBraceOpen = false;
+  while (ccf < m_spPattern.size()) {
+    if (m_spPattern[ccf] == '\'') {
+      int32_t iCurChar = ccf;
+      GetLiteralText(m_spPattern, &ccf);
+      wsTempPattern +=
+          WideStringView(m_spPattern.data() + iCurChar, ccf - iCurChar + 1);
+    } else if (!bBraceOpen && iFindCategory != 3 &&
+               !pdfium::ContainsValue(kConstChars, m_spPattern[ccf])) {
+      WideString wsCategory(m_spPattern[ccf]);
+      ccf++;
+      while (ccf < m_spPattern.size() && m_spPattern[ccf] != '{' &&
+             m_spPattern[ccf] != '.' && m_spPattern[ccf] != '(') {
+        if (m_spPattern[ccf] == 'T') {
+          *wsDatePattern = m_wsPattern.First(ccf);
+          *wsTimePattern = m_wsPattern.Last(m_wsPattern.GetLength() - ccf);
+          wsTimePattern->SetAt(0, ' ');
+          if (!*pLocale)
+            *pLocale = m_pLocaleMgr->GetDefLocale();
+
+          return FX_DATETIMETYPE_DateTime;
+        }
+        wsCategory += m_spPattern[ccf];
+        ccf++;
+      }
+      if (!(iFindCategory & 1) && wsCategory.EqualsASCII("date")) {
+        iFindCategory |= 1;
+        eCategory = FX_LOCALECATEGORY_Date;
+        if (iFindCategory & 2)
+          iFindCategory = 4;
+      } else if (!(iFindCategory & 2) && wsCategory.EqualsASCII("time")) {
+        iFindCategory |= 2;
+        eCategory = FX_LOCALECATEGORY_Time;
+      } else if (wsCategory.EqualsASCII("datetime")) {
+        iFindCategory = 3;
+        eCategory = FX_LOCALECATEGORY_DateTime;
+      } else {
+        continue;
+      }
+      while (ccf < m_spPattern.size()) {
+        if (m_spPattern[ccf] == '{') {
+          bBraceOpen = true;
+          break;
+        }
+        if (m_spPattern[ccf] == '(') {
+          ccf++;
+          WideString wsLCID;
+          while (ccf < m_spPattern.size() && m_spPattern[ccf] != ')')
+            wsLCID += m_spPattern[ccf++];
+
+          *pLocale = m_pLocaleMgr->GetLocaleByName(wsLCID);
+        } else if (m_spPattern[ccf] == '.') {
+          WideString wsSubCategory;
+          ccf++;
+          while (ccf < m_spPattern.size() && m_spPattern[ccf] != '(' &&
+                 m_spPattern[ccf] != '{')
+            wsSubCategory += m_spPattern[ccf++];
+
+          uint32_t dwSubHash =
+              FX_HashCode_GetW(wsSubCategory.AsStringView(), false);
+          FX_LOCALEDATETIMESUBCATEGORY eSubCategory =
+              FX_LOCALEDATETIMESUBCATEGORY_Medium;
+          for (const auto& data : g_FXLocaleDateTimeSubCatData) {
+            if (data.uHash == dwSubHash) {
+              eSubCategory = data.eSubCategory;
+              break;
+            }
+          }
+          if (!*pLocale)
+            *pLocale = m_pLocaleMgr->GetDefLocale();
+          ASSERT(*pLocale);
+
+          switch (eCategory) {
+            case FX_LOCALECATEGORY_Date:
+              *wsDatePattern =
+                  wsTempPattern + (*pLocale)->GetDatePattern(eSubCategory);
+              break;
+            case FX_LOCALECATEGORY_Time:
+              *wsTimePattern =
+                  wsTempPattern + (*pLocale)->GetTimePattern(eSubCategory);
+              break;
+            case FX_LOCALECATEGORY_DateTime:
+              *wsDatePattern =
+                  wsTempPattern + (*pLocale)->GetDatePattern(eSubCategory);
+              *wsTimePattern = (*pLocale)->GetTimePattern(eSubCategory);
+              break;
+            default:
+              break;
+          }
+          wsTempPattern.clear();
+          continue;
+        }
+        ccf++;
+      }
+    } else if (m_spPattern[ccf] == '}') {
+      bBraceOpen = false;
+      if (!wsTempPattern.IsEmpty()) {
+        if (eCategory == FX_LOCALECATEGORY_Time)
+          *wsTimePattern = std::move(wsTempPattern);
+        else if (eCategory == FX_LOCALECATEGORY_Date)
+          *wsDatePattern = std::move(wsTempPattern);
+        else
+          wsTempPattern.clear();
+      }
+    } else {
+      wsTempPattern += m_spPattern[ccf];
+    }
+    ccf++;
+  }
+
+  if (!wsTempPattern.IsEmpty()) {
+    if (eCategory == FX_LOCALECATEGORY_Date)
+      *wsDatePattern += wsTempPattern;
+    else
+      *wsTimePattern += wsTempPattern;
+  }
+  if (!*pLocale)
+    *pLocale = m_pLocaleMgr->GetDefLocale();
+  if (!iFindCategory) {
+    wsTimePattern->clear();
+    *wsDatePattern = m_wsPattern;
+  }
+  return (FX_DATETIMETYPE)iFindCategory;
+}
+
+bool CFGAS_StringFormatter::ParseDateTime(const WideString& wsSrcDateTime,
+                                          FX_DATETIMETYPE eDateTimeType,
+                                          CFX_DateTime* dtValue) const {
+  dtValue->Reset();
+  if (wsSrcDateTime.IsEmpty() || m_spPattern.empty())
+    return false;
+
+  LocaleIface* pLocale = nullptr;
+  WideString wsDatePattern;
+  WideString wsTimePattern;
+  FX_DATETIMETYPE eCategory =
+      GetDateTimeFormat(&pLocale, &wsDatePattern, &wsTimePattern);
+  if (!pLocale)
+    return false;
+
+  if (eCategory == FX_DATETIMETYPE_Unknown)
+    eCategory = eDateTimeType;
+
+  size_t iStart = 0;
+  switch (eCategory) {
+    case FX_DATETIMETYPE_Date:
+      return ParseLocaleDate(wsSrcDateTime, wsDatePattern, pLocale, dtValue,
+                             &iStart);
+    case FX_DATETIMETYPE_Time:
+      return ParseLocaleTime(wsSrcDateTime, wsTimePattern, pLocale, dtValue,
+                             &iStart);
+    case FX_DATETIMETYPE_DateTime:
+      return ParseLocaleDate(wsSrcDateTime, wsTimePattern, pLocale, dtValue,
+                             &iStart) &&
+             ParseLocaleTime(wsSrcDateTime, wsDatePattern, pLocale, dtValue,
+                             &iStart);
+    case FX_DATETIMETYPE_TimeDate:
+      return ParseLocaleTime(wsSrcDateTime, wsTimePattern, pLocale, dtValue,
+                             &iStart) &&
+             ParseLocaleDate(wsSrcDateTime, wsDatePattern, pLocale, dtValue,
+                             &iStart);
+    case FX_DATETIMETYPE_Unknown:
+    default:
+      return false;
+  }
+}
+
+bool CFGAS_StringFormatter::ParseZero(const WideString& wsSrcText) const {
+  WideString wsTextFormat = GetTextFormat(L"zero");
+  pdfium::span<const wchar_t> spSrcText = wsSrcText.span();
+  pdfium::span<const wchar_t> spTextFormat = wsTextFormat.span();
+
+  size_t iText = 0;
+  size_t iPattern = 0;
+  while (iPattern < spTextFormat.size() && iText < spSrcText.size()) {
+    if (spTextFormat[iPattern] == '\'') {
+      WideString wsLiteral = GetLiteralText(spTextFormat, &iPattern);
+      int32_t iLiteralLen = wsLiteral.GetLength();
+      if (iText + iLiteralLen > spSrcText.size() ||
+          wcsncmp(spSrcText.data() + iText, wsLiteral.c_str(), iLiteralLen)) {
+        return false;
+      }
+      iText += iLiteralLen;
+      iPattern++;
+      continue;
+    }
+    if (spTextFormat[iPattern] != spSrcText[iText])
+      return false;
+
+    iText++;
+    iPattern++;
+  }
+  return iPattern == spTextFormat.size() && iText == spSrcText.size();
+}
+
+bool CFGAS_StringFormatter::ParseNull(const WideString& wsSrcText) const {
+  WideString wsTextFormat = GetTextFormat(L"null");
+  pdfium::span<const wchar_t> spSrcText = wsSrcText.span();
+  pdfium::span<const wchar_t> spTextFormat = wsTextFormat.span();
+
+  size_t iText = 0;
+  size_t iPattern = 0;
+  while (iPattern < spTextFormat.size() && iText < spSrcText.size()) {
+    if (spTextFormat[iPattern] == '\'') {
+      WideString wsLiteral = GetLiteralText(spTextFormat, &iPattern);
+      int32_t iLiteralLen = wsLiteral.GetLength();
+      if (iText + iLiteralLen > spSrcText.size() ||
+          wcsncmp(spSrcText.data() + iText, wsLiteral.c_str(), iLiteralLen)) {
+        return false;
+      }
+      iText += iLiteralLen;
+      iPattern++;
+      continue;
+    }
+    if (spTextFormat[iPattern] != spSrcText[iText])
+      return false;
+
+    iText++;
+    iPattern++;
+  }
+  return iPattern == spTextFormat.size() && iText == spSrcText.size();
+}
+
+bool CFGAS_StringFormatter::FormatText(const WideString& wsSrcText,
+                                       WideString* wsOutput) const {
+  if (wsSrcText.IsEmpty() || m_spPattern.empty())
+    return false;
+
+  WideString wsTextFormat = GetTextFormat(L"text");
+  pdfium::span<const wchar_t> spSrcText = wsSrcText.span();
+  pdfium::span<const wchar_t> spTextFormat = wsTextFormat.span();
+
+  size_t iText = 0;
+  size_t iPattern = 0;
+  while (iPattern < spTextFormat.size()) {
+    switch (spTextFormat[iPattern]) {
+      case '\'': {
+        *wsOutput += GetLiteralText(spTextFormat, &iPattern);
+        iPattern++;
+        break;
+      }
+      case 'A':
+        if (iText >= spSrcText.size() || !FXSYS_iswalpha(spSrcText[iText]))
+          return false;
+
+        *wsOutput += spSrcText[iText++];
+        iPattern++;
+        break;
+      case 'X':
+        if (iText >= spSrcText.size())
+          return false;
+
+        *wsOutput += spSrcText[iText++];
+        iPattern++;
+        break;
+      case 'O':
+      case '0':
+        if (iText >= spSrcText.size() ||
+            (!FXSYS_IsDecimalDigit(spSrcText[iText]) &&
+             !FXSYS_iswalpha(spSrcText[iText]))) {
+          return false;
+        }
+        *wsOutput += spSrcText[iText++];
+        iPattern++;
+        break;
+      case '9':
+        if (iText >= spSrcText.size() ||
+            !FXSYS_IsDecimalDigit(spSrcText[iText]))
+          return false;
+
+        *wsOutput += spSrcText[iText++];
+        iPattern++;
+        break;
+      default:
+        *wsOutput += spTextFormat[iPattern++];
+        break;
+    }
+  }
+  return iText == spSrcText.size();
+}
+
+bool CFGAS_StringFormatter::FormatNum(const WideString& wsInputNum,
+                                      WideString* wsOutput) const {
+  if (wsInputNum.IsEmpty() || m_spPattern.empty())
+    return false;
+
+  size_t dot_index_f = m_spPattern.size();
+  uint32_t dwNumStyle = 0;
+  WideString wsNumFormat;
+  LocaleIface* pLocale =
+      GetNumericFormat(&dot_index_f, &dwNumStyle, &wsNumFormat);
+  if (!pLocale || wsNumFormat.IsEmpty())
+    return false;
+
+  pdfium::span<const wchar_t> spNumFormat = wsNumFormat.span();
+  WideString wsSrcNum = wsInputNum;
+  wsSrcNum.TrimLeft('0');
+  if (wsSrcNum.IsEmpty() || wsSrcNum[0] == '.')
+    wsSrcNum.InsertAtFront('0');
+
+  CFGAS_Decimal decimal = CFGAS_Decimal(wsSrcNum.AsStringView());
+  if (dwNumStyle & FX_NUMSTYLE_Percent) {
+    decimal = decimal * CFGAS_Decimal(100);
+    wsSrcNum = decimal.ToWideString();
+  }
+
+  int32_t exponent = 0;
+  if (dwNumStyle & FX_NUMSTYLE_Exponent) {
+    int fixed_count = 0;
+    for (size_t ccf = 0; ccf < dot_index_f; ++ccf) {
+      switch (spNumFormat[ccf]) {
+        case '\'':
+          GetLiteralText(spNumFormat, &ccf);
+          break;
+        case '9':
+        case 'z':
+        case 'Z':
+          fixed_count++;
+          break;
+      }
+    }
+
+    FX_SAFE_UINT32 threshold = 1;
+    while (fixed_count > 1) {
+      threshold *= 10;
+      fixed_count--;
+    }
+    if (!threshold.IsValid())
+      return false;
+
+    bool bAdjusted = false;
+    while (decimal.IsNotZero() &&
+           fabs(decimal.ToDouble()) < threshold.ValueOrDie()) {
+      decimal = decimal * CFGAS_Decimal(10);
+      --exponent;
+      bAdjusted = true;
+    }
+    if (!bAdjusted) {
+      threshold *= 10;
+      if (!threshold.IsValid())
+        return false;
+
+      while (decimal.IsNotZero() &&
+             fabs(decimal.ToDouble()) > threshold.ValueOrDie()) {
+        decimal = decimal / CFGAS_Decimal(10);
+        ++exponent;
+      }
+    }
+  }
+
+  bool bTrimTailZeros = false;
+  int32_t iTreading =
+      GetNumTrailingLimit(wsNumFormat, dot_index_f, &bTrimTailZeros);
+  int32_t scale = decimal.GetScale();
+  if (iTreading < scale) {
+    decimal.SetScale(iTreading);
+    wsSrcNum = decimal.ToWideString();
+  }
+  if (bTrimTailZeros && scale > 0 && iTreading > 0) {
+    wsSrcNum.TrimRight(L"0");
+    wsSrcNum.TrimRight(L".");
+  }
+
+  WideString wsGroupSymbol = pLocale->GetGroupingSymbol();
+  bool bNeg = false;
+  if (wsSrcNum[0] == '-') {
+    bNeg = true;
+    wsSrcNum.Delete(0, 1);
+  }
+
+  bool bAddNeg = false;
+  pdfium::span<const wchar_t> spSrcNum = wsSrcNum.span();
+  auto dot_index = wsSrcNum.Find('.');
+  if (!dot_index.has_value())
+    dot_index = spSrcNum.size();
+
+  size_t cc = dot_index.value() - 1;
+  for (size_t ccf = dot_index_f - 1; ccf < spNumFormat.size(); --ccf) {
+    switch (spNumFormat[ccf]) {
+      case '9':
+        if (cc < spSrcNum.size()) {
+          if (!FXSYS_IsDecimalDigit(spSrcNum[cc]))
+            return false;
+          wsOutput->InsertAtFront(spSrcNum[cc]);
+          cc--;
+        } else {
+          wsOutput->InsertAtFront(L'0');
+        }
+        break;
+      case 'z':
+        if (cc < spSrcNum.size()) {
+          if (!FXSYS_IsDecimalDigit(spSrcNum[cc]))
+            return false;
+          if (spSrcNum[0] != '0')
+            wsOutput->InsertAtFront(spSrcNum[cc]);
+          cc--;
+        }
+        break;
+      case 'Z':
+        if (cc < spSrcNum.size()) {
+          if (!FXSYS_IsDecimalDigit(spSrcNum[cc]))
+            return false;
+          wsOutput->InsertAtFront(spSrcNum[0] == '0' ? L' ' : spSrcNum[cc]);
+          cc--;
+        } else {
+          wsOutput->InsertAtFront(L' ');
+        }
+        break;
+      case 'S':
+        if (bNeg) {
+          *wsOutput = pLocale->GetMinusSymbol() + *wsOutput;
+          bAddNeg = true;
+        } else {
+          wsOutput->InsertAtFront(L' ');
+        }
+        break;
+      case 's':
+        if (bNeg) {
+          *wsOutput = pLocale->GetMinusSymbol() + *wsOutput;
+          bAddNeg = true;
+        }
+        break;
+      case 'E':
+        *wsOutput = WideString::Format(L"E%+d", exponent) + *wsOutput;
+        break;
+      case '$':
+        *wsOutput = pLocale->GetCurrencySymbol() + *wsOutput;
+        break;
+      case 'r':
+        if (ccf - 1 < spNumFormat.size() && spNumFormat[ccf - 1] == 'c') {
+          if (bNeg)
+            *wsOutput = L"CR" + *wsOutput;
+          ccf--;
+          bAddNeg = true;
+        } else {
+          wsOutput->InsertAtFront('r');
+        }
+        break;
+      case 'R':
+        if (ccf - 1 < spNumFormat.size() && spNumFormat[ccf - 1] == 'C') {
+          *wsOutput = bNeg ? L"CR" : L"  " + *wsOutput;
+          ccf--;
+          bAddNeg = true;
+        } else {
+          wsOutput->InsertAtFront('R');
+        }
+        break;
+      case 'b':
+        if (ccf - 1 < spNumFormat.size() && spNumFormat[ccf - 1] == 'd') {
+          if (bNeg)
+            *wsOutput = L"db" + *wsOutput;
+          ccf--;
+          bAddNeg = true;
+        } else {
+          wsOutput->InsertAtFront('b');
+        }
+        break;
+      case 'B':
+        if (ccf - 1 < spNumFormat.size() && spNumFormat[ccf - 1] == 'D') {
+          *wsOutput = bNeg ? L"DB" : L"  " + *wsOutput;
+          ccf--;
+          bAddNeg = true;
+        } else {
+          wsOutput->InsertAtFront('B');
+        }
+        break;
+      case '%':
+        *wsOutput = pLocale->GetPercentSymbol() + *wsOutput;
+        break;
+      case ',':
+        if (cc < spSrcNum.size())
+          *wsOutput = wsGroupSymbol + *wsOutput;
+        break;
+      case '(':
+        wsOutput->InsertAtFront(bNeg ? L'(' : L' ');
+        bAddNeg = true;
+        break;
+      case ')':
+        wsOutput->InsertAtFront(bNeg ? L')' : L' ');
+        break;
+      case '\'':
+        *wsOutput = GetLiteralTextReverse(spNumFormat, &ccf) + *wsOutput;
+        break;
+      default:
+        wsOutput->InsertAtFront(spNumFormat[ccf]);
+        break;
+    }
+  }
+
+  if (cc < spSrcNum.size()) {
+    size_t nPos = dot_index.value() % 3;
+    wsOutput->clear();
+    for (size_t i = 0; i < dot_index.value(); i++) {
+      if (i % 3 == nPos && i != 0)
+        *wsOutput += wsGroupSymbol;
+      *wsOutput += wsSrcNum[i];
+    }
+    if (dot_index.value() < spSrcNum.size()) {
+      *wsOutput += pLocale->GetDecimalSymbol();
+      *wsOutput += wsSrcNum.Last(spSrcNum.size() - dot_index.value() - 1);
+    }
+    if (bNeg)
+      *wsOutput = pLocale->GetMinusSymbol() + *wsOutput;
+    return true;
+  }
+  if (dot_index_f == wsNumFormat.GetLength()) {
+    if (!bAddNeg && bNeg)
+      *wsOutput = pLocale->GetMinusSymbol() + *wsOutput;
+    return true;
+  }
+
+  WideString wsDotSymbol = pLocale->GetDecimalSymbol();
+  if (spNumFormat[dot_index_f] == 'V') {
+    *wsOutput += wsDotSymbol;
+  } else if (spNumFormat[dot_index_f] == '.') {
+    if (dot_index.value() < spSrcNum.size()) {
+      *wsOutput += wsDotSymbol;
+    } else if (dot_index_f + 1 < spNumFormat.size() &&
+               (spNumFormat[dot_index_f + 1] == '9' ||
+                spNumFormat[dot_index_f + 1] == 'Z')) {
+      *wsOutput += wsDotSymbol;
+    }
+  }
+
+  cc = dot_index.value() + 1;
+  for (size_t ccf = dot_index_f + 1; ccf < spNumFormat.size(); ++ccf) {
+    switch (spNumFormat[ccf]) {
+      case '\'':
+        *wsOutput += GetLiteralText(spNumFormat, &ccf);
+        break;
+      case '9':
+        if (cc < spSrcNum.size()) {
+          if (!FXSYS_IsDecimalDigit(spSrcNum[cc]))
+            return false;
+          *wsOutput += spSrcNum[cc];
+          cc++;
+        } else {
+          *wsOutput += L'0';
+        }
+        break;
+      case 'z':
+        if (cc < spSrcNum.size()) {
+          if (!FXSYS_IsDecimalDigit(spSrcNum[cc]))
+            return false;
+          *wsOutput += spSrcNum[cc];
+          cc++;
+        }
+        break;
+      case 'Z':
+        if (cc < spSrcNum.size()) {
+          if (!FXSYS_IsDecimalDigit(spSrcNum[cc]))
+            return false;
+          *wsOutput += spSrcNum[cc];
+          cc++;
+        } else {
+          *wsOutput += L'0';
+        }
+        break;
+      case 'E': {
+        *wsOutput += WideString::Format(L"E%+d", exponent);
+        break;
+      }
+      case '$':
+        *wsOutput += pLocale->GetCurrencySymbol();
+        break;
+      case 'c':
+        if (ccf + 1 < spNumFormat.size() && spNumFormat[ccf + 1] == 'r') {
+          if (bNeg)
+            *wsOutput += L"CR";
+          ccf++;
+          bAddNeg = true;
+        }
+        break;
+      case 'C':
+        if (ccf + 1 < spNumFormat.size() && spNumFormat[ccf + 1] == 'R') {
+          *wsOutput += bNeg ? L"CR" : L"  ";
+          ccf++;
+          bAddNeg = true;
+        }
+        break;
+      case 'd':
+        if (ccf + 1 < spNumFormat.size() && spNumFormat[ccf + 1] == 'b') {
+          if (bNeg)
+            *wsOutput += L"db";
+          ccf++;
+          bAddNeg = true;
+        }
+        break;
+      case 'D':
+        if (ccf + 1 < spNumFormat.size() && spNumFormat[ccf + 1] == 'B') {
+          *wsOutput += bNeg ? L"DB" : L"  ";
+          ccf++;
+          bAddNeg = true;
+        }
+        break;
+      case '%':
+        *wsOutput += pLocale->GetPercentSymbol();
+        break;
+      case '8':
+        while (ccf + 1 < spNumFormat.size() && spNumFormat[ccf + 1] == '8')
+          ccf++;
+        while (cc < spSrcNum.size() && FXSYS_IsDecimalDigit(spSrcNum[cc])) {
+          *wsOutput += spSrcNum[cc];
+          cc++;
+        }
+        break;
+      case ',':
+        *wsOutput += wsGroupSymbol;
+        break;
+      case '(':
+        *wsOutput += bNeg ? '(' : ' ';
+        bAddNeg = true;
+        break;
+      case ')':
+        *wsOutput += bNeg ? ')' : ' ';
+        break;
+      default:
+        break;
+    }
+  }
+  if (!bAddNeg && bNeg)
+    *wsOutput = pLocale->GetMinusSymbol() + *wsOutput;
+
+  return true;
+}
+
+bool CFGAS_StringFormatter::FormatDateTime(const WideString& wsSrcDateTime,
+                                           FX_DATETIMETYPE eDateTimeType,
+                                           WideString* wsOutput) const {
+  if (wsSrcDateTime.IsEmpty() || m_spPattern.empty())
+    return false;
+
+  WideString wsDatePattern;
+  WideString wsTimePattern;
+  LocaleIface* pLocale = nullptr;
+  FX_DATETIMETYPE eCategory =
+      GetDateTimeFormat(&pLocale, &wsDatePattern, &wsTimePattern);
+  if (!pLocale)
+    return false;
+
+  if (eCategory == FX_DATETIMETYPE_Unknown) {
+    if (eDateTimeType == FX_DATETIMETYPE_Time) {
+      wsTimePattern = std::move(wsDatePattern);
+      wsDatePattern = WideString();
+    }
+    eCategory = eDateTimeType;
+    if (eCategory == FX_DATETIMETYPE_Unknown)
+      return false;
+  }
+
+  CFX_DateTime dt;
+  auto iT = wsSrcDateTime.Find(L"T");
+  if (!iT.has_value()) {
+    if (eCategory == FX_DATETIMETYPE_Date &&
+        FX_DateFromCanonical(wsSrcDateTime.span(), &dt)) {
+      *wsOutput = FormatDateTimeInternal(dt, wsDatePattern, wsTimePattern, true,
+                                         pLocale);
+      return true;
+    }
+    if (eCategory == FX_DATETIMETYPE_Time &&
+        FX_TimeFromCanonical(pLocale, wsSrcDateTime.span(), &dt)) {
+      *wsOutput = FormatDateTimeInternal(dt, wsDatePattern, wsTimePattern, true,
+                                         pLocale);
+      return true;
+    }
+  } else {
+    pdfium::span<const wchar_t> wsSrcDate =
+        wsSrcDateTime.span().first(iT.value());
+    pdfium::span<const wchar_t> wsSrcTime =
+        wsSrcDateTime.span().subspan(iT.value() + 1);
+    if (wsSrcDate.empty() || wsSrcTime.empty())
+      return false;
+
+    if (FX_DateFromCanonical(wsSrcDate, &dt) &&
+        FX_TimeFromCanonical(pLocale, wsSrcTime, &dt)) {
+      *wsOutput = FormatDateTimeInternal(dt, wsDatePattern, wsTimePattern,
+                                         eCategory != FX_DATETIMETYPE_TimeDate,
+                                         pLocale);
+      return true;
+    }
+  }
+  return false;
+}
+
+bool CFGAS_StringFormatter::FormatZero(WideString* wsOutput) const {
+  if (m_spPattern.empty())
+    return false;
+
+  WideString wsTextFormat = GetTextFormat(L"zero");
+  pdfium::span<const wchar_t> spTextFormat = wsTextFormat.span();
+  for (size_t iPattern = 0; iPattern < spTextFormat.size(); ++iPattern) {
+    if (spTextFormat[iPattern] == '\'') {
+      *wsOutput += GetLiteralText(spTextFormat, &iPattern);
+      continue;
+    }
+    *wsOutput += spTextFormat[iPattern];
+  }
+  return true;
+}
+
+bool CFGAS_StringFormatter::FormatNull(WideString* wsOutput) const {
+  if (m_spPattern.empty())
+    return false;
+
+  WideString wsTextFormat = GetTextFormat(L"null");
+  pdfium::span<const wchar_t> spTextFormat = wsTextFormat.span();
+  for (size_t iPattern = 0; iPattern < spTextFormat.size(); ++iPattern) {
+    if (spTextFormat[iPattern] == '\'') {
+      *wsOutput += GetLiteralText(spTextFormat, &iPattern);
+      continue;
+    }
+    *wsOutput += spTextFormat[iPattern];
+  }
+  return true;
+}
diff --git a/xfa/fgas/crt/cfgas_stringformatter.h b/xfa/fgas/crt/cfgas_stringformatter.h
new file mode 100644
index 0000000..afdeeb9
--- /dev/null
+++ b/xfa/fgas/crt/cfgas_stringformatter.h
@@ -0,0 +1,67 @@
+// 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_FGAS_CRT_CFGAS_STRINGFORMATTER_H_
+#define XFA_FGAS_CRT_CFGAS_STRINGFORMATTER_H_
+
+#include <vector>
+
+#include "core/fxcrt/unowned_ptr.h"
+#include "third_party/base/span.h"
+#include "xfa/fgas/crt/locale_iface.h"
+#include "xfa/fgas/crt/locale_mgr_iface.h"
+
+bool FX_DateFromCanonical(pdfium::span<const wchar_t> wsTime,
+                          CFX_DateTime* datetime);
+bool FX_TimeFromCanonical(const LocaleIface* pLocale,
+                          pdfium::span<const wchar_t> wsTime,
+                          CFX_DateTime* datetime);
+
+class CFGAS_StringFormatter {
+ public:
+  CFGAS_StringFormatter(LocaleMgrIface* pLocaleMgr,
+                        const WideString& wsPattern);
+  ~CFGAS_StringFormatter();
+
+  static std::vector<WideString> SplitOnBars(const WideString& wsFormatString);
+
+  FX_LOCALECATEGORY GetCategory() const;
+
+  bool ParseText(const WideString& wsSrcText,
+                 WideString* wsValue) const;
+  bool ParseNum(const WideString& wsSrcNum,
+                WideString* wsValue) const;
+  bool ParseDateTime(const WideString& wsSrcDateTime,
+                     FX_DATETIMETYPE eDateTimeType,
+                     CFX_DateTime* dtValue) const;
+  bool ParseZero(const WideString& wsSrcText) const;
+  bool ParseNull(const WideString& wsSrcText) const;
+
+  bool FormatText(const WideString& wsSrcText,
+                  WideString* wsOutput) const;
+  bool FormatNum(const WideString& wsSrcNum,
+                 WideString* wsOutput) const;
+  bool FormatDateTime(const WideString& wsSrcDateTime,
+                      FX_DATETIMETYPE eDateTimeType,
+                      WideString* wsOutput) const;
+  bool FormatZero(WideString* wsOutput) const;
+  bool FormatNull(WideString* wsOutput) const;
+
+ private:
+  WideString GetTextFormat(WideStringView wsCategory) const;
+  LocaleIface* GetNumericFormat(size_t* iDotIndex,
+                                uint32_t* dwStyle,
+                                WideString* wsPurgePattern) const;
+  FX_DATETIMETYPE GetDateTimeFormat(LocaleIface** pLocale,
+                                    WideString* wsDatePattern,
+                                    WideString* wsTimePattern) const;
+
+  UnownedPtr<LocaleMgrIface> const m_pLocaleMgr;
+  const WideString m_wsPattern;                   // keep pattern string alive.
+  const pdfium::span<const wchar_t> m_spPattern;  // span into |m_wsPattern|.
+};
+
+#endif  // XFA_FGAS_CRT_CFGAS_STRINGFORMATTER_H_
diff --git a/xfa/fgas/crt/cfgas_formatstring_unittest.cpp b/xfa/fgas/crt/cfgas_stringformatter_unittest.cpp
similarity index 75%
rename from xfa/fgas/crt/cfgas_formatstring_unittest.cpp
rename to xfa/fgas/crt/cfgas_stringformatter_unittest.cpp
index 51c0010..8a9e60c 100644
--- a/xfa/fgas/crt/cfgas_formatstring_unittest.cpp
+++ b/xfa/fgas/crt/cfgas_stringformatter_unittest.cpp
@@ -4,27 +4,27 @@
 
 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
 
-#include "xfa/fgas/crt/cfgas_formatstring.h"
+#include "xfa/fgas/crt/cfgas_stringformatter.h"
 
 #include <time.h>
 
 #include <memory>
 
-#include "core/fpdfapi/cpdf_modulemgr.h"
+#include "build/build_config.h"
+#include "core/fpdfapi/page/cpdf_pagemodule.h"
 #include "testing/fx_string_testhelpers.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "testing/test_support.h"
 #include "third_party/base/ptr_util.h"
 #include "xfa/fxfa/parser/cxfa_localemgr.h"
 
-class CFGAS_FormatStringTest : public testing::Test {
+class CFGAS_StringFormatterTest : public testing::Test {
  public:
-  CFGAS_FormatStringTest() {
+  CFGAS_StringFormatterTest() {
     SetTZ("UTC");
-    CPDF_ModuleMgr::Get()->Init();
+    CPDF_PageModule::Create();
   }
 
-  ~CFGAS_FormatStringTest() override { CPDF_ModuleMgr::Get()->Destroy(); }
+  ~CFGAS_StringFormatterTest() override { CPDF_PageModule::Destroy(); }
 
   void TearDown() override {
     fmt_.reset();
@@ -32,7 +32,7 @@
   }
 
   void SetTZ(const char* tz) {
-#if _FX_PLATFORM_ == _FX_PLATFORM_WINDOWS_
+#if defined(OS_WIN)
     _putenv_s("TZ", tz);
     _tzset();
 #else
@@ -43,20 +43,22 @@
 
   // Note, this re-creates the fmt on each call. If you need to multiple
   // times store it locally.
-  CFGAS_FormatString* fmt(const WideString& locale) {
+  CFGAS_StringFormatter* fmt(const WideString& locale,
+                             const WideString& pattern) {
+    fmt_.reset();  // Can't outlive |mgr_|.
     mgr_ = pdfium::MakeUnique<CXFA_LocaleMgr>(nullptr, locale);
-    fmt_ = pdfium::MakeUnique<CFGAS_FormatString>(mgr_.get());
+    fmt_ = pdfium::MakeUnique<CFGAS_StringFormatter>(mgr_.get(), pattern);
     return fmt_.get();
   }
 
  protected:
   std::unique_ptr<CXFA_LocaleMgr> mgr_;
-  std::unique_ptr<CFGAS_FormatString> fmt_;
+  std::unique_ptr<CFGAS_StringFormatter> fmt_;
 };
 
 // TODO(dsinclair): Looks like the formatter/parser does not handle the various
 // 'g' flags.
-TEST_F(CFGAS_FormatStringTest, DateFormat) {
+TEST_F(CFGAS_StringFormatterTest, DateFormat) {
   struct {
     const wchar_t* locale;
     const wchar_t* input;
@@ -113,14 +115,14 @@
 
   for (size_t i = 0; i < FX_ArraySize(tests); ++i) {
     WideString result;
-    EXPECT_TRUE(fmt(tests[i].locale)
-                    ->FormatDateTime(tests[i].input, tests[i].pattern,
-                                     FX_DATETIMETYPE_Date, &result));
+    EXPECT_TRUE(
+        fmt(tests[i].locale, tests[i].pattern)
+            ->FormatDateTime(tests[i].input, FX_DATETIMETYPE_Date, &result));
     EXPECT_STREQ(tests[i].output, result.c_str()) << " TEST: " << i;
   }
 }
 
-TEST_F(CFGAS_FormatStringTest, TimeFormat) {
+TEST_F(CFGAS_StringFormatterTest, TimeFormat) {
   struct {
     const wchar_t* locale;
     const wchar_t* input;
@@ -162,16 +164,46 @@
 
   for (size_t i = 0; i < FX_ArraySize(tests); ++i) {
     WideString result;
-    EXPECT_TRUE(fmt(tests[i].locale)
-                    ->FormatDateTime(tests[i].input, tests[i].pattern,
-                                     FX_DATETIMETYPE_Time, &result));
+    EXPECT_TRUE(
+        fmt(tests[i].locale, tests[i].pattern)
+            ->FormatDateTime(tests[i].input, FX_DATETIMETYPE_Time, &result));
     EXPECT_STREQ(tests[i].output, result.c_str()) << " TEST: " << i;
   }
 
   SetTZ("UTC");
 }
 
-TEST_F(CFGAS_FormatStringTest, DateTimeFormat) {
+TEST_F(CFGAS_StringFormatterTest, DateTimeFormat) {
+  struct {
+    const wchar_t* locale;
+    const wchar_t* input;
+    const wchar_t* pattern;
+    const wchar_t* output;
+  } tests[] = {
+      {L"en", L"1999-07-16T10:30Z",
+       L"'At' time{HH:MM Z} 'on' date{MMM DD, YYYY}",
+       L"At 10:30 GMT on Jul 16, 1999"},
+      {L"en", L"1999-07-16T10:30", L"'At' time{HH:MM} 'on' date{MMM DD, YYYY}",
+       L"At 10:30 on Jul 16, 1999"},
+      {L"en", L"1999-07-16T10:30Z",
+       L"time{'At' HH:MM Z} date{'on' MMM DD, YYYY}",
+       L"At 10:30 GMT on Jul 16, 1999"},
+      {L"en", L"1999-07-16T10:30Z",
+       L"time{'At 'HH:MM Z}date{' on 'MMM DD, YYYY}",
+       L"At 10:30 GMT on Jul 16, 1999"},
+      {L"en", L"9111T1111:", L"MMM D, YYYYTh:MM:SS A",
+       L"Jan 1, 9111 11:11:00 AM"}};
+
+  for (size_t i = 0; i < FX_ArraySize(tests); ++i) {
+    WideString result;
+    EXPECT_TRUE(fmt(tests[i].locale, tests[i].pattern)
+                    ->FormatDateTime(tests[i].input, FX_DATETIMETYPE_DateTime,
+                                     &result));
+    EXPECT_STREQ(tests[i].output, result.c_str()) << " TEST: " << i;
+  }
+}
+
+TEST_F(CFGAS_StringFormatterTest, TimeDateFormat) {
   struct {
     const wchar_t* locale;
     const wchar_t* input;
@@ -192,14 +224,14 @@
 
   for (size_t i = 0; i < FX_ArraySize(tests); ++i) {
     WideString result;
-    EXPECT_TRUE(fmt(tests[i].locale)
-                    ->FormatDateTime(tests[i].input, tests[i].pattern,
-                                     FX_DATETIMETYPE_TimeDate, &result));
+    EXPECT_TRUE(fmt(tests[i].locale, tests[i].pattern)
+                    ->FormatDateTime(tests[i].input, FX_DATETIMETYPE_TimeDate,
+                                     &result));
     EXPECT_STREQ(tests[i].output, result.c_str()) << " TEST: " << i;
   }
 }
 
-TEST_F(CFGAS_FormatStringTest, DateParse) {
+TEST_F(CFGAS_StringFormatterTest, DateParse) {
   struct {
     const wchar_t* locale;
     const wchar_t* input;
@@ -253,16 +285,16 @@
 
   for (size_t i = 0; i < FX_ArraySize(tests); ++i) {
     CFX_DateTime result;
-    EXPECT_TRUE(fmt(tests[i].locale)
-                    ->ParseDateTime(tests[i].input, tests[i].pattern,
-                                    FX_DATETIMETYPE_Date, &result));
+    EXPECT_TRUE(
+        fmt(tests[i].locale, tests[i].pattern)
+            ->ParseDateTime(tests[i].input, FX_DATETIMETYPE_Date, &result));
     EXPECT_EQ(tests[i].output, result) << " TEST: " << i;
   }
 }
 
 // TODO(dsinclair): GetDateTimeFormat is broken and doesn't allow just returning
 // a parsed Time. It will assume it's a Date. The method needs to be re-written.
-// TEST_F(CFGAS_FormatStringTest, TimeParse) {
+// TEST_F(CFGAS_StringFormatterTest, TimeParse) {
 //   struct {
 //     const wchar_t* locale;
 //     const wchar_t* input;
@@ -287,28 +319,36 @@
 //   }
 // }
 
-TEST_F(CFGAS_FormatStringTest, SplitFormatString) {
-  std::vector<WideString> results;
-  fmt(L"en")->SplitFormatString(
-      L"null{'No data'} | null{} | text{999*9999} | text{999*999*9999}",
-      &results);
+TEST_F(CFGAS_StringFormatterTest, SplitFormatString) {
+  std::vector<WideString> results = CFGAS_StringFormatter::SplitOnBars(L"");
+  EXPECT_EQ(1UL, results.size());
+  EXPECT_TRUE(results[0].IsEmpty());
+
+  results = CFGAS_StringFormatter::SplitOnBars(L"|");
+  EXPECT_EQ(2UL, results.size());
+  EXPECT_TRUE(results[0].IsEmpty());
+  EXPECT_TRUE(results[1].IsEmpty());
+
+  results = CFGAS_StringFormatter::SplitOnBars(
+      L"null{'No|data'} | null{} | text{999*9999} | text{999*999*9999}");
   EXPECT_EQ(4UL, results.size());
 
-  const wchar_t* patterns[] = {L"null{'No data'} ", L" null{} ",
+  const wchar_t* patterns[] = {L"null{'No|data'} ", L" null{} ",
                                L" text{999*9999} ", L" text{999*999*9999}"};
-
   for (size_t i = 0; i < results.size(); ++i) {
     EXPECT_STREQ(patterns[i], results[i].c_str());
   }
 }
 
-TEST_F(CFGAS_FormatStringTest, NumParse) {
-  struct {
+TEST_F(CFGAS_StringFormatterTest, NumParse) {
+  struct TestCase {
     const wchar_t* locale;
     const wchar_t* input;
     const wchar_t* pattern;
     const wchar_t* output;
-  } tests[] = {
+  };
+
+  static const TestCase tests[] = {
       // {L"en", L"€100.00", L"num(en_GB){$z,zz9.99}", L"100"},
       // {L"en", L"1050", L"99V99", L"10.50"},
       // {L"en", L"3125", L"99V99", L"31.25"},
@@ -413,24 +453,48 @@
       {L"en", L"123.5 ", L"zzz.z)", L"123.5"},
       {L"en", L"123.5 ", L"zzz.z(", L"123.5"},
       {L"en", L"123.545,4", L"zzz.zzz,z", L"123.5454"},
+      // https://crbug.com/938724
+      {L"en", L"1", L" num.().().}", L"1"},
   };
 
-  for (size_t i = 0; i < FX_ArraySize(tests); ++i) {
+  static const TestCase failures[] = {
+      // https://crbug.com/pdfium/1260
+      {L"en", L"..", L"VC", L"."},
+
+      // https://crbug.com/938626
+      {L"en", L"PDF", L"num( ", L"."},
+
+      // https://crbug.com/945836
+      {L"en", L"9.E99999999999", L"EdEE.E999", L""},
+
+      // https://crbug.com/947188
+      {L"en", L"-3.E98998998 ", L" 35EEEE.EE98", L""},
+  };
+
+  for (const auto& test : tests) {
     WideString result;
-    EXPECT_TRUE(fmt(tests[i].locale)
-                    ->ParseNum(tests[i].input, tests[i].pattern, &result))
-        << " TEST: " << i;
-    EXPECT_STREQ(tests[i].output, result.c_str()) << " TEST: " << i;
+    EXPECT_TRUE(fmt(test.locale, test.pattern)->ParseNum(test.input, &result))
+        << " TEST: " << test.input << ", " << test.pattern;
+    EXPECT_STREQ(test.output, result.c_str())
+        << " TEST: " << test.input << ", " << test.pattern;
+  }
+
+  for (const auto& test : failures) {
+    WideString result;
+    EXPECT_FALSE(fmt(test.locale, test.pattern)->ParseNum(test.input, &result))
+        << " TEST: " << test.input << ", " << test.pattern;
   }
 }
 
-TEST_F(CFGAS_FormatStringTest, NumFormat) {
-  struct {
+TEST_F(CFGAS_StringFormatterTest, NumFormat) {
+  struct TestCase {
     const wchar_t* locale;
     const wchar_t* input;
     const wchar_t* pattern;
     const wchar_t* output;
-  } tests[] = {
+  };
+
+  static const TestCase tests[] = {
       {L"en", L"1.234", L"zz9.zzz", L"1.234"},
       {L"en", L"1", L"num{z 'text'}", L"1 text"},
       {L"en", L"1", L"num{'text' z}", L"text 1"},
@@ -509,18 +573,49 @@
       // {L"en", L"-123.5", L"zzz.z)", L"123.5)"},
       {L"en", L"123.5", L"zzz.z)", L"123.5 "},
       {L"en", L"123.5", L"zzz.z(", L"123.5 "},
+      // https://crbug.com/pdfium/1233
+      {L"en", L"1", L"r9", L"r1"},
+      {L"en", L"1", L"R9", L"R1"},
+      {L"en", L"1", L"b9", L"b1"},
+      {L"en", L"1", L"B9", L"B1"},
+      {L"en", L"1", L"9.c", L"1"},
+      {L"en", L"1", L"9.C", L"1"},
+      {L"en", L"1", L"9.d", L"1"},
+      {L"en", L"1", L"9.D", L"1"},
+      // https://crbug.com/pdfium/1244
+      {L"en", L"1", L"E", L"1"},
+      {L"en", L"0", L"E", L"0"},
+      {L"en", L"-1", L"E", L"-1"},
+      {L"en", L"900000000000000000000", L"E", L"900,000,000,000,000,000,000"},
+      // TODO(tsepez): next one seems wrong
+      // {L"en", L".000000000000000000009", L"E", L"9"},
+      // https://crbug.com/938724
+      {L"en", L"1", L"| num.().().", L"1"},
+      // https://crbug.com/942449
+      {L"en", L"1", L"9.", L"1"},
   };
 
-  for (size_t i = 0; i < FX_ArraySize(tests); ++i) {
+  static const TestCase failures[] = {
+      // https://crbug.com/pdfium/1271
+      {L"en", L"1", L"num.{E", L""},
+  };
+
+  for (const auto& test : tests) {
     WideString result;
-    EXPECT_TRUE(fmt(tests[i].locale)
-                    ->FormatNum(tests[i].input, tests[i].pattern, &result))
-        << " TEST: " << i;
-    EXPECT_STREQ(tests[i].output, result.c_str()) << " TEST: " << i;
+    EXPECT_TRUE(fmt(test.locale, test.pattern)->FormatNum(test.input, &result))
+        << " TEST: " << test.input << ", " << test.pattern;
+    EXPECT_STREQ(test.output, result.c_str())
+        << " TEST: " << test.input << ", " << test.pattern;
+  }
+
+  for (const auto& test : failures) {
+    WideString result;
+    EXPECT_FALSE(fmt(test.locale, test.pattern)->FormatNum(test.input, &result))
+        << " TEST: " << test.input << ", " << test.pattern;
   }
 }
 
-TEST_F(CFGAS_FormatStringTest, TextParse) {
+TEST_F(CFGAS_StringFormatterTest, TextParse) {
   struct {
     const wchar_t* locale;
     const wchar_t* input;
@@ -539,19 +634,19 @@
 
   for (size_t i = 0; i < FX_ArraySize(tests); ++i) {
     WideString result;
-    EXPECT_TRUE(fmt(tests[i].locale)
-                    ->ParseText(tests[i].input, tests[i].pattern, &result));
+    EXPECT_TRUE(fmt(tests[i].locale, tests[i].pattern)
+                    ->ParseText(tests[i].input, &result));
     EXPECT_STREQ(tests[i].output, result.c_str()) << " TEST: " << i;
   }
 }
 
-TEST_F(CFGAS_FormatStringTest, InvalidTextParse) {
+TEST_F(CFGAS_StringFormatterTest, InvalidTextParse) {
   // Input does not match mask.
   WideString result;
-  EXPECT_FALSE(fmt(L"en")->ParseText(L"123-4567-8", L"AAA-9999-X", &result));
+  EXPECT_FALSE(fmt(L"en", L"AAA-9999-X")->ParseText(L"123-4567-8", &result));
 }
 
-TEST_F(CFGAS_FormatStringTest, TextFormat) {
+TEST_F(CFGAS_StringFormatterTest, TextFormat) {
   struct {
     const wchar_t* locale;
     const wchar_t* input;
@@ -569,29 +664,30 @@
 
   for (size_t i = 0; i < FX_ArraySize(tests); ++i) {
     WideString result;
-    EXPECT_TRUE(fmt(tests[i].locale)
-                    ->FormatText(tests[i].input, tests[i].pattern, &result));
+    EXPECT_TRUE(fmt(tests[i].locale, tests[i].pattern)
+                    ->FormatText(tests[i].input, &result));
     EXPECT_STREQ(tests[i].output, result.c_str()) << " TEST: " << i;
   }
 }
 
-TEST_F(CFGAS_FormatStringTest, NullParse) {
+TEST_F(CFGAS_StringFormatterTest, NullParse) {
   struct {
     const wchar_t* locale;
     const wchar_t* input;
     const wchar_t* pattern;
   } tests[] = {
-      {L"en", L"", L"null{}"}, {L"en", L"No data", L"null{'No data'}"},
+      {L"en", L"", L"null{}"},
+      {L"en", L"No data", L"null{'No data'}"},
   };
 
   for (size_t i = 0; i < FX_ArraySize(tests); ++i) {
     EXPECT_TRUE(
-        fmt(tests[i].locale)->ParseNull(tests[i].input, tests[i].pattern))
+        fmt(tests[i].locale, tests[i].pattern)->ParseNull(tests[i].input))
         << " TEST: " << i;
   }
 }
 
-TEST_F(CFGAS_FormatStringTest, NullFormat) {
+TEST_F(CFGAS_StringFormatterTest, NullFormat) {
   struct {
     const wchar_t* locale;
     const wchar_t* pattern;
@@ -600,12 +696,12 @@
 
   for (size_t i = 0; i < FX_ArraySize(tests); ++i) {
     WideString result;
-    EXPECT_TRUE(fmt(tests[i].locale)->FormatNull(tests[i].pattern, &result));
+    EXPECT_TRUE(fmt(tests[i].locale, tests[i].pattern)->FormatNull(&result));
     EXPECT_STREQ(tests[i].output, result.c_str()) << " TEST: " << i;
   }
 }
 
-TEST_F(CFGAS_FormatStringTest, ZeroParse) {
+TEST_F(CFGAS_StringFormatterTest, ZeroParse) {
   struct {
     const wchar_t* locale;
     const wchar_t* input;
@@ -616,12 +712,12 @@
 
   for (size_t i = 0; i < FX_ArraySize(tests); ++i) {
     EXPECT_TRUE(
-        fmt(tests[i].locale)->ParseZero(tests[i].input, tests[i].pattern))
+        fmt(tests[i].locale, tests[i].pattern)->ParseZero(tests[i].input))
         << " TEST: " << i;
   }
 }
 
-TEST_F(CFGAS_FormatStringTest, ZeroFormat) {
+TEST_F(CFGAS_StringFormatterTest, ZeroFormat) {
   struct {
     const wchar_t* locale;
     const wchar_t* input;
@@ -636,26 +732,26 @@
 
   for (size_t i = 0; i < FX_ArraySize(tests); ++i) {
     WideString result;
-    EXPECT_TRUE(
-        fmt(tests[i].locale)
-            ->FormatZero(/* tests[i].input,*/ tests[i].pattern, &result));
+    EXPECT_TRUE(fmt(tests[i].locale, tests[i].pattern)->FormatZero(&result));
     EXPECT_STREQ(tests[i].output, result.c_str()) << " TEST: " << i;
   }
 }
 
-TEST_F(CFGAS_FormatStringTest, GetCategory) {
-  CFGAS_FormatString* f = fmt(L"en");
-
-  EXPECT_EQ(FX_LOCALECATEGORY_Unknown, f->GetCategory(L"'just text'"));
-  EXPECT_EQ(FX_LOCALECATEGORY_Null, f->GetCategory(L"null{}"));
-  EXPECT_EQ(FX_LOCALECATEGORY_Zero, f->GetCategory(L"zero{}"));
-  EXPECT_EQ(FX_LOCALECATEGORY_Num, f->GetCategory(L"num{}"));
-  EXPECT_EQ(FX_LOCALECATEGORY_Text, f->GetCategory(L"text{}"));
-  EXPECT_EQ(FX_LOCALECATEGORY_DateTime, f->GetCategory(L"datetime{}"));
-  EXPECT_EQ(FX_LOCALECATEGORY_Time, f->GetCategory(L"time{}"));
-  EXPECT_EQ(FX_LOCALECATEGORY_Date, f->GetCategory(L"date{}"));
-  EXPECT_EQ(FX_LOCALECATEGORY_DateTime, f->GetCategory(L"time{} date{}"));
-  EXPECT_EQ(FX_LOCALECATEGORY_DateTime, f->GetCategory(L"date{} time{}"));
-  EXPECT_EQ(FX_LOCALECATEGORY_Num, f->GetCategory(L"num(en_GB){}"));
-  EXPECT_EQ(FX_LOCALECATEGORY_Date, f->GetCategory(L"date.long{}"));
+TEST_F(CFGAS_StringFormatterTest, GetCategory) {
+  EXPECT_EQ(FX_LOCALECATEGORY_Unknown,
+            fmt(L"en", L"'just text'")->GetCategory());
+  EXPECT_EQ(FX_LOCALECATEGORY_Null, fmt(L"en", L"null{}")->GetCategory());
+  EXPECT_EQ(FX_LOCALECATEGORY_Zero, fmt(L"en", L"zero{}")->GetCategory());
+  EXPECT_EQ(FX_LOCALECATEGORY_Num, fmt(L"en", L"num{}")->GetCategory());
+  EXPECT_EQ(FX_LOCALECATEGORY_Text, fmt(L"en", L"text{}")->GetCategory());
+  EXPECT_EQ(FX_LOCALECATEGORY_DateTime,
+            fmt(L"en", L"datetime{}")->GetCategory());
+  EXPECT_EQ(FX_LOCALECATEGORY_Time, fmt(L"en", L"time{}")->GetCategory());
+  EXPECT_EQ(FX_LOCALECATEGORY_Date, fmt(L"en", L"date{}")->GetCategory());
+  EXPECT_EQ(FX_LOCALECATEGORY_DateTime,
+            fmt(L"en", L"time{} date{}")->GetCategory());
+  EXPECT_EQ(FX_LOCALECATEGORY_DateTime,
+            fmt(L"en", L"date{} time{}")->GetCategory());
+  EXPECT_EQ(FX_LOCALECATEGORY_Num, fmt(L"en", L"num(en_GB){}")->GetCategory());
+  EXPECT_EQ(FX_LOCALECATEGORY_Date, fmt(L"en", L"date.long{}")->GetCategory());
 }
diff --git a/xfa/fgas/crt/locale_iface.h b/xfa/fgas/crt/locale_iface.h
new file mode 100644
index 0000000..b5aecdb
--- /dev/null
+++ b/xfa/fgas/crt/locale_iface.h
@@ -0,0 +1,70 @@
+// Copyright 2014 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_FGAS_CRT_LOCALE_IFACE_H_
+#define XFA_FGAS_CRT_LOCALE_IFACE_H_
+
+#include "core/fxcrt/cfx_datetime.h"
+#include "core/fxcrt/fx_string.h"
+
+enum FX_LOCALEDATETIMESUBCATEGORY {
+  FX_LOCALEDATETIMESUBCATEGORY_Default,
+  FX_LOCALEDATETIMESUBCATEGORY_Short,
+  FX_LOCALEDATETIMESUBCATEGORY_Medium,
+  FX_LOCALEDATETIMESUBCATEGORY_Full,
+  FX_LOCALEDATETIMESUBCATEGORY_Long,
+};
+
+enum FX_LOCALENUMSUBCATEGORY {
+  FX_LOCALENUMPATTERN_Percent,
+  FX_LOCALENUMPATTERN_Currency,
+  FX_LOCALENUMPATTERN_Decimal,
+  FX_LOCALENUMPATTERN_Integer,
+};
+
+enum FX_LOCALECATEGORY {
+  FX_LOCALECATEGORY_Unknown,
+  FX_LOCALECATEGORY_Date,
+  FX_LOCALECATEGORY_Time,
+  FX_LOCALECATEGORY_DateTime,
+  FX_LOCALECATEGORY_Num,
+  FX_LOCALECATEGORY_Text,
+  FX_LOCALECATEGORY_Zero,
+  FX_LOCALECATEGORY_Null,
+};
+
+enum FX_DATETIMETYPE {
+  FX_DATETIMETYPE_Unknown,
+  FX_DATETIMETYPE_Date,
+  FX_DATETIMETYPE_Time,
+  FX_DATETIMETYPE_DateTime,
+  FX_DATETIMETYPE_TimeDate,
+};
+
+class LocaleIface {
+ public:
+  virtual ~LocaleIface() = default;
+
+  virtual WideString GetName() const = 0;
+  virtual WideString GetDecimalSymbol() const = 0;
+  virtual WideString GetGroupingSymbol() const = 0;
+  virtual WideString GetPercentSymbol() const = 0;
+  virtual WideString GetMinusSymbol() const = 0;
+  virtual WideString GetCurrencySymbol() const = 0;
+  virtual WideString GetDateTimeSymbols() const = 0;
+  virtual WideString GetMonthName(int32_t nMonth, bool bAbbr) const = 0;
+  virtual WideString GetDayName(int32_t nWeek, bool bAbbr) const = 0;
+  virtual WideString GetMeridiemName(bool bAM) const = 0;
+  virtual FX_TIMEZONE GetTimeZone() const = 0;
+  virtual WideString GetEraName(bool bAD) const = 0;
+  virtual WideString GetDatePattern(
+      FX_LOCALEDATETIMESUBCATEGORY eType) const = 0;
+  virtual WideString GetTimePattern(
+      FX_LOCALEDATETIMESUBCATEGORY eType) const = 0;
+  virtual WideString GetNumPattern(FX_LOCALENUMSUBCATEGORY eType) const = 0;
+};
+
+#endif  // XFA_FGAS_CRT_LOCALE_IFACE_H_
diff --git a/xfa/fgas/crt/locale_mgr_iface.h b/xfa/fgas/crt/locale_mgr_iface.h
new file mode 100644
index 0000000..42f5ada
--- /dev/null
+++ b/xfa/fgas/crt/locale_mgr_iface.h
@@ -0,0 +1,22 @@
+// Copyright 2019 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_FGAS_CRT_LOCALE_MGR_IFACE_H_
+#define XFA_FGAS_CRT_LOCALE_MGR_IFACE_H_
+
+#include "core/fxcrt/fx_string.h"
+
+class LocaleIface;
+
+class LocaleMgrIface {
+ public:
+  virtual ~LocaleMgrIface() = default;
+
+  virtual LocaleIface* GetDefLocale() = 0;
+  virtual LocaleIface* GetLocaleByName(const WideString& wsLCID) = 0;
+};
+
+#endif  // XFA_FGAS_CRT_LOCALE_MGR_IFACE_H_
diff --git a/xfa/fgas/font/cfgas_defaultfontmanager.cpp b/xfa/fgas/font/cfgas_defaultfontmanager.cpp
index 4d0ff20..239dfa7 100644
--- a/xfa/fgas/font/cfgas_defaultfontmanager.cpp
+++ b/xfa/fgas/font/cfgas_defaultfontmanager.cpp
@@ -6,57 +6,58 @@
 
 #include "xfa/fgas/font/cfgas_defaultfontmanager.h"
 
+#include "core/fxge/fx_font.h"
+#include "xfa/fgas/font/cfgas_gefont.h"
 #include "xfa/fgas/font/fgas_fontutils.h"
 
-CFGAS_DefaultFontManager::CFGAS_DefaultFontManager() {}
-
-CFGAS_DefaultFontManager::~CFGAS_DefaultFontManager() {}
-
+// static
 RetainPtr<CFGAS_GEFont> CFGAS_DefaultFontManager::GetFont(
     CFGAS_FontMgr* pFontMgr,
-    const WideStringView& wsFontFamily,
+    WideStringView wsFontFamily,
     uint32_t dwFontStyles) {
   WideString wsFontName(wsFontFamily);
   RetainPtr<CFGAS_GEFont> pFont =
       pFontMgr->LoadFont(wsFontName.c_str(), dwFontStyles, 0xFFFF);
-  if (!pFont) {
-    const FGAS_FontInfo* pCurFont =
-        FGAS_FontInfoByFontName(wsFontName.AsStringView());
-    if (pCurFont && pCurFont->pReplaceFont) {
-      uint32_t dwStyle = 0;
-      // TODO(dsinclair): Why doesn't this check the other flags?
-      if (FontStyleIsBold(dwFontStyles))
-        dwStyle |= FXFONT_BOLD;
-      if (FontStyleIsItalic(dwFontStyles))
-        dwStyle |= FXFONT_ITALIC;
-
-      const wchar_t* pReplace = pCurFont->pReplaceFont;
-      int32_t iLength = wcslen(pReplace);
-      while (iLength > 0) {
-        const wchar_t* pNameText = pReplace;
-        while (*pNameText != L',' && iLength > 0) {
-          pNameText++;
-          iLength--;
-        }
-        WideString wsReplace = WideString(pReplace, pNameText - pReplace);
-        pFont = pFontMgr->LoadFont(wsReplace.c_str(), dwStyle, 0xFFFF);
-        if (pFont)
-          break;
-
-        iLength--;
-        pNameText++;
-        pReplace = pNameText;
-      }
-    }
-  }
   if (pFont)
-    m_CacheFonts.push_back(pFont);
+    return pFont;
+
+  const FGAS_FontInfo* pCurFont =
+      FGAS_FontInfoByFontName(wsFontName.AsStringView());
+  if (!pCurFont || !pCurFont->pReplaceFont)
+    return pFont;
+
+  uint32_t dwStyle = 0;
+  // TODO(dsinclair): Why doesn't this check the other flags?
+  if (FontStyleIsForceBold(dwFontStyles))
+    dwStyle |= FXFONT_FORCE_BOLD;
+  if (FontStyleIsItalic(dwFontStyles))
+    dwStyle |= FXFONT_ITALIC;
+
+  const char* pReplace = pCurFont->pReplaceFont;
+  int32_t iLength = strlen(pReplace);
+  while (iLength > 0) {
+    const char* pNameText = pReplace;
+    while (*pNameText != ',' && iLength > 0) {
+      pNameText++;
+      iLength--;
+    }
+    WideString wsReplace =
+        WideString::FromASCII(ByteStringView(pReplace, pNameText - pReplace));
+    pFont = pFontMgr->LoadFont(wsReplace.c_str(), dwStyle, 0xFFFF);
+    if (pFont)
+      break;
+
+    iLength--;
+    pNameText++;
+    pReplace = pNameText;
+  }
   return pFont;
 }
 
+// static
 RetainPtr<CFGAS_GEFont> CFGAS_DefaultFontManager::GetDefaultFont(
     CFGAS_FontMgr* pFontMgr,
-    const WideStringView& wsFontFamily,
+    WideStringView wsFontFamily,
     uint32_t dwFontStyles) {
   RetainPtr<CFGAS_GEFont> pFont =
       pFontMgr->LoadFont(L"Arial Narrow", dwFontStyles, 0xFFFF);
@@ -64,7 +65,5 @@
     pFont = pFontMgr->LoadFont(static_cast<const wchar_t*>(nullptr),
                                dwFontStyles, 0xFFFF);
   }
-  if (pFont)
-    m_CacheFonts.push_back(pFont);
   return pFont;
 }
diff --git a/xfa/fgas/font/cfgas_defaultfontmanager.h b/xfa/fgas/font/cfgas_defaultfontmanager.h
index 2afe9eb..ebf2f3c 100644
--- a/xfa/fgas/font/cfgas_defaultfontmanager.h
+++ b/xfa/fgas/font/cfgas_defaultfontmanager.h
@@ -7,26 +7,24 @@
 #ifndef XFA_FGAS_FONT_CFGAS_DEFAULTFONTMANAGER_H_
 #define XFA_FGAS_FONT_CFGAS_DEFAULTFONTMANAGER_H_
 
-#include <vector>
-
 #include "core/fxcrt/fx_string.h"
 #include "core/fxcrt/retain_ptr.h"
-#include "xfa/fgas/font/cfgas_gefont.h"
+
+class CFGAS_GEFont;
+class CFGAS_FontMgr;
 
 class CFGAS_DefaultFontManager {
  public:
-  CFGAS_DefaultFontManager();
-  ~CFGAS_DefaultFontManager();
-
-  RetainPtr<CFGAS_GEFont> GetFont(CFGAS_FontMgr* pFontMgr,
-                                  const WideStringView& wsFontFamily,
-                                  uint32_t dwFontStyles);
-  RetainPtr<CFGAS_GEFont> GetDefaultFont(CFGAS_FontMgr* pFontMgr,
-                                         const WideStringView& wsFontFamily,
+  static RetainPtr<CFGAS_GEFont> GetFont(CFGAS_FontMgr* pFontMgr,
+                                         WideStringView wsFontFamily,
                                          uint32_t dwFontStyles);
+  static RetainPtr<CFGAS_GEFont> GetDefaultFont(CFGAS_FontMgr* pFontMgr,
+                                                WideStringView wsFontFamily,
+                                                uint32_t dwFontStyles);
 
- private:
-  std::vector<RetainPtr<CFGAS_GEFont>> m_CacheFonts;
+  CFGAS_DefaultFontManager() = delete;
+  CFGAS_DefaultFontManager(const CFGAS_DefaultFontManager&) = delete;
+  CFGAS_DefaultFontManager& operator=(const CFGAS_DefaultFontManager&) = delete;
 };
 
 #endif  // XFA_FGAS_FONT_CFGAS_DEFAULTFONTMANAGER_H_
diff --git a/xfa/fgas/font/cfgas_fontmgr.cpp b/xfa/fgas/font/cfgas_fontmgr.cpp
index 862e929..96407f3 100644
--- a/xfa/fgas/font/cfgas_fontmgr.cpp
+++ b/xfa/fgas/font/cfgas_fontmgr.cpp
@@ -10,80 +10,49 @@
 #include <memory>
 #include <utility>
 
+#include "build/build_config.h"
 #include "core/fxcrt/cfx_memorystream.h"
 #include "core/fxcrt/fx_codepage.h"
+#include "core/fxcrt/fx_memory_wrappers.h"
 #include "core/fxge/cfx_font.h"
 #include "core/fxge/cfx_fontmapper.h"
 #include "core/fxge/cfx_fontmgr.h"
 #include "core/fxge/cfx_gemodule.h"
 #include "core/fxge/fx_font.h"
-#include "core/fxge/ifx_systemfontinfo.h"
 #include "third_party/base/ptr_util.h"
 #include "third_party/base/stl_util.h"
 #include "xfa/fgas/font/cfgas_gefont.h"
 #include "xfa/fgas/font/fgas_fontutils.h"
 
-#if _FX_PLATFORM_ == _FX_PLATFORM_WINDOWS_
+#if !defined(OS_WIN)
+#include "xfa/fgas/font/cfx_fontsourceenum_file.h"
+#endif
 
 namespace {
 
-struct FX_CHARSET_MAP {
-  uint16_t charset;
-  uint16_t codepage;
-};
+bool VerifyUnicode(const RetainPtr<CFGAS_GEFont>& pFont, wchar_t wcUnicode) {
+  RetainPtr<CFX_Face> pFace = pFont->GetDevFont()->GetFace();
+  if (!pFace)
+    return false;
 
-const FX_CHARSET_MAP g_FXCharset2CodePageTable[] = {
-    {FX_CHARSET_ANSI, FX_CODEPAGE_MSWin_WesternEuropean},
-    {FX_CHARSET_Default, FX_CODEPAGE_DefANSI},
-    {FX_CHARSET_Symbol, FX_CODEPAGE_Symbol},
-    {FX_CHARSET_MAC_Roman, FX_CODEPAGE_MAC_Roman},
-    {FX_CHARSET_MAC_ShiftJIS, FX_CODEPAGE_MAC_ShiftJIS},
-    {FX_CHARSET_MAC_Korean, FX_CODEPAGE_MAC_Korean},
-    {FX_CHARSET_MAC_ChineseSimplified, FX_CODEPAGE_MAC_ChineseSimplified},
-    {FX_CHARSET_MAC_ChineseTraditional, FX_CODEPAGE_MAC_ChineseTraditional},
-    {FX_CHARSET_MAC_Hebrew, FX_CODEPAGE_MAC_Hebrew},
-    {FX_CHARSET_MAC_Arabic, FX_CODEPAGE_MAC_Arabic},
-    {FX_CHARSET_MAC_Greek, FX_CODEPAGE_MAC_Greek},
-    {FX_CHARSET_MAC_Turkish, FX_CODEPAGE_MAC_Turkish},
-    {FX_CHARSET_MAC_Thai, FX_CODEPAGE_MAC_Thai},
-    {FX_CHARSET_MAC_EasternEuropean, FX_CODEPAGE_MAC_EasternEuropean},
-    {FX_CHARSET_MAC_Cyrillic, FX_CODEPAGE_MAC_Cyrillic},
-    {FX_CHARSET_ShiftJIS, FX_CODEPAGE_ShiftJIS},
-    {FX_CHARSET_Hangul, FX_CODEPAGE_Hangul},
-    {FX_CHARSET_Johab, FX_CODEPAGE_Johab},
-    {FX_CHARSET_ChineseSimplified, FX_CODEPAGE_ChineseSimplified},
-    {FX_CHARSET_ChineseTraditional, FX_CODEPAGE_ChineseTraditional},
-    {FX_CHARSET_MSWin_Greek, FX_CODEPAGE_MSWin_Greek},
-    {FX_CHARSET_MSWin_Turkish, FX_CODEPAGE_MSWin_Turkish},
-    {FX_CHARSET_MSWin_Vietnamese, FX_CODEPAGE_MSWin_Vietnamese},
-    {FX_CHARSET_MSWin_Hebrew, FX_CODEPAGE_MSWin_Hebrew},
-    {FX_CHARSET_MSWin_Arabic, FX_CODEPAGE_MSWin_Arabic},
-    {FX_CHARSET_MSWin_Baltic, FX_CODEPAGE_MSWin_Baltic},
-    {FX_CHARSET_MSWin_Cyrillic, FX_CODEPAGE_MSWin_Cyrillic},
-    {FX_CHARSET_Thai, FX_CODEPAGE_MSDOS_Thai},
-    {FX_CHARSET_MSWin_EasternEuropean, FX_CODEPAGE_MSWin_EasternEuropean},
-    {FX_CHARSET_US, FX_CODEPAGE_MSDOS_US},
-    {FX_CHARSET_OEM, FX_CODEPAGE_MSDOS_WesternEuropean},
-};
+  FXFT_FaceRec* pFaceRec = pFace->GetRec();
+  FT_CharMap charmap = FXFT_Get_Face_Charmap(pFaceRec);
+  if (FXFT_Select_Charmap(pFaceRec, FT_ENCODING_UNICODE) != 0)
+    return false;
 
-uint16_t GetCodePageFromCharset(uint8_t charset) {
-  int32_t iEnd = sizeof(g_FXCharset2CodePageTable) / sizeof(FX_CHARSET_MAP) - 1;
-  ASSERT(iEnd >= 0);
-
-  int32_t iStart = 0, iMid;
-  do {
-    iMid = (iStart + iEnd) / 2;
-    const FX_CHARSET_MAP& cp = g_FXCharset2CodePageTable[iMid];
-    if (charset == cp.charset)
-      return cp.codepage;
-    if (charset < cp.charset)
-      iEnd = iMid - 1;
-    else
-      iStart = iMid + 1;
-  } while (iStart <= iEnd);
-  return 0xFFFF;
+  if (FT_Get_Char_Index(pFaceRec, wcUnicode) == 0) {
+    FT_Set_Charmap(pFaceRec, charmap);
+    return false;
+  }
+  return true;
 }
 
+}  // namespace
+
+#if defined(OS_WIN)
+
+namespace {
+
 int32_t GetSimilarityScore(FX_FONTDESCRIPTOR const* pFont,
                            uint32_t dwFontStyles) {
   int32_t iValue = 0;
@@ -108,7 +77,7 @@
   const FX_FONTDESCRIPTOR* pBestFont = nullptr;
   int32_t iBestSimilar = 0;
   for (const auto& font : fonts) {
-    if (FontStyleIsBold(font.dwFontStyles) &&
+    if (FontStyleIsForceBold(font.dwFontStyles) &&
         FontStyleIsItalic(font.dwFontStyles)) {
       continue;
     }
@@ -122,7 +91,7 @@
     if (font.uCharSet == FX_CHARSET_Symbol)
       continue;
     if (pParams->wCodePage != 0xFFFF) {
-      if (GetCodePageFromCharset(font.uCharSet) != pParams->wCodePage)
+      if (FX_GetCodePageFromCharset(font.uCharSet) != pParams->wCodePage)
         continue;
     } else {
       if (pParams->dwUSB < 128) {
@@ -173,23 +142,20 @@
   const LOGFONTW& lf = ((LPENUMLOGFONTEXW)lpelfe)->elfLogFont;
   if (lf.lfFaceName[0] == L'@')
     return 1;
-  FX_FONTDESCRIPTOR* pFont = FX_Alloc(FX_FONTDESCRIPTOR, 1);
-  memset(pFont, 0, sizeof(FX_FONTDESCRIPTOR));
-  pFont->uCharSet = lf.lfCharSet;
-  pFont->dwFontStyles = GetGdiFontStyles(lf);
-  FXSYS_wcsncpy(pFont->wsFontFace, (const wchar_t*)lf.lfFaceName, 31);
-  pFont->wsFontFace[31] = 0;
-  memcpy(&pFont->FontSignature, &lpntme->ntmFontSig,
-         sizeof(lpntme->ntmFontSig));
-  reinterpret_cast<std::deque<FX_FONTDESCRIPTOR>*>(lParam)->push_back(*pFont);
-  FX_Free(pFont);
+  FX_FONTDESCRIPTOR font;
+  memset(&font, 0, sizeof(FX_FONTDESCRIPTOR));
+  font.uCharSet = lf.lfCharSet;
+  font.dwFontStyles = GetGdiFontStyles(lf);
+  FXSYS_wcsncpy(font.wsFontFace, (const wchar_t*)lf.lfFaceName, 31);
+  font.wsFontFace[31] = 0;
+  memcpy(&font.FontSignature, &lpntme->ntmFontSig, sizeof(lpntme->ntmFontSig));
+  reinterpret_cast<std::deque<FX_FONTDESCRIPTOR>*>(lParam)->push_back(font);
   return 1;
 }
 
-void EnumGdiFonts(std::deque<FX_FONTDESCRIPTOR>* fonts,
-                  const wchar_t* pwsFaceName,
-                  wchar_t wUnicode) {
-  HDC hDC = ::GetDC(nullptr);
+std::deque<FX_FONTDESCRIPTOR> EnumGdiFonts(const wchar_t* pwsFaceName,
+                                           wchar_t wUnicode) {
+  std::deque<FX_FONTDESCRIPTOR> fonts;
   LOGFONTW lfFind;
   memset(&lfFind, 0, sizeof(lfFind));
   lfFind.lfCharSet = DEFAULT_CHARSET;
@@ -197,24 +163,56 @@
     FXSYS_wcsncpy(lfFind.lfFaceName, pwsFaceName, 31);
     lfFind.lfFaceName[31] = 0;
   }
+  HDC hDC = ::GetDC(nullptr);
   EnumFontFamiliesExW(hDC, (LPLOGFONTW)&lfFind, (FONTENUMPROCW)GdiFontEnumProc,
-                      (LPARAM)fonts, 0);
+                      (LPARAM)&fonts, 0);
   ::ReleaseDC(nullptr, hDC);
+  return fonts;
 }
 
 }  // namespace
 
-CFGAS_FontMgr::CFGAS_FontMgr() : m_pEnumerator(EnumGdiFonts), m_FontFaces(100) {
-  if (m_pEnumerator)
-    m_pEnumerator(&m_FontFaces, nullptr, 0xFEFF);
-}
+CFGAS_FontMgr::CFGAS_FontMgr() : m_FontFaces(EnumGdiFonts(nullptr, 0xFEFF)) {}
 
-CFGAS_FontMgr::~CFGAS_FontMgr() {}
+CFGAS_FontMgr::~CFGAS_FontMgr() = default;
 
 bool CFGAS_FontMgr::EnumFonts() {
   return true;
 }
 
+RetainPtr<CFGAS_GEFont> CFGAS_FontMgr::GetFontByUnicodeImpl(
+    wchar_t wUnicode,
+    uint32_t dwFontStyles,
+    const wchar_t* pszFontFamily,
+    uint32_t dwHash,
+    uint16_t wCodePage,
+    uint16_t wBitField) {
+  const FX_FONTDESCRIPTOR* pFD = FindFont(pszFontFamily, dwFontStyles, false,
+                                          wCodePage, wBitField, wUnicode);
+  if (!pFD && pszFontFamily) {
+    pFD =
+        FindFont(nullptr, dwFontStyles, false, wCodePage, wBitField, wUnicode);
+  }
+  if (!pFD)
+    return nullptr;
+
+  uint16_t newCodePage = FX_GetCodePageFromCharset(pFD->uCharSet);
+  const wchar_t* pFontFace = pFD->wsFontFace;
+  RetainPtr<CFGAS_GEFont> pFont =
+      CFGAS_GEFont::LoadFont(pFontFace, dwFontStyles, newCodePage, this);
+  if (!pFont)
+    return nullptr;
+
+  pFont->SetLogicalFontStyle(dwFontStyles);
+  if (!VerifyUnicode(pFont, wUnicode)) {
+    m_FailedUnicodesSet.insert(wUnicode);
+    return nullptr;
+  }
+
+  m_Hash2Fonts[dwHash].push_back(pFont);
+  return pFont;
+}
+
 const FX_FONTDESCRIPTOR* CFGAS_FontMgr::FindFont(const wchar_t* pszFontFamily,
                                                  uint32_t dwFontStyles,
                                                  bool matchParagraphStyle,
@@ -229,15 +227,19 @@
   params.pwsFamily = pszFontFamily;
   params.dwFontStyles = dwFontStyles;
   params.matchParagraphStyle = matchParagraphStyle;
+
   const FX_FONTDESCRIPTOR* pDesc = MatchDefaultFont(&params, m_FontFaces);
   if (pDesc)
     return pDesc;
 
-  if (!pszFontFamily || !m_pEnumerator)
+  if (!pszFontFamily)
     return nullptr;
 
-  std::deque<FX_FONTDESCRIPTOR> namedFonts;
-  m_pEnumerator(&namedFonts, pszFontFamily, wUnicode);
+  // Use a named object to store the returned value of EnumGdiFonts() instead
+  // of using a temporary object. This can prevent use-after-free issues since
+  // pDesc may point to one of std::deque object's elements.
+  std::deque<FX_FONTDESCRIPTOR> namedFonts =
+      EnumGdiFonts(pszFontFamily, wUnicode);
   params.pwsFamily = nullptr;
   pDesc = MatchDefaultFont(&params, namedFonts);
   if (!pDesc)
@@ -251,21 +253,10 @@
   return &m_FontFaces.back();
 }
 
-#else  // _FX_PLATFORM_ == _FX_PLATFORM_WINDOWS_
+#else  // defined(OS_WIN)
 
 namespace {
 
-constexpr const char* g_FontFolders[] = {
-#if _FX_PLATFORM_ == _FX_PLATFORM_LINUX_
-    "/usr/share/fonts", "/usr/share/X11/fonts/Type1",
-    "/usr/share/X11/fonts/TTF", "/usr/local/share/fonts",
-#elif _FX_PLATFORM_ == _FX_PLATFORM_APPLE_
-    "~/Library/Fonts", "/Library/Fonts", "/System/Library/Fonts",
-#elif _FX_PLATFORM_ == _FX_PLATFORM_ANDROID_
-    "/system/fonts",
-#endif
-};
-
 const uint16_t g_CodePages[] = {FX_CODEPAGE_MSWin_WesternEuropean,
                                 FX_CODEPAGE_MSWin_EasternEuropean,
                                 FX_CODEPAGE_MSWin_Cyrillic,
@@ -352,82 +343,9 @@
   return static_cast<uint16_t>(p[0] << 8 | p[1]);
 }
 
-struct FX_BIT2CHARSET {
-  uint16_t wBit;
-  uint16_t wCharset;
-};
-
-const FX_BIT2CHARSET g_FX_Bit2Charset[4][16] = {
-    {{1 << 0, FX_CHARSET_ANSI},
-     {1 << 1, FX_CHARSET_MSWin_EasternEuropean},
-     {1 << 2, FX_CHARSET_MSWin_Cyrillic},
-     {1 << 3, FX_CHARSET_MSWin_Greek},
-     {1 << 4, FX_CHARSET_MSWin_Turkish},
-     {1 << 5, FX_CHARSET_MSWin_Hebrew},
-     {1 << 6, FX_CHARSET_MSWin_Arabic},
-     {1 << 7, FX_CHARSET_MSWin_Baltic},
-     {1 << 8, FX_CHARSET_MSWin_Vietnamese},
-     {1 << 9, FX_CHARSET_Default},
-     {1 << 10, FX_CHARSET_Default},
-     {1 << 11, FX_CHARSET_Default},
-     {1 << 12, FX_CHARSET_Default},
-     {1 << 13, FX_CHARSET_Default},
-     {1 << 14, FX_CHARSET_Default},
-     {1 << 15, FX_CHARSET_Default}},
-    {{1 << 0, FX_CHARSET_Thai},
-     {1 << 1, FX_CHARSET_ShiftJIS},
-     {1 << 2, FX_CHARSET_ChineseSimplified},
-     {1 << 3, FX_CHARSET_Hangul},
-     {1 << 4, FX_CHARSET_ChineseTraditional},
-     {1 << 5, FX_CHARSET_Johab},
-     {1 << 6, FX_CHARSET_Default},
-     {1 << 7, FX_CHARSET_Default},
-     {1 << 8, FX_CHARSET_Default},
-     {1 << 9, FX_CHARSET_Default},
-     {1 << 10, FX_CHARSET_Default},
-     {1 << 11, FX_CHARSET_Default},
-     {1 << 12, FX_CHARSET_Default},
-     {1 << 13, FX_CHARSET_Default},
-     {1 << 14, FX_CHARSET_OEM},
-     {1 << 15, FX_CHARSET_Symbol}},
-    {{1 << 0, FX_CHARSET_Default},
-     {1 << 1, FX_CHARSET_Default},
-     {1 << 2, FX_CHARSET_Default},
-     {1 << 3, FX_CHARSET_Default},
-     {1 << 4, FX_CHARSET_Default},
-     {1 << 5, FX_CHARSET_Default},
-     {1 << 6, FX_CHARSET_Default},
-     {1 << 7, FX_CHARSET_Default},
-     {1 << 8, FX_CHARSET_Default},
-     {1 << 9, FX_CHARSET_Default},
-     {1 << 10, FX_CHARSET_Default},
-     {1 << 11, FX_CHARSET_Default},
-     {1 << 12, FX_CHARSET_Default},
-     {1 << 13, FX_CHARSET_Default},
-     {1 << 14, FX_CHARSET_Default},
-     {1 << 15, FX_CHARSET_Default}},
-    {{1 << 0, FX_CHARSET_Default},
-     {1 << 1, FX_CHARSET_Default},
-     {1 << 2, FX_CHARSET_Default},
-     {1 << 3, FX_CHARSET_Default},
-     {1 << 4, FX_CHARSET_Default},
-     {1 << 5, FX_CHARSET_Default},
-     {1 << 6, FX_CHARSET_Default},
-     {1 << 7, FX_CHARSET_Default},
-     {1 << 8, FX_CHARSET_Default},
-     {1 << 9, FX_CHARSET_Default},
-     {1 << 10, FX_CHARSET_Default},
-     {1 << 11, FX_CHARSET_Default},
-     {1 << 12, FX_CHARSET_Default},
-     {1 << 13, FX_CHARSET_Default},
-     {1 << 14, FX_CHARSET_Default},
-     {1 << 15, FX_CHARSET_US}}};
-
-constexpr wchar_t kFolderSeparator = L'/';
-
 extern "C" {
 
-unsigned long ftStreamRead(FXFT_Stream stream,
+unsigned long ftStreamRead(FXFT_StreamRec* stream,
                            unsigned long offset,
                            unsigned char* buffer,
                            unsigned long count) {
@@ -436,206 +354,129 @@
 
   IFX_SeekableReadStream* pFile =
       static_cast<IFX_SeekableReadStream*>(stream->descriptor.pointer);
-  if (!pFile->ReadBlock(buffer, offset, count))
+  if (!pFile->ReadBlockAtOffset(buffer, offset, count))
     return 0;
 
   return count;
 }
 
-void ftStreamClose(FXFT_Stream stream) {}
+void ftStreamClose(FXFT_StreamRec* stream) {}
 
-};  // extern "C"
+}  // extern "C"
 
-}  // namespace
+// TODO(thestig): Pass in |name_table| as a std::vector?
+std::vector<WideString> GetNames(const uint8_t* name_table) {
+  std::vector<WideString> results;
+  if (!name_table)
+    return results;
 
-CFX_FontDescriptor::CFX_FontDescriptor()
-    : m_nFaceIndex(0), m_dwFontStyles(0), m_dwUsb(), m_dwCsb() {}
+  const uint8_t* lpTable = name_table;
+  WideString wsFamily;
+  const uint8_t* sp = lpTable + 2;
+  const uint8_t* lpNameRecord = lpTable + 6;
+  uint16_t nNameCount = GetUInt16(sp);
+  const uint8_t* lpStr = lpTable + GetUInt16(sp + 2);
+  for (uint16_t j = 0; j < nNameCount; j++) {
+    uint16_t nNameID = GetUInt16(lpNameRecord + j * 12 + 6);
+    if (nNameID != 1)
+      continue;
 
-CFX_FontDescriptor::~CFX_FontDescriptor() {}
-
-CFX_FontSourceEnum_File::CFX_FontSourceEnum_File() {
-  for (size_t i = 0; i < FX_ArraySize(g_FontFolders); ++i)
-    m_FolderPaths.push_back(g_FontFolders[i]);
-}
-
-CFX_FontSourceEnum_File::~CFX_FontSourceEnum_File() {}
-
-ByteString CFX_FontSourceEnum_File::GetNextFile() {
-  FX_FileHandle* pCurHandle =
-      !m_FolderQueue.empty() ? m_FolderQueue.back().pFileHandle : nullptr;
-  if (!pCurHandle) {
-    if (m_FolderPaths.empty())
-      return "";
-    pCurHandle = FX_OpenFolder(m_FolderPaths.back().c_str());
-    HandleParentPath hpp;
-    hpp.pFileHandle = pCurHandle;
-    hpp.bsParentPath = m_FolderPaths.back();
-    m_FolderQueue.push_back(hpp);
-  }
-  ByteString bsName;
-  bool bFolder;
-  ByteString bsFolderSeparator =
-      ByteString::FromUnicode(WideString(kFolderSeparator));
-  while (true) {
-    if (!FX_GetNextFile(pCurHandle, &bsName, &bFolder)) {
-      FX_CloseFolder(pCurHandle);
-      if (!m_FolderQueue.empty())
-        m_FolderQueue.pop_back();
-      if (m_FolderQueue.empty()) {
-        if (!m_FolderPaths.empty())
-          m_FolderPaths.pop_back();
-        return !m_FolderPaths.empty() ? GetNextFile() : "";
+    uint16_t nPlatformID = GetUInt16(lpNameRecord + j * 12 + 0);
+    uint16_t nNameLength = GetUInt16(lpNameRecord + j * 12 + 8);
+    uint16_t nNameOffset = GetUInt16(lpNameRecord + j * 12 + 10);
+    wsFamily.clear();
+    if (nPlatformID != 1) {
+      for (uint16_t k = 0; k < nNameLength / 2; k++) {
+        wchar_t wcTemp = GetUInt16(lpStr + nNameOffset + k * 2);
+        wsFamily += wcTemp;
       }
-      pCurHandle = m_FolderQueue.back().pFileHandle;
+      results.push_back(wsFamily);
       continue;
     }
-    if (bsName == "." || bsName == "..")
-      continue;
-    if (bFolder) {
-      HandleParentPath hpp;
-      hpp.bsParentPath =
-          m_FolderQueue.back().bsParentPath + bsFolderSeparator + bsName;
-      hpp.pFileHandle = FX_OpenFolder(hpp.bsParentPath.c_str());
-      if (!hpp.pFileHandle)
-        continue;
-      m_FolderQueue.push_back(hpp);
-      pCurHandle = hpp.pFileHandle;
-      continue;
+    for (uint16_t k = 0; k < nNameLength; k++) {
+      wchar_t wcTemp = GetUInt8(lpStr + nNameOffset + k);
+      wsFamily += wcTemp;
     }
-    bsName = m_FolderQueue.back().bsParentPath + bsFolderSeparator + bsName;
-    break;
+    results.push_back(wsFamily);
   }
-  return bsName;
+  return results;
 }
 
-bool CFX_FontSourceEnum_File::HasStartPosition() {
-  m_wsNext = GetNextFile().UTF8Decode();
-  return m_wsNext.GetLength() != 0;
-}
-
-// <next exists, stream for next>
-std::pair<bool, RetainPtr<IFX_SeekableStream>>
-CFX_FontSourceEnum_File::GetNext() {
-  if (m_wsNext.GetLength() == 0)
-    return {false, nullptr};
-
-  auto stream = IFX_SeekableStream::CreateFromFilename(m_wsNext.c_str(),
-                                                       FX_FILEMODE_ReadOnly);
-  m_wsNext = GetNextFile().UTF8Decode();
-  return {true, stream};
-}
-
-CFGAS_FontMgr::CFGAS_FontMgr()
-    : m_pFontSource(pdfium::MakeUnique<CFX_FontSourceEnum_File>()) {}
-
-CFGAS_FontMgr::~CFGAS_FontMgr() {}
-
-bool CFGAS_FontMgr::EnumFontsFromFontMapper() {
-  CFX_FontMapper* pFontMapper =
-      CFX_GEModule::Get()->GetFontMgr()->GetBuiltinMapper();
-  if (!pFontMapper)
-    return false;
-
-  IFX_SystemFontInfo* pSystemFontInfo = pFontMapper->GetSystemFontInfo();
-  if (!pSystemFontInfo)
-    return false;
-
-  pSystemFontInfo->EnumFontList(pFontMapper);
-  for (int32_t i = 0; i < pFontMapper->GetFaceSize(); ++i) {
-    RetainPtr<IFX_SeekableReadStream> pFontStream =
-        CreateFontStream(pFontMapper, pSystemFontInfo, i);
-    if (!pFontStream)
-      continue;
-
-    WideString wsFaceName =
-        WideString::FromLocal(pFontMapper->GetFaceName(i).c_str());
-    RegisterFaces(pFontStream, &wsFaceName);
+void GetUSBCSB(FXFT_FaceRec* pFace, uint32_t* USB, uint32_t* CSB) {
+  TT_OS2* pOS2 = static_cast<TT_OS2*>(FT_Get_Sfnt_Table(pFace, ft_sfnt_os2));
+  if (!pOS2) {
+    USB[0] = 0;
+    USB[1] = 0;
+    USB[2] = 0;
+    USB[3] = 0;
+    CSB[0] = 0;
+    CSB[1] = 0;
+    return;
   }
-  return !m_InstalledFonts.empty();
+  USB[0] = pOS2->ulUnicodeRange1;
+  USB[1] = pOS2->ulUnicodeRange2;
+  USB[2] = pOS2->ulUnicodeRange3;
+  USB[3] = pOS2->ulUnicodeRange4;
+  CSB[0] = pOS2->ulCodePageRange1;
+  CSB[1] = pOS2->ulCodePageRange2;
 }
 
-bool CFGAS_FontMgr::EnumFontsFromFiles() {
-  CFX_GEModule::Get()->GetFontMgr()->InitFTLibrary();
-  if (!m_pFontSource->HasStartPosition())
-    return !m_InstalledFonts.empty();
+uint32_t GetFlags(FXFT_FaceRec* pFace) {
+  uint32_t flags = 0;
+  if (FXFT_Is_Face_Bold(pFace))
+    flags |= FXFONT_FORCE_BOLD;
+  if (FXFT_Is_Face_Italic(pFace))
+    flags |= FXFONT_ITALIC;
+  if (FT_IS_FIXED_WIDTH(pFace))
+    flags |= FXFONT_FIXED_PITCH;
 
-  bool has_next;
-  RetainPtr<IFX_SeekableStream> stream;
-  std::tie(has_next, stream) = m_pFontSource->GetNext();
-  while (has_next) {
-    if (stream)
-      RegisterFaces(stream, nullptr);
-    std::tie(has_next, stream) = m_pFontSource->GetNext();
+  TT_OS2* pOS2 = static_cast<TT_OS2*>(FT_Get_Sfnt_Table(pFace, ft_sfnt_os2));
+  if (!pOS2)
+    return flags;
+
+  if (pOS2->ulCodePageRange1 & (1 << 31))
+    flags |= FXFONT_SYMBOLIC;
+  if (pOS2->panose[0] == 2) {
+    uint8_t uSerif = pOS2->panose[1];
+    if ((uSerif > 1 && uSerif < 10) || uSerif > 13)
+      flags |= FXFONT_SERIF;
   }
-  return !m_InstalledFonts.empty();
+  return flags;
 }
 
-bool CFGAS_FontMgr::EnumFonts() {
-  return EnumFontsFromFontMapper() || EnumFontsFromFiles();
+RetainPtr<IFX_SeekableReadStream> CreateFontStream(
+    CFX_FontMapper* pFontMapper,
+    uint32_t index) {
+  size_t dwFileSize = 0;
+  std::unique_ptr<uint8_t, FxFreeDeleter> pBuffer =
+      pFontMapper->RawBytesForIndex(index, &dwFileSize);
+  if (!pBuffer)
+    return nullptr;
+
+  return pdfium::MakeRetain<CFX_MemoryStream>(std::move(pBuffer), dwFileSize);
 }
 
-bool CFGAS_FontMgr::VerifyUnicode(CFX_FontDescriptor* pDesc,
-                                  wchar_t wcUnicode) {
-  RetainPtr<IFX_SeekableReadStream> pFileRead =
-      CreateFontStream(pDesc->m_wsFaceName.UTF8Encode());
-  if (!pFileRead)
-    return false;
-
-  FXFT_Face pFace = LoadFace(pFileRead, pDesc->m_nFaceIndex);
-  FT_Error retCharmap = FXFT_Select_Charmap(pFace, FXFT_ENCODING_UNICODE);
-  FT_Error retIndex = FXFT_Get_Char_Index(pFace, wcUnicode);
-  if (!pFace)
-    return false;
-
-  if (FXFT_Get_Face_External_Stream(pFace))
-    FXFT_Clear_Face_External_Stream(pFace);
-
-  FXFT_Done_Face(pFace);
-  return !retCharmap && retIndex;
-}
-
-RetainPtr<CFGAS_GEFont> CFGAS_FontMgr::LoadFont(const WideString& wsFaceName,
-                                                int32_t iFaceIndex,
-                                                int32_t* pFaceCount) {
+RetainPtr<IFX_SeekableReadStream> CreateFontStream(
+    const ByteString& bsFaceName) {
   CFX_FontMgr* pFontMgr = CFX_GEModule::Get()->GetFontMgr();
   CFX_FontMapper* pFontMapper = pFontMgr->GetBuiltinMapper();
-  if (!pFontMapper)
-    return nullptr;
+  pFontMapper->LoadInstalledFonts();
 
-  IFX_SystemFontInfo* pSystemFontInfo = pFontMapper->GetSystemFontInfo();
-  if (!pSystemFontInfo)
-    return nullptr;
-
-  RetainPtr<IFX_SeekableReadStream> pFontStream =
-      CreateFontStream(wsFaceName.UTF8Encode());
-  if (!pFontStream)
-    return nullptr;
-
-  auto pInternalFont = pdfium::MakeUnique<CFX_Font>();
-  if (!pInternalFont->LoadFile(pFontStream, iFaceIndex))
-    return nullptr;
-
-  RetainPtr<CFGAS_GEFont> pFont =
-      CFGAS_GEFont::LoadFont(std::move(pInternalFont), this);
-  if (!pFont)
-    return nullptr;
-
-  m_IFXFont2FileRead[pFont] = pFontStream;
-  if (pFaceCount)
-    *pFaceCount = pFont->GetDevFont()->GetFace()->num_faces;
-  return pFont;
+  for (int32_t i = 0; i < pFontMapper->GetFaceSize(); ++i) {
+    if (pFontMapper->GetFaceName(i) == bsFaceName)
+      return CreateFontStream(pFontMapper, i);
+  }
+  return nullptr;
 }
 
-FXFT_Face CFGAS_FontMgr::LoadFace(
+RetainPtr<CFX_Face> LoadFace(
     const RetainPtr<IFX_SeekableReadStream>& pFontStream,
     int32_t iFaceIndex) {
   if (!pFontStream)
     return nullptr;
 
   CFX_FontMgr* pFontMgr = CFX_GEModule::Get()->GetFontMgr();
-  pFontMgr->InitFTLibrary();
-
-  FXFT_Library library = pFontMgr->GetFTLibrary();
+  FXFT_LibraryRec* library = pFontMgr->GetFTLibrary();
   if (!library)
     return nullptr;
 
@@ -643,8 +484,8 @@
   // Ultimately, we want to change this to:
   //   FXFT_Stream ftStream = FX_Alloc(FXFT_StreamRec, 1);
   // https://bugs.chromium.org/p/pdfium/issues/detail?id=690
-  FXFT_Stream ftStream =
-      static_cast<FXFT_Stream>(ft_scalloc(sizeof(FXFT_StreamRec), 1));
+  FXFT_StreamRec* ftStream =
+      static_cast<FXFT_StreamRec*>(ft_scalloc(sizeof(FXFT_StreamRec), 1));
   memset(ftStream, 0, sizeof(FXFT_StreamRec));
   ftStream->base = nullptr;
   ftStream->descriptor.pointer = static_cast<void*>(pFontStream.Get());
@@ -653,83 +494,50 @@
   ftStream->read = ftStreamRead;
   ftStream->close = ftStreamClose;
 
-  FXFT_Open_Args ftArgs;
-  memset(&ftArgs, 0, sizeof(FXFT_Open_Args));
+  FT_Open_Args ftArgs;
+  memset(&ftArgs, 0, sizeof(FT_Open_Args));
   ftArgs.flags |= FT_OPEN_STREAM;
   ftArgs.stream = ftStream;
 
-  FXFT_Face pFace = nullptr;
-  if (FXFT_Open_Face(library, &ftArgs, iFaceIndex, &pFace)) {
+  RetainPtr<CFX_Face> pFace = CFX_Face::Open(library, &ftArgs, iFaceIndex);
+  if (!pFace) {
     ft_sfree(ftStream);
     return nullptr;
   }
-
-  FXFT_Set_Pixel_Sizes(pFace, 0, 64);
+  FT_Set_Pixel_Sizes(pFace->GetRec(), 0, 64);
   return pFace;
 }
 
-RetainPtr<IFX_SeekableReadStream> CFGAS_FontMgr::CreateFontStream(
-    CFX_FontMapper* pFontMapper,
-    IFX_SystemFontInfo* pSystemFontInfo,
-    uint32_t index) {
-  void* hFont = pSystemFontInfo->MapFont(
-      0, 0, FX_CHARSET_Default, 0, pFontMapper->GetFaceName(index).c_str());
-  if (!hFont)
-    return nullptr;
+bool VerifyUnicodeForFontDescriptor(CFX_FontDescriptor* pDesc,
+                                    wchar_t wcUnicode) {
+  RetainPtr<IFX_SeekableReadStream> pFileRead =
+      CreateFontStream(pDesc->m_wsFaceName.ToUTF8());
+  if (!pFileRead)
+    return false;
 
-  uint32_t dwFileSize = pSystemFontInfo->GetFontData(hFont, 0, nullptr, 0);
-  if (dwFileSize == 0)
-    return nullptr;
+  RetainPtr<CFX_Face> pFace = LoadFace(pFileRead, pDesc->m_nFaceIndex);
+  if (!pFace)
+    return false;
 
-  uint8_t* pBuffer = FX_Alloc(uint8_t, dwFileSize + 1);
-  dwFileSize = pSystemFontInfo->GetFontData(hFont, 0, pBuffer, dwFileSize);
+  FT_Error retCharmap =
+      FXFT_Select_Charmap(pFace->GetRec(), FT_ENCODING_UNICODE);
+  FT_Error retIndex = FT_Get_Char_Index(pFace->GetRec(), wcUnicode);
 
-  return pdfium::MakeRetain<CFX_MemoryStream>(pBuffer, dwFileSize, true);
+  if (FXFT_Get_Face_External_Stream(pFace->GetRec()))
+    FXFT_Clear_Face_External_Stream(pFace->GetRec());
+
+  return !retCharmap && retIndex;
 }
 
-RetainPtr<IFX_SeekableReadStream> CFGAS_FontMgr::CreateFontStream(
-    const ByteString& bsFaceName) {
-  CFX_FontMgr* pFontMgr = CFX_GEModule::Get()->GetFontMgr();
-  CFX_FontMapper* pFontMapper = pFontMgr->GetBuiltinMapper();
-  if (!pFontMapper)
-    return nullptr;
-
-  IFX_SystemFontInfo* pSystemFontInfo = pFontMapper->GetSystemFontInfo();
-  if (!pSystemFontInfo)
-    return nullptr;
-
-  pSystemFontInfo->EnumFontList(pFontMapper);
-  for (int32_t i = 0; i < pFontMapper->GetFaceSize(); ++i) {
-    if (pFontMapper->GetFaceName(i) == bsFaceName)
-      return CreateFontStream(pFontMapper, pSystemFontInfo, i);
-  }
-  return nullptr;
+bool IsPartName(const WideString& name1, const WideString& name2) {
+  return name1.Contains(name2.AsStringView());
 }
 
-void CFGAS_FontMgr::MatchFonts(
-    std::vector<CFX_FontDescriptorInfo>* pMatchedFonts,
-    uint16_t wCodePage,
-    uint32_t dwFontStyles,
-    const WideString& FontName,
-    wchar_t wcUnicode) {
-  pMatchedFonts->clear();
-  for (const auto& pFont : m_InstalledFonts) {
-    int32_t nPenalty =
-        CalcPenalty(pFont.get(), wCodePage, dwFontStyles, FontName, wcUnicode);
-    if (nPenalty >= 0xffff)
-      continue;
-    pMatchedFonts->push_back({pFont.get(), nPenalty});
-    if (pMatchedFonts->size() == 0xffff)
-      break;
-  }
-  std::sort(pMatchedFonts->begin(), pMatchedFonts->end());
-}
-
-int32_t CFGAS_FontMgr::CalcPenalty(CFX_FontDescriptor* pInstalled,
-                                   uint16_t wCodePage,
-                                   uint32_t dwFontStyles,
-                                   const WideString& FontName,
-                                   wchar_t wcUnicode) {
+int32_t CalcPenalty(CFX_FontDescriptor* pInstalled,
+                    uint16_t wCodePage,
+                    uint32_t dwFontStyles,
+                    const WideString& FontName,
+                    wchar_t wcUnicode) {
   int32_t nPenalty = 30000;
   if (FontName.GetLength() != 0) {
     if (FontName != pInstalled->m_wsFaceName) {
@@ -745,11 +553,10 @@
     } else {
       nPenalty -= 30000;
     }
-    if (30000 == nPenalty &&
-        0 == IsPartName(pInstalled->m_wsFaceName, FontName)) {
+    if (nPenalty == 30000 && !IsPartName(pInstalled->m_wsFaceName, FontName)) {
       size_t i;
       for (i = 0; i < pInstalled->m_wsFamilyNames.size(); i++) {
-        if (IsPartName(pInstalled->m_wsFamilyNames[i], FontName) != 0)
+        if (IsPartName(pInstalled->m_wsFamilyNames[i], FontName))
           break;
       }
       if (i == pInstalled->m_wsFamilyNames.size())
@@ -761,7 +568,7 @@
     }
   }
   uint32_t dwStyleMask = pInstalled->m_dwFontStyles ^ dwFontStyles;
-  if (FontStyleIsBold(dwStyleMask))
+  if (FontStyleIsForceBold(dwStyleMask))
     nPenalty += 4500;
   if (FontStyleIsFixedPitch(dwStyleMask))
     nPenalty += 10000;
@@ -796,35 +603,155 @@
   return nPenalty;
 }
 
-void CFGAS_FontMgr::RegisterFace(FXFT_Face pFace, const WideString* pFaceName) {
-  if ((pFace->face_flags & FT_FACE_FLAG_SCALABLE) == 0)
+}  // namespace
+
+CFX_FontDescriptor::CFX_FontDescriptor()
+    : m_nFaceIndex(0), m_dwFontStyles(0), m_dwUsb(), m_dwCsb() {}
+
+CFX_FontDescriptor::~CFX_FontDescriptor() {}
+
+CFGAS_FontMgr::CFGAS_FontMgr()
+    : m_pFontSource(pdfium::MakeUnique<CFX_FontSourceEnum_File>()) {}
+
+CFGAS_FontMgr::~CFGAS_FontMgr() {}
+
+bool CFGAS_FontMgr::EnumFontsFromFontMapper() {
+  CFX_FontMapper* pFontMapper =
+      CFX_GEModule::Get()->GetFontMgr()->GetBuiltinMapper();
+  pFontMapper->LoadInstalledFonts();
+
+  for (int32_t i = 0; i < pFontMapper->GetFaceSize(); ++i) {
+    RetainPtr<IFX_SeekableReadStream> pFontStream =
+        CreateFontStream(pFontMapper, i);
+    if (!pFontStream)
+      continue;
+
+    WideString wsFaceName =
+        WideString::FromDefANSI(pFontMapper->GetFaceName(i).AsStringView());
+    RegisterFaces(pFontStream, &wsFaceName);
+  }
+
+  return !m_InstalledFonts.empty();
+}
+
+bool CFGAS_FontMgr::EnumFontsFromFiles() {
+  m_pFontSource->GetNext();
+  while (m_pFontSource->HasNext()) {
+    RetainPtr<IFX_SeekableStream> stream = m_pFontSource->GetStream();
+    if (stream)
+      RegisterFaces(stream, nullptr);
+    m_pFontSource->GetNext();
+  }
+  return !m_InstalledFonts.empty();
+}
+
+bool CFGAS_FontMgr::EnumFonts() {
+  return EnumFontsFromFontMapper() || EnumFontsFromFiles();
+}
+
+RetainPtr<CFGAS_GEFont> CFGAS_FontMgr::GetFontByUnicodeImpl(
+    wchar_t wUnicode,
+    uint32_t dwFontStyles,
+    const wchar_t* pszFontFamily,
+    uint32_t dwHash,
+    uint16_t wCodePage,
+    uint16_t /* wBitField */) {
+  std::vector<CFX_FontDescriptorInfo>* sortedFontInfos =
+      m_Hash2CandidateList[dwHash].get();
+  if (!sortedFontInfos) {
+    auto pNewFonts = pdfium::MakeUnique<std::vector<CFX_FontDescriptorInfo>>();
+    sortedFontInfos = pNewFonts.get();
+    MatchFonts(sortedFontInfos, wCodePage, dwFontStyles,
+               WideString(pszFontFamily), wUnicode);
+    m_Hash2CandidateList[dwHash] = std::move(pNewFonts);
+  }
+  for (const auto& info : *sortedFontInfos) {
+    CFX_FontDescriptor* pDesc = info.pFont;
+    if (!VerifyUnicodeForFontDescriptor(pDesc, wUnicode))
+      continue;
+    RetainPtr<CFGAS_GEFont> pFont =
+        LoadFontInternal(pDesc->m_wsFaceName, pDesc->m_nFaceIndex);
+    if (!pFont)
+      continue;
+    pFont->SetLogicalFontStyle(dwFontStyles);
+    m_Hash2Fonts[dwHash].push_back(pFont);
+    return pFont;
+  }
+  if (!pszFontFamily)
+    m_FailedUnicodesSet.insert(wUnicode);
+  return nullptr;
+}
+
+RetainPtr<CFGAS_GEFont> CFGAS_FontMgr::LoadFontInternal(
+    const WideString& wsFaceName,
+    int32_t iFaceIndex) {
+  RetainPtr<IFX_SeekableReadStream> pFontStream =
+      CreateFontStream(wsFaceName.ToUTF8());
+  if (!pFontStream)
+    return nullptr;
+
+  auto pInternalFont = pdfium::MakeUnique<CFX_Font>();
+  if (!pInternalFont->LoadFile(pFontStream, iFaceIndex))
+    return nullptr;
+
+  RetainPtr<CFGAS_GEFont> pFont =
+      CFGAS_GEFont::LoadFont(std::move(pInternalFont), this);
+  if (!pFont)
+    return nullptr;
+
+  m_IFXFont2FileRead[pFont] = pFontStream;
+  return pFont;
+}
+
+void CFGAS_FontMgr::MatchFonts(
+    std::vector<CFX_FontDescriptorInfo>* pMatchedFonts,
+    uint16_t wCodePage,
+    uint32_t dwFontStyles,
+    const WideString& FontName,
+    wchar_t wcUnicode) {
+  pMatchedFonts->clear();
+  for (const auto& pFont : m_InstalledFonts) {
+    int32_t nPenalty =
+        CalcPenalty(pFont.get(), wCodePage, dwFontStyles, FontName, wcUnicode);
+    if (nPenalty >= 0xffff)
+      continue;
+    pMatchedFonts->push_back({pFont.get(), nPenalty});
+    if (pMatchedFonts->size() == 0xffff)
+      break;
+  }
+  std::sort(pMatchedFonts->begin(), pMatchedFonts->end());
+}
+
+void CFGAS_FontMgr::RegisterFace(RetainPtr<CFX_Face> pFace,
+                                 const WideString* pFaceName) {
+  if ((pFace->GetRec()->face_flags & FT_FACE_FLAG_SCALABLE) == 0)
     return;
 
   auto pFont = pdfium::MakeUnique<CFX_FontDescriptor>();
-  pFont->m_dwFontStyles |= FXFT_Is_Face_Bold(pFace) ? FXFONT_BOLD : 0;
-  pFont->m_dwFontStyles |= FXFT_Is_Face_Italic(pFace) ? FXFONT_ITALIC : 0;
-  pFont->m_dwFontStyles |= GetFlags(pFace);
+  pFont->m_dwFontStyles |= GetFlags(pFace->GetRec());
 
-  std::vector<uint16_t> charsets = GetCharsets(pFace);
-  GetUSBCSB(pFace, pFont->m_dwUsb, pFont->m_dwCsb);
+  GetUSBCSB(pFace->GetRec(), pFont->m_dwUsb, pFont->m_dwCsb);
 
   FT_ULong dwTag;
   FT_ENC_TAG(dwTag, 'n', 'a', 'm', 'e');
 
   std::vector<uint8_t> table;
   unsigned long nLength = 0;
-  unsigned int error = FXFT_Load_Sfnt_Table(pFace, dwTag, 0, nullptr, &nLength);
+  unsigned int error =
+      FT_Load_Sfnt_Table(pFace->GetRec(), dwTag, 0, nullptr, &nLength);
   if (error == 0 && nLength != 0) {
     table.resize(nLength);
-    if (FXFT_Load_Sfnt_Table(pFace, dwTag, 0, table.data(), nullptr))
+    if (FT_Load_Sfnt_Table(pFace->GetRec(), dwTag, 0, table.data(), nullptr))
       table.clear();
   }
-  GetNames(table.empty() ? nullptr : table.data(), pFont->m_wsFamilyNames);
-  pFont->m_wsFamilyNames.push_back(ByteString(pFace->family_name).UTF8Decode());
+  pFont->m_wsFamilyNames = GetNames(table.empty() ? nullptr : table.data());
+  pFont->m_wsFamilyNames.push_back(
+      WideString::FromUTF8(pFace->GetRec()->family_name));
   pFont->m_wsFaceName =
-      pFaceName ? *pFaceName
-                : WideString::FromLocal(FXFT_Get_Postscript_Name(pFace));
-  pFont->m_nFaceIndex = pFace->face_index;
+      pFaceName
+          ? *pFaceName
+          : WideString::FromDefANSI(FT_Get_Postscript_Name(pFace->GetRec()));
+  pFont->m_nFaceIndex = pFace->GetRec()->face_index;
   m_InstalledFonts.push_back(std::move(pFont));
 }
 
@@ -834,119 +761,19 @@
   int32_t index = 0;
   int32_t num_faces = 0;
   do {
-    FXFT_Face pFace = LoadFace(pFontStream, index++);
+    RetainPtr<CFX_Face> pFace = LoadFace(pFontStream, index++);
     if (!pFace)
       continue;
     // All faces keep number of faces. It can be retrieved from any one face.
     if (num_faces == 0)
-      num_faces = pFace->num_faces;
+      num_faces = pFace->GetRec()->num_faces;
     RegisterFace(pFace, pFaceName);
-    if (FXFT_Get_Face_External_Stream(pFace))
-      FXFT_Clear_Face_External_Stream(pFace);
-    FXFT_Done_Face(pFace);
+    if (FXFT_Get_Face_External_Stream(pFace->GetRec()))
+      FXFT_Clear_Face_External_Stream(pFace->GetRec());
   } while (index < num_faces);
 }
 
-uint32_t CFGAS_FontMgr::GetFlags(FXFT_Face pFace) {
-  uint32_t flag = 0;
-  if (FT_IS_FIXED_WIDTH(pFace))
-    flag |= FXFONT_FIXED_PITCH;
-  TT_OS2* pOS2 = (TT_OS2*)FT_Get_Sfnt_Table(pFace, ft_sfnt_os2);
-  if (!pOS2)
-    return flag;
-
-  if (pOS2->ulCodePageRange1 & (1 << 31))
-    flag |= FXFONT_SYMBOLIC;
-  if (pOS2->panose[0] == 2) {
-    uint8_t uSerif = pOS2->panose[1];
-    if ((uSerif > 1 && uSerif < 10) || uSerif > 13)
-      flag |= FXFONT_SERIF;
-  }
-  return flag;
-}
-
-void CFGAS_FontMgr::GetNames(const uint8_t* name_table,
-                             std::vector<WideString>& Names) {
-  if (!name_table)
-    return;
-
-  uint8_t* lpTable = (uint8_t*)name_table;
-  WideString wsFamily;
-  uint8_t* sp = lpTable + 2;
-  uint8_t* lpNameRecord = lpTable + 6;
-  uint16_t nNameCount = GetUInt16(sp);
-  uint8_t* lpStr = lpTable + GetUInt16(sp + 2);
-  for (uint16_t j = 0; j < nNameCount; j++) {
-    uint16_t nNameID = GetUInt16(lpNameRecord + j * 12 + 6);
-    if (nNameID != 1)
-      continue;
-
-    uint16_t nPlatformID = GetUInt16(lpNameRecord + j * 12 + 0);
-    uint16_t nNameLength = GetUInt16(lpNameRecord + j * 12 + 8);
-    uint16_t nNameOffset = GetUInt16(lpNameRecord + j * 12 + 10);
-    wsFamily.clear();
-    if (nPlatformID != 1) {
-      for (uint16_t k = 0; k < nNameLength / 2; k++) {
-        wchar_t wcTemp = GetUInt16(lpStr + nNameOffset + k * 2);
-        wsFamily += wcTemp;
-      }
-      Names.push_back(wsFamily);
-      continue;
-    }
-    for (uint16_t k = 0; k < nNameLength; k++) {
-      wchar_t wcTemp = GetUInt8(lpStr + nNameOffset + k);
-      wsFamily += wcTemp;
-    }
-    Names.push_back(wsFamily);
-  }
-}
-
-std::vector<uint16_t> CFGAS_FontMgr::GetCharsets(FXFT_Face pFace) const {
-  std::vector<uint16_t> charsets;
-  TT_OS2* pOS2 = (TT_OS2*)FT_Get_Sfnt_Table(pFace, ft_sfnt_os2);
-  if (!pOS2) {
-    charsets.push_back(FX_CHARSET_Default);
-    return charsets;
-  }
-  uint16_t a[4] = {
-      pOS2->ulCodePageRange1 & 0xffff, (pOS2->ulCodePageRange1 >> 16) & 0xffff,
-      pOS2->ulCodePageRange2 & 0xffff, (pOS2->ulCodePageRange2 >> 16) & 0xffff};
-  for (int n = 0; n < 4; n++) {
-    for (int32_t i = 0; i < 16; i++) {
-      if ((a[n] & g_FX_Bit2Charset[n][i].wBit) != 0)
-        charsets.push_back(g_FX_Bit2Charset[n][i].wCharset);
-    }
-  }
-  return charsets;
-}
-
-void CFGAS_FontMgr::GetUSBCSB(FXFT_Face pFace, uint32_t* USB, uint32_t* CSB) {
-  TT_OS2* pOS2 = (TT_OS2*)FT_Get_Sfnt_Table(pFace, ft_sfnt_os2);
-  if (!pOS2) {
-    USB[0] = 0;
-    USB[1] = 0;
-    USB[2] = 0;
-    USB[3] = 0;
-    CSB[0] = 0;
-    CSB[1] = 0;
-    return;
-  }
-  USB[0] = pOS2->ulUnicodeRange1;
-  USB[1] = pOS2->ulUnicodeRange2;
-  USB[2] = pOS2->ulUnicodeRange3;
-  USB[3] = pOS2->ulUnicodeRange4;
-  CSB[0] = pOS2->ulCodePageRange1;
-  CSB[1] = pOS2->ulCodePageRange2;
-}
-
-int32_t CFGAS_FontMgr::IsPartName(const WideString& Name1,
-                                  const WideString& Name2) {
-  if (Name1.Contains(Name2.c_str()))
-    return 1;
-  return 0;
-}
-
-#endif  // _FX_PLATFORM_ == _FX_PLATFORM_WINDOWS_
+#endif  // defined(OS_WIN)
 
 RetainPtr<CFGAS_GEFont> CFGAS_FontMgr::GetFontByCodePage(
     uint16_t wCodePage,
@@ -955,11 +782,16 @@
   ByteString bsHash = ByteString::Format("%d, %d", wCodePage, dwFontStyles);
   bsHash += FX_UTF8Encode(WideStringView(pszFontFamily));
   uint32_t dwHash = FX_HashCode_GetA(bsHash.AsStringView(), false);
-  std::vector<RetainPtr<CFGAS_GEFont>>* pFontArray = &m_Hash2Fonts[dwHash];
-  if (!pFontArray->empty())
-    return (*pFontArray)[0];
+  auto* pFontVector = &m_Hash2Fonts[dwHash];
+  if (!pFontVector->empty()) {
+    for (auto iter = pFontVector->begin(); iter != pFontVector->end(); ++iter) {
+      if (*iter != nullptr)
+        return *iter;
+    }
+    return nullptr;
+  }
 
-#if _FX_PLATFORM_ == _FX_PLATFORM_WINDOWS_
+#if defined(OS_WIN)
   const FX_FONTDESCRIPTOR* pFD =
       FindFont(pszFontFamily, dwFontStyles, true, wCodePage, 999, 0);
   if (!pFD)
@@ -971,7 +803,7 @@
 
   RetainPtr<CFGAS_GEFont> pFont =
       CFGAS_GEFont::LoadFont(pFD->wsFontFace, dwFontStyles, wCodePage, this);
-#else   // _FX_PLATFORM_ == _FX_PLATFORM_WINDOWS_
+#else   // defined(OS_WIN)
   std::vector<CFX_FontDescriptorInfo>* sortedFontInfos =
       m_Hash2CandidateList[dwHash].get();
   if (!sortedFontInfos) {
@@ -986,14 +818,14 @@
 
   CFX_FontDescriptor* pDesc = (*sortedFontInfos)[0].pFont;
   RetainPtr<CFGAS_GEFont> pFont =
-      LoadFont(pDesc->m_wsFaceName, pDesc->m_nFaceIndex, nullptr);
-#endif  // _FX_PLATFORM_ == _FX_PLATFORM_WINDOWS_
+      LoadFontInternal(pDesc->m_wsFaceName, pDesc->m_nFaceIndex);
+#endif  // defined(OS_WIN)
 
   if (!pFont)
     return nullptr;
 
   pFont->SetLogicalFontStyle(dwFontStyles);
-  pFontArray->push_back(pFont);
+  pFontVector->push_back(pFont);
   return pFont;
 }
 
@@ -1001,10 +833,8 @@
     wchar_t wUnicode,
     uint32_t dwFontStyles,
     const wchar_t* pszFontFamily) {
-#if _FX_PLATFORM_ != _FX_PLATFORM_WINDOWS_
   if (pdfium::ContainsKey(m_FailedUnicodesSet, wUnicode))
     return nullptr;
-#endif  // _FX_PLATFORM_ != _FX_PLATFORM_WINDOWS_
 
   const FGAS_FONTUSB* x = FGAS_GetUnicodeBitField(wUnicode);
   uint16_t wCodePage = x ? x->wCodePage : 0xFFFF;
@@ -1018,80 +848,20 @@
   }
   bsHash += FX_UTF8Encode(WideStringView(pszFontFamily));
   uint32_t dwHash = FX_HashCode_GetA(bsHash.AsStringView(), false);
-  std::vector<RetainPtr<CFGAS_GEFont>>* pFonts = &m_Hash2Fonts[dwHash];
-  for (size_t i = 0; i < pFonts->size(); ++i) {
-    if (VerifyUnicode((*pFonts)[i], wUnicode))
-      return (*pFonts)[i];
+  std::vector<RetainPtr<CFGAS_GEFont>>& fonts = m_Hash2Fonts[dwHash];
+  for (auto& pFont : fonts) {
+    if (VerifyUnicode(pFont, wUnicode))
+      return pFont;
   }
-#if _FX_PLATFORM_ == _FX_PLATFORM_WINDOWS_
-  const FX_FONTDESCRIPTOR* pFD = FindFont(pszFontFamily, dwFontStyles, false,
-                                          wCodePage, wBitField, wUnicode);
-  if (!pFD && pszFontFamily) {
-    pFD =
-        FindFont(nullptr, dwFontStyles, false, wCodePage, wBitField, wUnicode);
-  }
-  if (!pFD)
-    return nullptr;
 
-  uint16_t newCodePage = GetCodePageFromCharset(pFD->uCharSet);
-  const wchar_t* pFontFace = pFD->wsFontFace;
-  RetainPtr<CFGAS_GEFont> pFont =
-      CFGAS_GEFont::LoadFont(pFontFace, dwFontStyles, newCodePage, this);
-  if (!pFont)
-    return nullptr;
-
-  pFont->SetLogicalFontStyle(dwFontStyles);
-  pFonts->push_back(pFont);
-  return pFont;
-#else   // _FX_PLATFORM_ == _FX_PLATFORM_WINDOWS_
-  std::vector<CFX_FontDescriptorInfo>* sortedFontInfos =
-      m_Hash2CandidateList[dwHash].get();
-  if (!sortedFontInfos) {
-    auto pNewFonts = pdfium::MakeUnique<std::vector<CFX_FontDescriptorInfo>>();
-    sortedFontInfos = pNewFonts.get();
-    MatchFonts(sortedFontInfos, wCodePage, dwFontStyles,
-               WideString(pszFontFamily), wUnicode);
-    m_Hash2CandidateList[dwHash] = std::move(pNewFonts);
-  }
-  for (const auto& info : *sortedFontInfos) {
-    CFX_FontDescriptor* pDesc = info.pFont;
-    if (!VerifyUnicode(pDesc, wUnicode))
-      continue;
-    RetainPtr<CFGAS_GEFont> pFont =
-        LoadFont(pDesc->m_wsFaceName, pDesc->m_nFaceIndex, nullptr);
-    if (!pFont)
-      continue;
-    pFont->SetLogicalFontStyle(dwFontStyles);
-    pFonts->push_back(pFont);
-    return pFont;
-  }
-  if (!pszFontFamily)
-    m_FailedUnicodesSet.insert(wUnicode);
-  return nullptr;
-#endif  // _FX_PLATFORM_ == _FX_PLATFORM_WINDOWS_
-}
-
-bool CFGAS_FontMgr::VerifyUnicode(const RetainPtr<CFGAS_GEFont>& pFont,
-                                  wchar_t wcUnicode) {
-  if (!pFont)
-    return false;
-
-  FXFT_Face pFace = pFont->GetDevFont()->GetFace();
-  FXFT_CharMap charmap = FXFT_Get_Face_Charmap(pFace);
-  if (FXFT_Select_Charmap(pFace, FXFT_ENCODING_UNICODE) != 0)
-    return false;
-
-  if (FXFT_Get_Char_Index(pFace, wcUnicode) == 0) {
-    FXFT_Set_Charmap(pFace, charmap);
-    return false;
-  }
-  return true;
+  return GetFontByUnicodeImpl(wUnicode, dwFontStyles, pszFontFamily, dwHash,
+                              wCodePage, wBitField);
 }
 
 RetainPtr<CFGAS_GEFont> CFGAS_FontMgr::LoadFont(const wchar_t* pszFontFamily,
                                                 uint32_t dwFontStyles,
                                                 uint16_t wCodePage) {
-#if _FX_PLATFORM_ == _FX_PLATFORM_WINDOWS_
+#if defined(OS_WIN)
   ByteString bsHash = ByteString::Format("%d, %d", wCodePage, dwFontStyles);
   bsHash += FX_UTF8Encode(WideStringView(pszFontFamily));
   uint32_t dwHash = FX_HashCode_GetA(bsHash.AsStringView(), false);
@@ -1114,18 +884,18 @@
   pFont->SetLogicalFontStyle(dwFontStyles);
   pFontArray->push_back(pFont);
   return pFont;
-#else   // _FX_PLATFORM_ == _FX_PLATFORM_WINDOWS_
+#else   // defined(OS_WIN)
   return GetFontByCodePage(wCodePage, dwFontStyles, pszFontFamily);
-#endif  // _FX_PLATFORM_ == _FX_PLATFORM_WINDOWS_
+#endif  // defined(OS_WIN)
 }
 
 void CFGAS_FontMgr::RemoveFont(const RetainPtr<CFGAS_GEFont>& pEFont) {
   if (!pEFont)
     return;
 
-#if _FX_PLATFORM_ != _FX_PLATFORM_WINDOWS_
+#if !defined(OS_WIN)
   m_IFXFont2FileRead.erase(pEFont);
-#endif  // _FX_PLATFORM_ != _FX_PLATFORM_WINDOWS_
+#endif
 
   auto iter = m_Hash2Fonts.begin();
   while (iter != m_Hash2Fonts.end()) {
diff --git a/xfa/fgas/font/cfgas_fontmgr.h b/xfa/fgas/font/cfgas_fontmgr.h
index 445b318..bc7768e 100644
--- a/xfa/fgas/font/cfgas_fontmgr.h
+++ b/xfa/fgas/font/cfgas_fontmgr.h
@@ -11,22 +11,22 @@
 #include <map>
 #include <memory>
 #include <set>
-#include <utility>
 #include <vector>
 
-#include "core/fxcrt/cfx_seekablestreamproxy.h"
+#include "build/build_config.h"
 #include "core/fxcrt/fx_extension.h"
-#include "core/fxcrt/observable.h"
+#include "core/fxcrt/observed_ptr.h"
 #include "core/fxcrt/retain_ptr.h"
+#include "core/fxge/cfx_face.h"
 #include "core/fxge/fx_freetype.h"
-#include "core/fxge/ifx_systemfontinfo.h"
 #include "xfa/fgas/font/cfgas_pdffontmgr.h"
 
 class CFGAS_GEFont;
 class CFX_FontMapper;
 class CFX_FontSourceEnum_File;
+class IFX_SeekableReadStream;
 
-#if _FX_PLATFORM_ == _FX_PLATFORM_WINDOWS_
+#if defined(OS_WIN)
 struct FX_FONTMATCHPARAMS {
   const wchar_t* pwsFamily;
   uint32_t dwFontStyles;
@@ -63,11 +63,7 @@
          wcscmp(left.wsFontFace, right.wsFontFace) == 0;
 }
 
-typedef void (*FX_LPEnumAllFonts)(std::deque<FX_FONTDESCRIPTOR>* fonts,
-                                  const wchar_t* pwsFaceName,
-                                  wchar_t wUnicode);
-
-#else  // _FX_PLATFORM_ == _FX_PLATFORM_WINDOWS_
+#else  // defined(OS_WIN)
 
 class CFX_FontDescriptor {
  public:
@@ -75,9 +71,9 @@
   ~CFX_FontDescriptor();
 
   int32_t m_nFaceIndex;
+  uint32_t m_dwFontStyles;
   WideString m_wsFaceName;
   std::vector<WideString> m_wsFamilyNames;
-  uint32_t m_dwFontStyles;
   uint32_t m_dwUsb[4];
   uint32_t m_dwCsb[2];
 };
@@ -98,35 +94,9 @@
   }
 };
 
-class CFX_FontSourceEnum_File {
- public:
-  CFX_FontSourceEnum_File();
-  ~CFX_FontSourceEnum_File();
+#endif  // defined(OS_WIN)
 
-  bool HasStartPosition();
-  std::pair<bool, RetainPtr<IFX_SeekableStream>> GetNext();
-
- private:
-  struct HandleParentPath {
-    HandleParentPath() = default;
-    HandleParentPath(const HandleParentPath& x) {
-      pFileHandle = x.pFileHandle;
-      bsParentPath = x.bsParentPath;
-    }
-    FX_FileHandle* pFileHandle;
-    ByteString bsParentPath;
-  };
-
-  ByteString GetNextFile();
-
-  WideString m_wsNext;
-  std::vector<HandleParentPath> m_FolderQueue;
-  std::vector<ByteString> m_FolderPaths;
-};
-
-#endif  // _FX_PLATFORM_ == _FX_PLATFORM_WINDOWS_
-
-class CFGAS_FontMgr : public Observable<CFGAS_FontMgr> {
+class CFGAS_FontMgr final : public Observable {
  public:
   CFGAS_FontMgr();
   ~CFGAS_FontMgr();
@@ -145,7 +115,14 @@
   bool EnumFonts();
 
  private:
-#if _FX_PLATFORM_ == _FX_PLATFORM_WINDOWS_
+  RetainPtr<CFGAS_GEFont> GetFontByUnicodeImpl(wchar_t wUnicode,
+                                               uint32_t dwFontStyles,
+                                               const wchar_t* pszFontFamily,
+                                               uint32_t dwHash,
+                                               uint16_t wCodePage,
+                                               uint16_t wBitField);
+
+#if defined(OS_WIN)
   const FX_FONTDESCRIPTOR* FindFont(const wchar_t* pszFontFamily,
                                     uint32_t dwFontStyles,
                                     bool matchParagraphStyle,
@@ -153,54 +130,34 @@
                                     uint32_t dwUSB,
                                     wchar_t wUnicode);
 
-  FX_LPEnumAllFonts m_pEnumerator;
-  std::deque<FX_FONTDESCRIPTOR> m_FontFaces;
-#else   // _FX_PLATFORM_ == _FX_PLATFORM_WINDOWS_
+#else   // defined(OS_WIN)
   bool EnumFontsFromFontMapper();
   bool EnumFontsFromFiles();
-  void RegisterFace(FXFT_Face pFace, const WideString* pFaceName);
+  void RegisterFace(RetainPtr<CFX_Face> pFace, const WideString* pFaceName);
   void RegisterFaces(const RetainPtr<IFX_SeekableReadStream>& pFontStream,
                      const WideString* pFaceName);
-  void GetNames(const uint8_t* name_table, std::vector<WideString>& Names);
-  std::vector<uint16_t> GetCharsets(FXFT_Face pFace) const;
-  void GetUSBCSB(FXFT_Face pFace, uint32_t* USB, uint32_t* CSB);
-  uint32_t GetFlags(FXFT_Face pFace);
-  bool VerifyUnicode(CFX_FontDescriptor* pDesc, wchar_t wcUnicode);
-  int32_t IsPartName(const WideString& Name1, const WideString& Name2);
   void MatchFonts(std::vector<CFX_FontDescriptorInfo>* MatchedFonts,
                   uint16_t wCodePage,
                   uint32_t dwFontStyles,
                   const WideString& FontName,
-                  wchar_t wcUnicode = 0xFFFE);
-  int32_t CalcPenalty(CFX_FontDescriptor* pInstalled,
-                      uint16_t wCodePage,
-                      uint32_t dwFontStyles,
-                      const WideString& FontName,
-                      wchar_t wcUnicode = 0xFFFE);
-  RetainPtr<CFGAS_GEFont> LoadFont(const WideString& wsFaceName,
-                                   int32_t iFaceIndex,
-                                   int32_t* pFaceCount);
-  FXFT_Face LoadFace(const RetainPtr<IFX_SeekableReadStream>& pFontStream,
-                     int32_t iFaceIndex);
-  RetainPtr<IFX_SeekableReadStream> CreateFontStream(
-      CFX_FontMapper* pFontMapper,
-      IFX_SystemFontInfo* pSystemFontInfo,
-      uint32_t index);
-  RetainPtr<IFX_SeekableReadStream> CreateFontStream(
-      const ByteString& bsFaceName);
+                  wchar_t wcUnicode);
+  RetainPtr<CFGAS_GEFont> LoadFontInternal(const WideString& wsFaceName,
+                                           int32_t iFaceIndex);
+#endif  // defined(OS_WIN)
 
+  std::map<uint32_t, std::vector<RetainPtr<CFGAS_GEFont>>> m_Hash2Fonts;
+  std::set<wchar_t> m_FailedUnicodesSet;
+
+#if defined(OS_WIN)
+  std::deque<FX_FONTDESCRIPTOR> m_FontFaces;
+#else
   std::unique_ptr<CFX_FontSourceEnum_File> m_pFontSource;
   std::vector<std::unique_ptr<CFX_FontDescriptor>> m_InstalledFonts;
   std::map<uint32_t, std::unique_ptr<std::vector<CFX_FontDescriptorInfo>>>
       m_Hash2CandidateList;
   std::map<RetainPtr<CFGAS_GEFont>, RetainPtr<IFX_SeekableReadStream>>
       m_IFXFont2FileRead;
-  std::set<wchar_t> m_FailedUnicodesSet;
-#endif  // _FX_PLATFORM_ == _FX_PLATFORM_WINDOWS_
-
-  bool VerifyUnicode(const RetainPtr<CFGAS_GEFont>& pFont, wchar_t wcUnicode);
-
-  std::map<uint32_t, std::vector<RetainPtr<CFGAS_GEFont>>> m_Hash2Fonts;
+#endif  // defined(OS_WIN)
 };
 
 #endif  // XFA_FGAS_FONT_CFGAS_FONTMGR_H_
diff --git a/xfa/fgas/font/cfgas_gefont.cpp b/xfa/fgas/font/cfgas_gefont.cpp
index 83b7ad6..5a7c625 100644
--- a/xfa/fgas/font/cfgas_gefont.cpp
+++ b/xfa/fgas/font/cfgas_gefont.cpp
@@ -9,11 +9,13 @@
 #include <memory>
 #include <utility>
 
+#include "build/build_config.h"
+#include "core/fpdfapi/font/cpdf_font.h"
 #include "core/fxcrt/fx_codepage.h"
 #include "core/fxge/cfx_font.h"
 #include "core/fxge/cfx_substfont.h"
-#include "core/fxge/cfx_unicodeencoding.h"
 #include "core/fxge/cfx_unicodeencodingex.h"
+#include "core/fxge/fx_font.h"
 #include "third_party/base/ptr_util.h"
 #include "xfa/fgas/font/fgas_fontutils.h"
 
@@ -22,25 +24,26 @@
                                                uint32_t dwFontStyles,
                                                uint16_t wCodePage,
                                                CFGAS_FontMgr* pFontMgr) {
-#if _FX_PLATFORM_ != _FX_PLATFORM_WINDOWS_
-  if (!pFontMgr)
-    return nullptr;
-
-  return pFontMgr->GetFontByCodePage(wCodePage, dwFontStyles, pszFontFamily);
-#else
+#if defined(OS_WIN)
   auto pFont = pdfium::MakeRetain<CFGAS_GEFont>(pFontMgr);
   if (!pFont->LoadFontInternal(pszFontFamily, dwFontStyles, wCodePage))
     return nullptr;
   return pFont;
+#else
+  if (!pFontMgr)
+    return nullptr;
+  return pFontMgr->GetFontByCodePage(wCodePage, dwFontStyles, pszFontFamily);
 #endif
 }
 
 // static
-RetainPtr<CFGAS_GEFont> CFGAS_GEFont::LoadFont(CFX_Font* pExternalFont,
-                                               CFGAS_FontMgr* pFontMgr) {
+RetainPtr<CFGAS_GEFont> CFGAS_GEFont::LoadFont(
+    const RetainPtr<CPDF_Font>& pPDFFont,
+    CFGAS_FontMgr* pFontMgr) {
   auto pFont = pdfium::MakeRetain<CFGAS_GEFont>(pFontMgr);
-  if (!pFont->LoadFontInternal(pExternalFont))
+  if (!pFont->LoadFontInternal(pPDFFont))
     return nullptr;
+
   return pFont;
 }
 
@@ -54,21 +57,21 @@
   return pFont;
 }
 
-CFGAS_GEFont::CFGAS_GEFont(CFGAS_FontMgr* pFontMgr)
-    :
-      m_bUseLogFontStyle(false),
-      m_dwLogFontStyle(0),
-      m_pFont(nullptr),
-      m_bExternalFont(false),
-      m_pFontMgr(pFontMgr) {
+// static
+RetainPtr<CFGAS_GEFont> CFGAS_GEFont::LoadStockFont(
+    CPDF_Document* pDoc,
+    CFGAS_FontMgr* pMgr,
+    const ByteString& font_family) {
+  RetainPtr<CPDF_Font> stock_font =
+      CPDF_Font::GetStockFont(pDoc, font_family.AsStringView());
+  return stock_font ? CFGAS_GEFont::LoadFont(stock_font, pMgr) : nullptr;
 }
 
-CFGAS_GEFont::~CFGAS_GEFont() {
-  if (!m_bExternalFont)
-    delete m_pFont;
-}
+CFGAS_GEFont::CFGAS_GEFont(CFGAS_FontMgr* pFontMgr) : m_pFontMgr(pFontMgr) {}
 
-#if _FX_PLATFORM_ == _FX_PLATFORM_WINDOWS_
+CFGAS_GEFont::~CFGAS_GEFont() = default;
+
+#if defined(OS_WIN)
 bool CFGAS_GEFont::LoadFontInternal(const wchar_t* pszFontFamily,
                                     uint32_t dwFontStyles,
                                     uint16_t wCodePage) {
@@ -76,41 +79,42 @@
     return false;
   ByteString csFontFamily;
   if (pszFontFamily)
-    csFontFamily = ByteString::FromUnicode(pszFontFamily);
+    csFontFamily = WideString(pszFontFamily).ToDefANSI();
 
   int32_t iWeight =
-      FontStyleIsBold(dwFontStyles) ? FXFONT_FW_BOLD : FXFONT_FW_NORMAL;
-  m_pFont = new CFX_Font;
-  if (FontStyleIsItalic(dwFontStyles) && FontStyleIsBold(dwFontStyles))
+      FontStyleIsForceBold(dwFontStyles) ? FXFONT_FW_BOLD : FXFONT_FW_NORMAL;
+  m_pFont = pdfium::MakeUnique<CFX_Font>();
+  if (FontStyleIsItalic(dwFontStyles) && FontStyleIsForceBold(dwFontStyles))
     csFontFamily += ",BoldItalic";
-  else if (FontStyleIsBold(dwFontStyles))
+  else if (FontStyleIsForceBold(dwFontStyles))
     csFontFamily += ",Bold";
   else if (FontStyleIsItalic(dwFontStyles))
     csFontFamily += ",Italic";
 
   m_pFont->LoadSubst(csFontFamily, true, dwFontStyles, iWeight, 0, wCodePage,
                      false);
-  if (!m_pFont->GetFace())
-    return false;
-  return InitFont();
+  return m_pFont->GetFaceRec() && InitFont();
 }
-#endif  // _FX_PLATFORM_ == _FX_PLATFORM_WINDOWS_
+#endif  // defined(OS_WIN)
 
-bool CFGAS_GEFont::LoadFontInternal(CFX_Font* pExternalFont) {
+bool CFGAS_GEFont::LoadFontInternal(const RetainPtr<CPDF_Font>& pPDFFont) {
+  CFX_Font* pExternalFont = pPDFFont->GetFont();
   if (m_pFont || !pExternalFont)
     return false;
 
   m_pFont = pExternalFont;
-  m_bExternalFont = true;
-  return InitFont();
+  if (!InitFont())
+    return false;
+
+  m_pPDFFont = pPDFFont;  // Keep pPDFFont alive for the duration.
+  return true;
 }
 
 bool CFGAS_GEFont::LoadFontInternal(std::unique_ptr<CFX_Font> pInternalFont) {
   if (m_pFont || !pInternalFont)
     return false;
 
-  m_pFont = pInternalFont.release();
-  m_bExternalFont = false;
+  m_pFont = std::move(pInternalFont);
   return InitFont();
 }
 
@@ -121,71 +125,66 @@
   if (m_pFontEncoding)
     return true;
 
-  m_pFontEncoding = FX_CreateFontEncodingEx(m_pFont, FXFM_ENCODING_NONE);
+  m_pFontEncoding = FX_CreateFontEncodingEx(m_pFont.Get());
   return !!m_pFontEncoding;
 }
 
 WideString CFGAS_GEFont::GetFamilyName() const {
-  if (!m_pFont->GetSubstFont() ||
-      m_pFont->GetSubstFont()->m_Family.GetLength() == 0) {
-    return WideString::FromLocal(m_pFont->GetFamilyName().AsStringView());
-  }
-  return WideString::FromLocal(
-      m_pFont->GetSubstFont()->m_Family.AsStringView());
+  CFX_SubstFont* subst_font = m_pFont->GetSubstFont();
+  ByteString family_name = subst_font && !subst_font->m_Family.IsEmpty()
+                               ? subst_font->m_Family
+                               : m_pFont->GetFamilyName();
+  return WideString::FromDefANSI(family_name.AsStringView());
 }
 
 uint32_t CFGAS_GEFont::GetFontStyles() const {
   ASSERT(m_pFont);
-  if (m_bUseLogFontStyle)
-    return m_dwLogFontStyle;
+  if (m_dwLogFontStyle.has_value())
+    return m_dwLogFontStyle.value();
 
   uint32_t dwStyles = 0;
   auto* pSubstFont = m_pFont->GetSubstFont();
   if (pSubstFont) {
     if (pSubstFont->m_Weight == FXFONT_FW_BOLD)
-      dwStyles |= FXFONT_BOLD;
-    if (pSubstFont->m_bFlagItalic)
-      dwStyles |= FXFONT_ITALIC;
+      dwStyles |= FXFONT_FORCE_BOLD;
   } else {
     if (m_pFont->IsBold())
-      dwStyles |= FXFONT_BOLD;
+      dwStyles |= FXFONT_FORCE_BOLD;
     if (m_pFont->IsItalic())
       dwStyles |= FXFONT_ITALIC;
   }
   return dwStyles;
 }
 
-bool CFGAS_GEFont::GetCharWidth(wchar_t wUnicode, int32_t& iWidth) {
+bool CFGAS_GEFont::GetCharWidth(wchar_t wUnicode, int32_t* pWidth) {
   auto it = m_CharWidthMap.find(wUnicode);
-  iWidth = it != m_CharWidthMap.end() ? it->second : 0;
-  if (iWidth == 65535)
+  *pWidth = it != m_CharWidthMap.end() ? it->second : 0;
+  if (*pWidth == 65535)
     return false;
 
-  if (iWidth > 0)
+  if (*pWidth > 0)
     return true;
 
-  if (!m_pProvider || !m_pProvider->GetCharWidth(RetainPtr<CFGAS_GEFont>(this),
-                                                 wUnicode, &iWidth)) {
-    RetainPtr<CFGAS_GEFont> pFont;
-    int32_t iGlyph;
-    std::tie(iGlyph, pFont) = GetGlyphIndexAndFont(wUnicode, true);
-    if (iGlyph != 0xFFFF && pFont) {
-      if (pFont.Get() == this) {
-        iWidth = m_pFont->GetGlyphWidth(iGlyph);
-        if (iWidth < 0)
-          iWidth = -1;
-      } else if (pFont->GetCharWidth(wUnicode, iWidth)) {
-        return true;
-      }
-    } else {
-      iWidth = -1;
+  RetainPtr<CFGAS_GEFont> pFont;
+  int32_t iGlyph;
+  std::tie(iGlyph, pFont) = GetGlyphIndexAndFont(wUnicode, true);
+  if (iGlyph != 0xFFFF && pFont) {
+    if (pFont == this) {
+      *pWidth = m_pFont->GetGlyphWidth(iGlyph);
+      if (*pWidth < 0)
+        *pWidth = -1;
+    } else if (pFont->GetCharWidth(wUnicode, pWidth)) {
+      return true;
     }
+  } else {
+    *pWidth = -1;
   }
-  m_CharWidthMap[wUnicode] = iWidth;
-  return iWidth > 0;
+
+  m_CharWidthMap[wUnicode] = *pWidth;
+  return *pWidth > 0;
 }
 
-bool CFGAS_GEFont::GetCharBBox(wchar_t wUnicode, CFX_Rect* bbox) {
+bool CFGAS_GEFont::GetCharBBox(wchar_t wUnicode, FX_RECT* bbox) {
   auto it = m_BBoxMap.find(wUnicode);
   if (it != m_BBoxMap.end()) {
     *bbox = it->second;
@@ -202,25 +201,16 @@
     return pFont->GetCharBBox(wUnicode, bbox);
 
   FX_RECT rtBBox;
-  if (!m_pFont->GetGlyphBBox(iGlyph, rtBBox))
+  if (!m_pFont->GetGlyphBBox(iGlyph, &rtBBox))
     return false;
 
-  CFX_Rect rt(rtBBox.left, rtBBox.top, rtBBox.Width(), rtBBox.Height());
-  m_BBoxMap[wUnicode] = rt;
-  *bbox = rt;
+  m_BBoxMap[wUnicode] = rtBBox;
+  *bbox = rtBBox;
   return true;
 }
 
-bool CFGAS_GEFont::GetBBox(CFX_Rect* bbox) {
-  FX_RECT rt(0, 0, 0, 0);
-  if (!m_pFont->GetBBox(rt))
-    return false;
-
-  bbox->left = rt.left;
-  bbox->width = rt.Width();
-  bbox->top = rt.bottom;
-  bbox->height = -rt.Height();
-  return true;
+bool CFGAS_GEFont::GetBBox(FX_RECT* bbox) {
+  return m_pFont->GetBBox(bbox);
 }
 
 int32_t CFGAS_GEFont::GetGlyphIndex(wchar_t wUnicode) {
@@ -235,7 +225,7 @@
     bool bRecursive) {
   int32_t iGlyphIndex = m_pFontEncoding->GlyphFromCharCode(wUnicode);
   if (iGlyphIndex > 0)
-    return {iGlyphIndex, RetainPtr<CFGAS_GEFont>(this)};
+    return {iGlyphIndex, pdfium::WrapRetain(this)};
 
   const FGAS_FONTUSB* pFontUSB = FGAS_GetUnicodeBitField(wUnicode);
   if (!pFontUSB)
@@ -263,11 +253,11 @@
   WideString wsFamily = GetFamilyName();
   RetainPtr<CFGAS_GEFont> pFont =
       m_pFontMgr->GetFontByUnicode(wUnicode, GetFontStyles(), wsFamily.c_str());
-#if _FX_PLATFORM_ != _FX_PLATFORM_WINDOWS_
+#if !defined(OS_WIN)
   if (!pFont)
     pFont = m_pFontMgr->GetFontByUnicode(wUnicode, GetFontStyles(), nullptr);
 #endif
-  if (!pFont || pFont.Get() == this)  // Avoids direct cycles below.
+  if (!pFont || pFont == this)  // Avoids direct cycles below.
     return {0xFFFF, nullptr};
 
   m_FontMapper[wUnicode] = pFont;
@@ -292,6 +282,6 @@
 RetainPtr<CFGAS_GEFont> CFGAS_GEFont::GetSubstFont(int32_t iGlyphIndex) {
   iGlyphIndex = static_cast<uint32_t>(iGlyphIndex) >> 24;
   if (iGlyphIndex == 0)
-    return RetainPtr<CFGAS_GEFont>(this);
+    return pdfium::WrapRetain(this);
   return m_SubstFonts[iGlyphIndex - 1];
 }
diff --git a/xfa/fgas/font/cfgas_gefont.h b/xfa/fgas/font/cfgas_gefont.h
index 646562d..7e021e1 100644
--- a/xfa/fgas/font/cfgas_gefont.h
+++ b/xfa/fgas/font/cfgas_gefont.h
@@ -12,18 +12,21 @@
 #include <utility>
 #include <vector>
 
-#include "core/fxcrt/fx_memory.h"
+#include "build/build_config.h"
+#include "core/fxcrt/fx_coordinates.h"
+#include "core/fxcrt/fx_system.h"
+#include "core/fxcrt/maybe_owned.h"
 #include "core/fxcrt/retain_ptr.h"
-#include "core/fxcrt/unowned_ptr.h"
+#include "third_party/base/optional.h"
 #include "xfa/fgas/font/cfgas_fontmgr.h"
-#include "xfa/fgas/font/cfgas_pdffontmgr.h"
 
-class CFX_UnicodeEncoding;
+class CFX_Font;
+class CFX_UnicodeEncodingEx;
+class CPDF_Document;
+class CPDF_Font;
 
-class CFGAS_GEFont : public Retainable {
+class CFGAS_GEFont final : public Retainable {
  public:
-  template <typename T>
-  friend class RetainPtr;
   template <typename T, typename... Args>
   friend RetainPtr<T> pdfium::MakeRetain(Args&&... args);
 
@@ -31,30 +34,29 @@
                                           uint32_t dwFontStyles,
                                           uint16_t wCodePage,
                                           CFGAS_FontMgr* pFontMgr);
-  static RetainPtr<CFGAS_GEFont> LoadFont(CFX_Font* pExternalFont,
+  static RetainPtr<CFGAS_GEFont> LoadFont(const RetainPtr<CPDF_Font>& pPDFFont,
                                           CFGAS_FontMgr* pFontMgr);
   static RetainPtr<CFGAS_GEFont> LoadFont(
       std::unique_ptr<CFX_Font> pInternalFont,
       CFGAS_FontMgr* pFontMgr);
 
+  static RetainPtr<CFGAS_GEFont> LoadStockFont(CPDF_Document* pDoc,
+                                               CFGAS_FontMgr* pMgr,
+                                               const ByteString& font_family);
+
   uint32_t GetFontStyles() const;
-  bool GetCharWidth(wchar_t wUnicode, int32_t& iWidth);
+  bool GetCharWidth(wchar_t wUnicode, int32_t* pWidth);
   int32_t GetGlyphIndex(wchar_t wUnicode);
   int32_t GetAscent() const;
   int32_t GetDescent() const;
 
-  bool GetCharBBox(wchar_t wUnicode, CFX_Rect* bbox);
-  bool GetBBox(CFX_Rect* bbox);
+  bool GetCharBBox(wchar_t wUnicode, FX_RECT* bbox);
+  bool GetBBox(FX_RECT* bbox);
 
   RetainPtr<CFGAS_GEFont> GetSubstFont(int32_t iGlyphIndex);
-  CFX_Font* GetDevFont() const { return m_pFont; }
-
-  void SetFontProvider(CFGAS_PDFFontMgr* pProvider) {
-    m_pProvider.Reset(pProvider);
-  }
+  CFX_Font* GetDevFont() const { return m_pFont.Get(); }
 
   void SetLogicalFontStyle(uint32_t dwLogFontStyle) {
-    m_bUseLogFontStyle = true;
     m_dwLogFontStyle = dwLogFontStyle;
   }
 
@@ -62,34 +64,27 @@
   explicit CFGAS_GEFont(CFGAS_FontMgr* pFontMgr);
   ~CFGAS_GEFont() override;
 
-#if _FX_PLATFORM_ == _FX_PLATFORM_WINDOWS_
+#if defined(OS_WIN)
   bool LoadFontInternal(const wchar_t* pszFontFamily,
                         uint32_t dwFontStyles,
                         uint16_t wCodePage);
   bool LoadFontInternal(const uint8_t* pBuffer, int32_t length);
-  bool LoadFontInternal(const RetainPtr<CFX_SeekableStreamProxy>& pFontStream,
-                        bool bSaveStream);
-#endif  // _FX_PLATFORM_ == _FX_PLATFORM_WINDOWS_
+#endif
   bool LoadFontInternal(std::unique_ptr<CFX_Font> pInternalFont);
-  bool LoadFontInternal(CFX_Font* pExternalFont);
+  bool LoadFontInternal(const RetainPtr<CPDF_Font>& pPDFFont);
   bool InitFont();
   std::pair<int32_t, RetainPtr<CFGAS_GEFont>> GetGlyphIndexAndFont(
       wchar_t wUnicode,
       bool bRecursive);
   WideString GetFamilyName() const;
 
-  bool m_bUseLogFontStyle;
-  uint32_t m_dwLogFontStyle;
-  CFX_Font* m_pFont;
-  bool m_bExternalFont;
-  RetainPtr<CFGAS_GEFont> m_pSrcFont;  // Only set by ctor, so no cycles.
-  CFGAS_FontMgr::ObservedPtr m_pFontMgr;
-  CFGAS_PDFFontMgr::ObservedPtr m_pProvider;
-  RetainPtr<CFX_SeekableStreamProxy> m_pStream;
-  RetainPtr<IFX_SeekableReadStream> m_pFileRead;
-  std::unique_ptr<CFX_UnicodeEncoding> m_pFontEncoding;
+  Optional<uint32_t> m_dwLogFontStyle;
+  RetainPtr<CPDF_Font> m_pPDFFont;  // Must come before |m_pFont|.
+  MaybeOwned<CFX_Font> m_pFont;     // Must come before |m_pFontEncoding|.
+  ObservedPtr<CFGAS_FontMgr> const m_pFontMgr;
+  std::unique_ptr<CFX_UnicodeEncodingEx> m_pFontEncoding;
   std::map<wchar_t, int32_t> m_CharWidthMap;
-  std::map<wchar_t, CFX_Rect> m_BBoxMap;
+  std::map<wchar_t, FX_RECT> m_BBoxMap;
   std::vector<RetainPtr<CFGAS_GEFont>> m_SubstFonts;
   std::map<wchar_t, RetainPtr<CFGAS_GEFont>> m_FontMapper;
 };
diff --git a/xfa/fgas/font/cfgas_pdffontmgr.cpp b/xfa/fgas/font/cfgas_pdffontmgr.cpp
index 4d34ac8..b342237 100644
--- a/xfa/fgas/font/cfgas_pdffontmgr.cpp
+++ b/xfa/fgas/font/cfgas_pdffontmgr.cpp
@@ -9,7 +9,10 @@
 #include <algorithm>
 
 #include "core/fpdfapi/font/cpdf_font.h"
+#include "core/fpdfapi/page/cpdf_docpagedata.h"
+#include "core/fpdfapi/parser/cpdf_dictionary.h"
 #include "core/fpdfapi/parser/cpdf_document.h"
+#include "core/fxge/fx_font.h"
 #include "xfa/fgas/font/cfgas_fontmgr.h"
 #include "xfa/fgas/font/cfgas_gefont.h"
 
@@ -35,7 +38,6 @@
 RetainPtr<CFGAS_GEFont> CFGAS_PDFFontMgr::FindFont(const ByteString& strPsName,
                                                    bool bBold,
                                                    bool bItalic,
-                                                   CPDF_Font** pDstPDFFont,
                                                    bool bStrictMatch) {
   CPDF_Dictionary* pFontSetDict =
       m_pDoc->GetRoot()->GetDictFor("AcroForm")->GetDictFor("DR");
@@ -48,9 +50,12 @@
 
   ByteString name = strPsName;
   name.Remove(' ');
-  for (const auto& it : *pFontSetDict) {
+
+  auto* pData = CPDF_DocPageData::FromDocument(m_pDoc.Get());
+  CPDF_DictionaryLocker locker(pFontSetDict);
+  for (const auto& it : locker) {
     const ByteString& key = it.first;
-    CPDF_Object* pObj = it.second.get();
+    CPDF_Object* pObj = it.second.Get();
     if (!PsNameMatchDRFontName(name.AsStringView(), bBold, bItalic, key,
                                bStrictMatch)) {
       continue;
@@ -59,36 +64,30 @@
     if (!pFontDict || pFontDict->GetStringFor("Type") != "Font")
       return nullptr;
 
-    CPDF_Font* pPDFFont = m_pDoc->LoadFont(pFontDict);
-    if (!pPDFFont)
+    RetainPtr<CPDF_Font> pPDFFont = pData->GetFont(pFontDict);
+    if (!pPDFFont || !pPDFFont->IsEmbedded())
       return nullptr;
 
-    if (!pPDFFont->IsEmbedded()) {
-      *pDstPDFFont = pPDFFont;
-      return nullptr;
-    }
-    return CFGAS_GEFont::LoadFont(pPDFFont->GetFont(), m_pFontMgr.Get());
+    return CFGAS_GEFont::LoadFont(pPDFFont, m_pFontMgr.Get());
   }
   return nullptr;
 }
 
-RetainPtr<CFGAS_GEFont> CFGAS_PDFFontMgr::GetFont(
-    const WideStringView& wsFontFamily,
-    uint32_t dwFontStyles,
-    CPDF_Font** pPDFFont,
-    bool bStrictMatch) {
+RetainPtr<CFGAS_GEFont> CFGAS_PDFFontMgr::GetFont(WideStringView wsFontFamily,
+                                                  uint32_t dwFontStyles,
+                                                  bool bStrictMatch) {
   uint32_t dwHashCode = FX_HashCode_GetW(wsFontFamily, false);
   ByteString strKey = ByteString::Format("%u%u", dwHashCode, dwFontStyles);
   auto it = m_FontMap.find(strKey);
   if (it != m_FontMap.end())
     return it->second;
 
-  ByteString bsPsName = ByteString::FromUnicode(WideString(wsFontFamily));
-  bool bBold = FontStyleIsBold(dwFontStyles);
+  ByteString bsPsName = WideString(wsFontFamily).ToDefANSI();
+  bool bBold = FontStyleIsForceBold(dwFontStyles);
   bool bItalic = FontStyleIsItalic(dwFontStyles);
   ByteString strFontName = PsNameToFontName(bsPsName, bBold, bItalic);
   RetainPtr<CFGAS_GEFont> pFont =
-      FindFont(strFontName, bBold, bItalic, pPDFFont, bStrictMatch);
+      FindFont(strFontName, bBold, bItalic, bStrictMatch);
   if (pFont)
     m_FontMap[strKey] = pFont;
 
@@ -111,7 +110,7 @@
   return strPsName;
 }
 
-bool CFGAS_PDFFontMgr::PsNameMatchDRFontName(const ByteStringView& bsPsName,
+bool CFGAS_PDFFontMgr::PsNameMatchDRFontName(ByteStringView bsPsName,
                                              bool bBold,
                                              bool bItalic,
                                              const ByteString& bsDRFontName,
@@ -150,7 +149,7 @@
       return false;
 
     if (iDifferLength > 1) {
-      ByteString bsDRTailer = bsDRName.Right(iDifferLength);
+      ByteString bsDRTailer = bsDRName.Last(iDifferLength);
       if (bsDRTailer == "MT" || bsDRTailer == "PSMT" ||
           bsDRTailer == "Regular" || bsDRTailer == "Reg") {
         return true;
@@ -161,17 +160,17 @@
       bool bMatch = false;
       switch (bsPsName[iPsLen - 1]) {
         case 'L':
-          if (bsDRName.Right(5) == "Light")
+          if (bsDRName.Last(5) == "Light")
             bMatch = true;
 
           break;
         case 'R':
-          if (bsDRName.Right(7) == "Regular" || bsDRName.Right(3) == "Reg")
+          if (bsDRName.Last(7) == "Regular" || bsDRName.Last(3) == "Reg")
             bMatch = true;
 
           break;
         case 'M':
-          if (bsDRName.Right(5) == "Medium")
+          if (bsDRName.Last(5) == "Medium")
             bMatch = true;
           break;
         default:
@@ -182,23 +181,3 @@
   }
   return true;
 }
-
-bool CFGAS_PDFFontMgr::GetCharWidth(const RetainPtr<CFGAS_GEFont>& pFont,
-                                    wchar_t wUnicode,
-                                    int32_t* pWidth) {
-  if (wUnicode != 0x20)
-    return false;
-
-  auto it = m_FDE2PDFFont.find(pFont);
-  if (it == m_FDE2PDFFont.end())
-    return false;
-
-  CPDF_Font* pPDFFont = it->second;
-  *pWidth = pPDFFont->GetCharWidthF(pPDFFont->CharCodeFromUnicode(wUnicode));
-  return true;
-}
-
-void CFGAS_PDFFontMgr::SetFont(const RetainPtr<CFGAS_GEFont>& pFont,
-                               CPDF_Font* pPDFFont) {
-  m_FDE2PDFFont[pFont] = pPDFFont;
-}
diff --git a/xfa/fgas/font/cfgas_pdffontmgr.h b/xfa/fgas/font/cfgas_pdffontmgr.h
index a019990..f9c56fc 100644
--- a/xfa/fgas/font/cfgas_pdffontmgr.h
+++ b/xfa/fgas/font/cfgas_pdffontmgr.h
@@ -9,41 +9,32 @@
 
 #include <map>
 
-#include "core/fpdfapi/parser/cpdf_dictionary.h"
-#include "core/fpdfapi/parser/cpdf_document.h"
 #include "core/fxcrt/fx_string.h"
-#include "core/fxcrt/observable.h"
+#include "core/fxcrt/observed_ptr.h"
 #include "core/fxcrt/retain_ptr.h"
 
 class CFGAS_FontMgr;
 class CFGAS_GEFont;
 class CPDF_Document;
-class CPDF_Font;
 
-class CFGAS_PDFFontMgr : public Observable<CFGAS_PDFFontMgr> {
+class CFGAS_PDFFontMgr final : public Observable {
  public:
   explicit CFGAS_PDFFontMgr(CPDF_Document* pDoc, CFGAS_FontMgr* pFontMgr);
   ~CFGAS_PDFFontMgr();
 
-  void SetFont(const RetainPtr<CFGAS_GEFont>& pFont, CPDF_Font* pPDFFont);
-  RetainPtr<CFGAS_GEFont> GetFont(const WideStringView& wsFontFamily,
+  RetainPtr<CFGAS_GEFont> GetFont(WideStringView wsFontFamily,
                                   uint32_t dwFontStyles,
-                                  CPDF_Font** pPDFFont,
                                   bool bStrictMatch);
-  bool GetCharWidth(const RetainPtr<CFGAS_GEFont>& pFont,
-                    wchar_t wUnicode,
-                    int32_t* pWidth);
 
  private:
   RetainPtr<CFGAS_GEFont> FindFont(const ByteString& strFamilyName,
                                    bool bBold,
                                    bool bItalic,
-                                   CPDF_Font** pPDFFont,
                                    bool bStrictMatch);
   ByteString PsNameToFontName(const ByteString& strPsName,
                               bool bBold,
                               bool bItalic);
-  bool PsNameMatchDRFontName(const ByteStringView& bsPsName,
+  bool PsNameMatchDRFontName(ByteStringView bsPsName,
                              bool bBold,
                              bool bItalic,
                              const ByteString& bsDRFontName,
@@ -51,7 +42,6 @@
 
   UnownedPtr<CPDF_Document> const m_pDoc;
   UnownedPtr<CFGAS_FontMgr> const m_pFontMgr;
-  std::map<RetainPtr<CFGAS_GEFont>, CPDF_Font*> m_FDE2PDFFont;
   std::map<ByteString, RetainPtr<CFGAS_GEFont>> m_FontMap;
 };
 
diff --git a/xfa/fgas/font/cfx_fontsourceenum_file.cpp b/xfa/fgas/font/cfx_fontsourceenum_file.cpp
new file mode 100644
index 0000000..83283ec
--- /dev/null
+++ b/xfa/fgas/font/cfx_fontsourceenum_file.cpp
@@ -0,0 +1,97 @@
+// Copyright 2018 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
+
+#include "xfa/fgas/font/cfx_fontsourceenum_file.h"
+
+#include <iterator>
+
+#include "build/build_config.h"
+
+namespace {
+
+constexpr char kFolderSeparator = '/';
+
+constexpr const char* kFontFolders[] = {
+#if _FX_PLATFORM_ == _FX_PLATFORM_LINUX_
+    "/usr/share/fonts",
+    "/usr/share/X11/fonts/Type1",
+    "/usr/share/X11/fonts/TTF",
+    "/usr/local/share/fonts",
+#elif defined(OS_MACOSX)
+    "~/Library/Fonts",
+    "/Library/Fonts",
+    "/System/Library/Fonts",
+#elif defined(OS_ANDROID)
+    "/system/fonts",
+#endif
+};
+
+}  // namespace
+
+CFX_FontSourceEnum_File::CFX_FontSourceEnum_File()
+    : m_FolderPaths(std::begin(kFontFolders), std::end(kFontFolders)) {}
+
+CFX_FontSourceEnum_File::~CFX_FontSourceEnum_File() = default;
+
+ByteString CFX_FontSourceEnum_File::GetNextFile() {
+  FX_FolderHandle* pCurHandle =
+      !m_FolderQueue.empty() ? m_FolderQueue.back().pFolderHandle : nullptr;
+  if (!pCurHandle) {
+    if (m_FolderPaths.empty())
+      return ByteString();
+    pCurHandle = FX_OpenFolder(m_FolderPaths.back().c_str());
+    HandleParentPath hpp;
+    hpp.pFolderHandle = pCurHandle;
+    hpp.bsParentPath = m_FolderPaths.back();
+    m_FolderQueue.push_back(hpp);
+  }
+  ByteString bsName;
+  bool bFolder;
+  while (true) {
+    if (!FX_GetNextFile(pCurHandle, &bsName, &bFolder)) {
+      FX_CloseFolder(pCurHandle);
+      if (!m_FolderQueue.empty())
+        m_FolderQueue.pop_back();
+      if (m_FolderQueue.empty()) {
+        if (!m_FolderPaths.empty())
+          m_FolderPaths.pop_back();
+        return !m_FolderPaths.empty() ? GetNextFile() : ByteString();
+      }
+      pCurHandle = m_FolderQueue.back().pFolderHandle;
+      continue;
+    }
+    if (bsName == "." || bsName == "..")
+      continue;
+    if (bFolder) {
+      HandleParentPath hpp;
+      hpp.bsParentPath =
+          m_FolderQueue.back().bsParentPath + kFolderSeparator + bsName;
+      hpp.pFolderHandle = FX_OpenFolder(hpp.bsParentPath.c_str());
+      if (!hpp.pFolderHandle)
+        continue;
+      m_FolderQueue.push_back(hpp);
+      pCurHandle = hpp.pFolderHandle;
+      continue;
+    }
+    bsName = m_FolderQueue.back().bsParentPath + kFolderSeparator + bsName;
+    break;
+  }
+  return bsName;
+}
+
+void CFX_FontSourceEnum_File::GetNext() {
+  m_wsNext = WideString::FromUTF8(GetNextFile().AsStringView());
+}
+
+bool CFX_FontSourceEnum_File::HasNext() const {
+  return !m_wsNext.IsEmpty();
+}
+
+RetainPtr<IFX_SeekableStream> CFX_FontSourceEnum_File::GetStream() const {
+  ASSERT(HasNext());
+  return IFX_SeekableStream::CreateFromFilename(m_wsNext.c_str(),
+                                                FX_FILEMODE_ReadOnly);
+}
diff --git a/xfa/fgas/font/cfx_fontsourceenum_file.h b/xfa/fgas/font/cfx_fontsourceenum_file.h
new file mode 100644
index 0000000..9e93a97
--- /dev/null
+++ b/xfa/fgas/font/cfx_fontsourceenum_file.h
@@ -0,0 +1,49 @@
+// Copyright 2018 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_FGAS_FONT_CFX_FONTSOURCEENUM_FILE_H_
+#define XFA_FGAS_FONT_CFX_FONTSOURCEENUM_FILE_H_
+
+#include <vector>
+
+#include "build/build_config.h"
+#include "core/fxcrt/fx_stream.h"
+#include "core/fxcrt/fx_string.h"
+#include "core/fxcrt/fx_system.h"
+#include "core/fxcrt/retain_ptr.h"
+
+#if defined(OS_WIN)
+#error "Not used on Windows"
+#endif
+
+class CFX_FontSourceEnum_File {
+ public:
+  CFX_FontSourceEnum_File();
+  ~CFX_FontSourceEnum_File();
+
+  void GetNext();
+  bool HasNext() const;
+  RetainPtr<IFX_SeekableStream> GetStream() const;
+
+ private:
+  struct HandleParentPath {
+    HandleParentPath() = default;
+    HandleParentPath(const HandleParentPath& x) {
+      pFolderHandle = x.pFolderHandle;
+      bsParentPath = x.bsParentPath;
+    }
+    FX_FolderHandle* pFolderHandle;
+    ByteString bsParentPath;
+  };
+
+  ByteString GetNextFile();
+
+  WideString m_wsNext;
+  std::vector<HandleParentPath> m_FolderQueue;
+  std::vector<ByteString> m_FolderPaths;
+};
+
+#endif  // XFA_FGAS_FONT_CFX_FONTSOURCEENUM_FILE_H_
diff --git a/xfa/fgas/font/fgas_fontutils.cpp b/xfa/fgas/font/fgas_fontutils.cpp
index 2cf56ce..cc6c922 100644
--- a/xfa/fgas/font/fgas_fontutils.cpp
+++ b/xfa/fgas/font/fgas_fontutils.cpp
@@ -6,6 +6,7 @@
 
 #include "xfa/fgas/font/fgas_fontutils.h"
 
+#include "build/build_config.h"
 #include "core/fxcrt/fx_codepage.h"
 #include "core/fxcrt/fx_extension.h"
 #include "xfa/fgas/font/cfgas_fontmgr.h"
@@ -188,1706 +189,1687 @@
     {0xFFA0, 0xFFEF, 68, 0xFFFF},
 };
 
-#if _FX_PLATFORM_ == _FX_PLATFORM_WINDOWS_
+#if defined(OS_WIN)
 const FGAS_FontInfo g_XFAFontsMap[] = {
-    {0x01d5d33e, L"SimSun", L"Arial", 0, 936},
-    {0x01e4f102, L"YouYuan", L"Arial", 1, 936},
-    {0x030549dc, L"LiSu", L"Arial", 1, 936},
-    {0x032edd44, L"Simhei", L"Arial", 1, 936},
-    {0x03eac6fc, L"PoorRichard-Regular", L"Arial", 2, 1252},
-    {0x03ed90e6, L"Nina", L"Arial", 0, 1252},
-    {0x077b56b3, L"KingsoftPhoneticPlain", L"Arial", 0, 1252},
-    {0x078ed524, L"MicrosoftSansSerif", L"Arial", 0, 1252},
-    {0x089b18a9, L"Arial", L"Arial", 0, 1252},
-    {0x0b2cad72, L"MonotypeCorsiva", L"Arial", 8, 1252},
-    {0x0bb003e7, L"Kartika", L"Arial", 2, 1252},
-    {0x0bb469df, L"VinerHandITC", L"Arial", 8, 1252},
-    {0x0bc1a851, L"SegoeUI", L"Arial", 0, 1252},
-    {0x0c112ebd, L"KozukaGothicPro-VIM", L"Arial", 0, 1252},
-    {0x0cfcb9c1, L"AdobeThai", L"Kokila,Arial Narrow", 0, 847},
-    {0x0e7de0f9, L"Playbill", L"Arial", 0, 1252},
-    {0x0eff47c3, L"STHupo", L"Arial", 0, 936},
-    {0x107ad374, L"Constantia", L"Arial", 2, 1252},
-    {0x12194c2d, L"KunstlerScript", L"Arial", 8, 1252},
-    {0x135ef6a1, L"MinionProSmBd",
-     L"Bell MT,Corbel,Times New Roman,Cambria,Berlin Sans FB", 0, 1252},
-    {0x158c4049, L"Garamond", L"Arial", 2, 1252},
-    {0x160ecb24, L"STZhongsong", L"Arial", 0, 936},
-    {0x161ed07e, L"MSGothic", L"Arial", 1, 1252},
-    {0x171d1ed1, L"SnapITC-Regular", L"Arial", 0, 1252},
-    {0x18d1188f, L"Cambria", L"Arial", 2, 1252},
-    {0x18eaf350, L"ArialUnicodeMS", L"Arial", 0, 936},
-    {0x1a92d115, L"MingLiU", L"Arial", 1, 1252},
-    {0x1cc217c6, L"TrebuchetMS", L"Arial", 0, 1252},
-    {0x1d649596, L"BasemicTimes", L"Arial", 0, 1252},
-    {0x1e34ee60, L"BellMT", L"Arial", 2, 1252},
-    {0x1eb36945, L"CooperBlack", L"Arial", 2, 1252},
-    {0x1ef7787d, L"BatangChe", L"Arial", 1, 1252},
-    {0x20b3bd3a, L"BrushScriptMT", L"Arial", 8, 1252},
-    {0x220877aa, L"Candara", L"Arial", 0, 1252},
-    {0x22135007, L"FreestyleScript-Regular", L"Arial", 8, 1252},
-    {0x251059c3, L"Chiller", L"Arial", 0, 1252},
-    {0x25bed6dd, L"MSReferenceSansSerif", L"Arial", 0, 1252},
-    {0x28154c81, L"Parchment-Regular", L"Arial", 8, 1252},
-    {0x29711eb9, L"STLiti", L"Arial", 0, 936},
-    {0x2b1993b4, L"Basemic", L"Arial", 0, 1252},
-    {0x2b316339, L"NiagaraSolid-Reg", L"Arial", 0, 1252},
-    {0x2c147529, L"FootlightMTLight", L"Arial", 0, 1252},
-    {0x2c198928, L"HarlowSolid", L"Arial", 0, 1252},
-    {0x2c6ac6b2, L"LucidaBright", L"Arial", 2, 1252},
-    {0x2c9f38e2, L"KozukaMinchoPro-VIR", L"Arial", 0, 1252},
-    {0x2d5a47b0, L"STCaiyun", L"Arial", 0, 936},
-    {0x2def26bf, L"BernardMT-Condensed", L"Arial", 0, 1252},
-    {0x2fd8930b, L"KozukaMinchoPr6NR", L"Arial", 0, 1252},
-    {0x3115525a, L"FangSong_GB2312", L"Arial", 0, 1252},
-    {0x31327817, L"MyriadPro",
-     L"Calibri,Corbel,Candara,Cambria Math,Franklin Gothic Medium,Arial "
-     L"Narrow,Times New Roman",
+    {0x01d5d33e, "SimSun", "Arial", 0, 936},
+    {0x01e4f102, "YouYuan", "Arial", 1, 936},
+    {0x030549dc, "LiSu", "Arial", 1, 936},
+    {0x032edd44, "Simhei", "Arial", 1, 936},
+    {0x03eac6fc, "PoorRichard-Regular", "Arial", 2, 1252},
+    {0x03ed90e6, "Nina", "Arial", 0, 1252},
+    {0x077b56b3, "KingsoftPhoneticPlain", "Arial", 0, 1252},
+    {0x078ed524, "MicrosoftSansSerif", "Arial", 0, 1252},
+    {0x089b18a9, "Arial", "Arial", 0, 1252},
+    {0x0b2cad72, "MonotypeCorsiva", "Arial", 8, 1252},
+    {0x0bb003e7, "Kartika", "Arial", 2, 1252},
+    {0x0bb469df, "VinerHandITC", "Arial", 8, 1252},
+    {0x0bc1a851, "SegoeUI", "Arial", 0, 1252},
+    {0x0c112ebd, "KozukaGothicPro-VIM", "Arial", 0, 1252},
+    {0x0cfcb9c1, "AdobeThai", "Kokila,Arial Narrow", 0, 847},
+    {0x0e7de0f9, "Playbill", "Arial", 0, 1252},
+    {0x0eff47c3, "STHupo", "Arial", 0, 936},
+    {0x107ad374, "Constantia", "Arial", 2, 1252},
+    {0x12194c2d, "KunstlerScript", "Arial", 8, 1252},
+    {0x135ef6a1, "MinionProSmBd",
+     "Bell MT,Corbel,Times New Roman,Cambria,Berlin Sans FB", 0, 1252},
+    {0x158c4049, "Garamond", "Arial", 2, 1252},
+    {0x160ecb24, "STZhongsong", "Arial", 0, 936},
+    {0x161ed07e, "MSGothic", "Arial", 1, 1252},
+    {0x171d1ed1, "SnapITC-Regular", "Arial", 0, 1252},
+    {0x18d1188f, "Cambria", "Arial", 2, 1252},
+    {0x18eaf350, "ArialUnicodeMS", "Arial", 0, 936},
+    {0x1a92d115, "MingLiU", "Arial", 1, 1252},
+    {0x1cc217c6, "TrebuchetMS", "Arial", 0, 1252},
+    {0x1d649596, "BasemicTimes", "Arial", 0, 1252},
+    {0x1e34ee60, "BellMT", "Arial", 2, 1252},
+    {0x1eb36945, "CooperBlack", "Arial", 2, 1252},
+    {0x1ef7787d, "BatangChe", "Arial", 1, 1252},
+    {0x20b3bd3a, "BrushScriptMT", "Arial", 8, 1252},
+    {0x220877aa, "Candara", "Arial", 0, 1252},
+    {0x22135007, "FreestyleScript-Regular", "Arial", 8, 1252},
+    {0x251059c3, "Chiller", "Arial", 0, 1252},
+    {0x25bed6dd, "MSReferenceSansSerif", "Arial", 0, 1252},
+    {0x28154c81, "Parchment-Regular", "Arial", 8, 1252},
+    {0x29711eb9, "STLiti", "Arial", 0, 936},
+    {0x2b1993b4, "Basemic", "Arial", 0, 1252},
+    {0x2b316339, "NiagaraSolid-Reg", "Arial", 0, 1252},
+    {0x2c147529, "FootlightMTLight", "Arial", 0, 1252},
+    {0x2c198928, "HarlowSolid", "Arial", 0, 1252},
+    {0x2c6ac6b2, "LucidaBright", "Arial", 2, 1252},
+    {0x2c9f38e2, "KozukaMinchoPro-VIR", "Arial", 0, 1252},
+    {0x2d5a47b0, "STCaiyun", "Arial", 0, 936},
+    {0x2def26bf, "BernardMT-Condensed", "Arial", 0, 1252},
+    {0x2fd8930b, "KozukaMinchoPr6NR", "Arial", 0, 1252},
+    {0x3115525a, "FangSong_GB2312", "Arial", 0, 1252},
+    {0x31327817, "MyriadPro",
+     "Calibri,Corbel,Candara,Cambria Math,Franklin Gothic Medium,Arial "
+     "Narrow,Times New Roman",
      0, 1252},
-    {0x32244975, L"Helvetica", L"Arial", 0, 1252},
-    {0x32ac995c, L"Terminal", L"Arial", 0, 1252},
-    {0x338d648a, L"NiagaraEngraved-Reg", L"Arial", 0, 1252},
-    {0x33bb65f2, L"Sylfaen", L"Arial", 2, 1252},
-    {0x3402c30e, L"MSPMincho", L"Arial", 2, 1252},
-    {0x3412bf31, L"SimSun-PUA", L"Arial", 0, 936},
-    {0x36eb39b9, L"BerlinSansFB", L"Arial", 0, 1252},
-    {0x36f42055, L"UniversATT", L"Microsoft Sans Serif", 0, 1252},
-    {0x3864c4f6, L"HighTowerText", L"Arial", 2, 1252},
-    {0x3a257d03, L"FangSong_GB2312", L"Arial", 0, 1252},
-    {0x3cdae668, L"FreestyleScript", L"Arial", 8, 1252},
-    {0x3d55aed7, L"Jokerman", L"Arial", 0, 1252},
-    {0x3d5b4385, L"PMingLiU", L"Arial", 2, 1252},
-    {0x3d9b7669, L"EstrangeloEdessa", L"Arial", 0, 1252},
-    {0x3e532d74, L"FranklinGothicMedium", L"Arial", 0, 1252},
-    {0x3e6aa32d, L"NSimSun", L"Arial", 1, 936},
-    {0x3f6c36a8, L"Gautami", L"Arial", 0, 1252},
-    {0x3ff32662, L"Chiller-Regular", L"Arial", 0, 1252},
-    {0x409de312, L"ModernNo.20", L"Arial", 2, 1252},
-    {0x41443c5e, L"Georgia", L"Arial", 2, 1252},
-    {0x4160ade5, L"BellGothicStdBlack",
-     L"Arial,Arial Unicode MS,Book Antiqua,Dotum,Georgia", 0, 1252},
-    {0x421976c4, L"Modern-Regular", L"Arial", 2, 1252},
-    {0x422a7252, L"Stencil", L"Arial", 0, 1252},
-    {0x42c8554f, L"Fixedsys", L"Arial", 0, 1252},
-    {0x435cb41d, L"Roman", L"Arial", 0, 1252},
-    {0x47882383, L"CourierNew", L"Arial", 1, 1252},
-    {0x480a2338, L"BerlinSansFBDemi", L"Arial", 0, 1252},
-    {0x480bf7a4, L"CourierStd", L"Courier New,Verdana", 0, 1252},
-    {0x481ad6ed, L"VladimirScript", L"Arial", 8, 1252},
-    {0x4911577a, L"YouYuan", L"Arial", 1, 936},
-    {0x4a788d72, L"STXingkai", L"Arial", 0, 936},
-    {0x4bf88566, L"SegoeCondensed", L"Arial", 0, 1252},
-    {0x4ccf51a4, L"BerlinSansFB-Reg", L"Arial", 0, 1252},
-    {0x4ea967ce, L"GulimChe", L"Arial", 1, 1252},
-    {0x4f68bd79, L"LetterGothicStd", L"Courier New,Verdana", 0, 1252},
-    {0x51a0d0e6, L"KozukaGothicPr6NM", L"Arial", 0, 1252},
-    {0x531b3dea, L"BasemicSymbol", L"Arial", 0, 1252},
-    {0x5333fd39, L"CalifornianFB-Reg", L"Arial", 2, 1252},
-    {0x53561a54, L"FZYTK--GBK1-0", L"Arial", 0, 936},
-    {0x55e0dde6, L"LucidaSansTypewriter", L"Arial", 0, 1252},
-    {0x574d4d3d, L"AdobeArabic", L"Arial Narrow", 0, 1252},
-    {0x5792e759, L"STKaiti", L"Arial", 0, 936},
-    {0x5921978e, L"LucidaSansUnicode", L"Arial", 0, 1252},
-    {0x594e2da4, L"Vrinda", L"Arial", 0, 1252},
-    {0x59baa9a2, L"KaiTi_GB2312", L"Arial", 0, 1252},
-    {0x5cfedf4f, L"BaskOldFace", L"Arial", 0, 1252},
-    {0x5f97921c, L"AdobeMyungjoStdM",
-     L"Batang,Bookman Old Style,Consolas,STZhongsong", 0, 936},
-    {0x5fefbfad, L"Batang", L"Arial", 2, 1252},
-    {0x605342b9, L"DotumChe", L"Arial", 1, 1252},
-    {0x608c5f9a, L"KaiTi_GB2312", L"Arial", 0, 936},
-    {0x61efd0d1, L"MaturaMTScriptCapitals", L"Arial", 0, 1252},
-    {0x626608a9, L"MVBoli", L"Arial", 0, 1252},
-    {0x630501a3, L"SmallFonts", L"Arial", 0, 1252},
-    {0x65d0e2a9, L"FZYTK--GBK1-0", L"Arial", 0, 936},
-    {0x669f29e1, L"FZSTK--GBK1-0", L"Arial", 0, 936},
-    {0x673a9e5f, L"Tunga", L"Arial", 0, 1252},
-    {0x691aa4ce, L"NiagaraSolid", L"Arial", 0, 1252},
-    {0x696259b7, L"Corbel", L"Arial", 0, 1252},
-    {0x696ee9be, L"STXihei", L"Arial", 0, 936},
-    {0x6c59cf69, L"Dotum", L"Arial", 0, 1252},
-    {0x707fa561, L"Gungsuh", L"Arial", 2, 1252},
-    {0x71416bb2, L"ZWAdobeF", L"Arial", 0, 1252},
-    {0x71b41801, L"Verdana", L"Arial", 0, 1252},
-    {0x73f25e4c, L"PalatinoLinotype", L"Arial", 0, 1252},
-    {0x73f4d19f, L"NiagaraEngraved", L"Arial", 0, 1252},
-    {0x74001694, L"MyriadProBlack", L"Book Antiqua,Constantia,Dotum,Georgia", 0,
+    {0x32244975, "Helvetica", "Arial", 0, 1252},
+    {0x32ac995c, "Terminal", "Arial", 0, 1252},
+    {0x338d648a, "NiagaraEngraved-Reg", "Arial", 0, 1252},
+    {0x33bb65f2, "Sylfaen", "Arial", 2, 1252},
+    {0x3402c30e, "MSPMincho", "Arial", 2, 1252},
+    {0x3412bf31, "SimSun-PUA", "Arial", 0, 936},
+    {0x36eb39b9, "BerlinSansFB", "Arial", 0, 1252},
+    {0x36f42055, "UniversATT", "Microsoft Sans Serif", 0, 1252},
+    {0x3864c4f6, "HighTowerText", "Arial", 2, 1252},
+    {0x3a257d03, "FangSong_GB2312", "Arial", 0, 1252},
+    {0x3cdae668, "FreestyleScript", "Arial", 8, 1252},
+    {0x3d55aed7, "Jokerman", "Arial", 0, 1252},
+    {0x3d5b4385, "PMingLiU", "Arial", 2, 1252},
+    {0x3d9b7669, "EstrangeloEdessa", "Arial", 0, 1252},
+    {0x3e532d74, "FranklinGothicMedium", "Arial", 0, 1252},
+    {0x3e6aa32d, "NSimSun", "Arial", 1, 936},
+    {0x3f6c36a8, "Gautami", "Arial", 0, 1252},
+    {0x3ff32662, "Chiller-Regular", "Arial", 0, 1252},
+    {0x409de312, "ModernNo.20", "Arial", 2, 1252},
+    {0x41443c5e, "Georgia", "Arial", 2, 1252},
+    {0x4160ade5, "BellGothicStdBlack",
+     "Arial,Arial Unicode MS,Book Antiqua,Dotum,Georgia", 0, 1252},
+    {0x421976c4, "Modern-Regular", "Arial", 2, 1252},
+    {0x422a7252, "Stencil", "Arial", 0, 1252},
+    {0x42c8554f, "Fixedsys", "Arial", 0, 1252},
+    {0x435cb41d, "Roman", "Arial", 0, 1252},
+    {0x47882383, "CourierNew", "Arial", 1, 1252},
+    {0x480a2338, "BerlinSansFBDemi", "Arial", 0, 1252},
+    {0x480bf7a4, "CourierStd", "Courier New,Verdana", 0, 1252},
+    {0x481ad6ed, "VladimirScript", "Arial", 8, 1252},
+    {0x4911577a, "YouYuan", "Arial", 1, 936},
+    {0x4a788d72, "STXingkai", "Arial", 0, 936},
+    {0x4bf88566, "SegoeCondensed", "Arial", 0, 1252},
+    {0x4ccf51a4, "BerlinSansFB-Reg", "Arial", 0, 1252},
+    {0x4ea967ce, "GulimChe", "Arial", 1, 1252},
+    {0x4f68bd79, "LetterGothicStd", "Courier New,Verdana", 0, 1252},
+    {0x51a0d0e6, "KozukaGothicPr6NM", "Arial", 0, 1252},
+    {0x531b3dea, "BasemicSymbol", "Arial", 0, 1252},
+    {0x5333fd39, "CalifornianFB-Reg", "Arial", 2, 1252},
+    {0x53561a54, "FZYTK--GBK1-0", "Arial", 0, 936},
+    {0x55e0dde6, "LucidaSansTypewriter", "Arial", 0, 1252},
+    {0x574d4d3d, "AdobeArabic", "Arial Narrow", 0, 1252},
+    {0x5792e759, "STKaiti", "Arial", 0, 936},
+    {0x5921978e, "LucidaSansUnicode", "Arial", 0, 1252},
+    {0x594e2da4, "Vrinda", "Arial", 0, 1252},
+    {0x59baa9a2, "KaiTi_GB2312", "Arial", 0, 1252},
+    {0x5cfedf4f, "BaskOldFace", "Arial", 0, 1252},
+    {0x5f97921c, "AdobeMyungjoStdM",
+     "Batang,Bookman Old Style,Consolas,STZhongsong", 0, 936},
+    {0x5fefbfad, "Batang", "Arial", 2, 1252},
+    {0x605342b9, "DotumChe", "Arial", 1, 1252},
+    {0x608c5f9a, "KaiTi_GB2312", "Arial", 0, 936},
+    {0x61efd0d1, "MaturaMTScriptCapitals", "Arial", 0, 1252},
+    {0x626608a9, "MVBoli", "Arial", 0, 1252},
+    {0x630501a3, "SmallFonts", "Arial", 0, 1252},
+    {0x65d0e2a9, "FZYTK--GBK1-0", "Arial", 0, 936},
+    {0x669f29e1, "FZSTK--GBK1-0", "Arial", 0, 936},
+    {0x673a9e5f, "Tunga", "Arial", 0, 1252},
+    {0x691aa4ce, "NiagaraSolid", "Arial", 0, 1252},
+    {0x696259b7, "Corbel", "Arial", 0, 1252},
+    {0x696ee9be, "STXihei", "Arial", 0, 936},
+    {0x6c59cf69, "Dotum", "Arial", 0, 1252},
+    {0x707fa561, "Gungsuh", "Arial", 2, 1252},
+    {0x71416bb2, "ZWAdobeF", "Arial", 0, 1252},
+    {0x71b41801, "Verdana", "Arial", 0, 1252},
+    {0x73f25e4c, "PalatinoLinotype", "Arial", 0, 1252},
+    {0x73f4d19f, "NiagaraEngraved", "Arial", 0, 1252},
+    {0x74001694, "MyriadProBlack", "Book Antiqua,Constantia,Dotum,Georgia", 0,
      1252},
-    {0x74b14d8f, L"Haettenschweiler", L"Arial", 0, 1252},
-    {0x74cb44ee, L"NSimSun", L"Arial", 1, 936},
-    {0x76b4d7ff, L"Shruti", L"Arial", 0, 1252},
-    {0x788b3533, L"Webdings", L"Arial", 6, 42},
-    {0x797dde99, L"MSSerif", L"Arial", 0, 1252},
-    {0x7a0f9e9e, L"MSMincho", L"Arial", 1, 1252},
-    {0x7b439caf, L"OldEnglishTextMT", L"Arial", 0, 1252},
-    {0x8213a433, L"LucidaSans-Typewriter", L"Arial", 0, 1252},
-    {0x82fec929, L"AdobeSongStdL",
-     L"Centaur,Calibri,STSong,Bell MT,Garamond,Times New Roman", 0, 936},
-    {0x83581825, L"Modern", L"Arial", 0, 1252},
-    {0x835a2823, L"Algerian", L"Arial", 0, 1252},
-    {0x83dab9f5, L"Script", L"Arial", 0, 1252},
-    {0x847b56da, L"Tahoma", L"Arial", 0, 1252},
-    {0x8a783cb2, L"SimSun-PUA", L"Arial", 0, 1252},
-    {0x8b5cac0e, L"Onyx", L"Arial", 0, 1252},
-    {0x8c6a499e, L"Gulim", L"Arial", 0, 1252},
-    {0x8e0af790, L"JuiceITC", L"Arial", 0, 1252},
-    {0x8e8d43b2, L"Centaur", L"Arial", 2, 1252},
-    {0x8ee4dcca, L"BookshelfSymbol7", L"Arial", 0, 1252},
-    {0x90794800, L"BellGothicStdLight", L"Bell MT,Calibri,Times New Roman", 0,
+    {0x74b14d8f, "Haettenschweiler", "Arial", 0, 1252},
+    {0x74cb44ee, "NSimSun", "Arial", 1, 936},
+    {0x76b4d7ff, "Shruti", "Arial", 0, 1252},
+    {0x788b3533, "Webdings", "Arial", 6, 42},
+    {0x797dde99, "MSSerif", "Arial", 0, 1252},
+    {0x7a0f9e9e, "MSMincho", "Arial", 1, 1252},
+    {0x7b439caf, "OldEnglishTextMT", "Arial", 0, 1252},
+    {0x8213a433, "LucidaSans-Typewriter", "Arial", 0, 1252},
+    {0x82fec929, "AdobeSongStd",
+     "Centaur,Calibri,STSong,Bell MT,Garamond,Times New Roman", 0, 936},
+    {0x83581825, "Modern", "Arial", 0, 1252},
+    {0x835a2823, "Algerian", "Arial", 0, 1252},
+    {0x83dab9f5, "Script", "Arial", 0, 1252},
+    {0x847b56da, "Tahoma", "Arial", 0, 1252},
+    {0x8a783cb2, "SimSun-PUA", "Arial", 0, 1252},
+    {0x8b5cac0e, "Onyx", "Arial", 0, 1252},
+    {0x8c6a499e, "Gulim", "Arial", 0, 1252},
+    {0x8e0af790, "JuiceITC", "Arial", 0, 1252},
+    {0x8e8d43b2, "Centaur", "Arial", 2, 1252},
+    {0x8ee4dcca, "BookshelfSymbol7", "Arial", 0, 1252},
+    {0x90794800, "BellGothicStdLight", "Bell MT,Calibri,Times New Roman", 0,
      1252},
-    {0x909b516a, L"Century", L"Arial", 2, 1252},
-    {0x92ae370d, L"MSOutlook", L"Arial", 4, 42},
-    {0x93c9fbf1, L"LucidaFax", L"Arial", 2, 1252},
-    {0x9565085e, L"BookAntiqua", L"Arial", 2, 1252},
-    {0x9856d95d, L"AdobeMingStdL", L"Arial,Arial Unicode MS,Cambria,BatangChe",
-     0, 949},
-    {0x9bbadd6b, L"ColonnaMT", L"Arial", 0, 1252},
-    {0x9cbd16a4, L"ShowcardGothic-Reg", L"Arial", 0, 1252},
-    {0x9d73008e, L"MSSansSerif", L"Arial", 0, 1252},
-    {0xa0607db1, L"GungsuhChe", L"Arial", 1, 1252},
-    {0xa0bcf6a1, L"LatinWide", L"Arial", 2, 1252},
-    {0xa1429b36, L"Symbol", L"Arial", 6, 42},
-    {0xa1fa5abc, L"Wingdings2", L"Arial", 6, 42},
-    {0xa1fa5abd, L"Wingdings3", L"Arial", 6, 42},
-    {0xa427bad4, L"InformalRoman-Regular", L"Arial", 8, 1252},
-    {0xa8b92ece, L"FZSTK--GBK1-0", L"Arial", 0, 936},
-    {0xa8d83ece, L"CalifornianFB", L"Arial", 2, 1252},
-    {0xaa3e082c, L"Kingsoft-Phonetic", L"Arial", 0, 1252},
-    {0xaa6bcabe, L"HarlowSolidItalic", L"Arial", 0, 1252},
-    {0xade5337c, L"MSUIGothic", L"Arial", 0, 1252},
-    {0xb08dd941, L"WideLatin", L"Arial", 2, 1252},
-    {0xb207f05d, L"PoorRichard", L"Arial", 2, 1252},
-    {0xb3bc492f, L"JuiceITC-Regular", L"Arial", 0, 1252},
-    {0xb5545399, L"Marlett", L"Arial", 4, 42},
-    {0xb5dd1ebb, L"BritannicBold", L"Arial", 0, 1252},
-    {0xb699c1c5, L"LucidaCalligraphy-Italic", L"Arial", 0, 1252},
-    {0xb725d629, L"TimesNewRoman", L"Arial", 2, 1252},
-    {0xb7eaebeb, L"AdobeHeitiStdR", L"Batang,Century,Dotum", 0, 936},
-    {0xbd29c486, L"BerlinSansFBDemi-Bold", L"Arial", 0, 1252},
-    {0xbe8a8db4, L"BookshelfSymbolSeven", L"Arial", 0, 1252},
-    {0xc16c0118, L"AdobeHebrew", L"Bell MT,Berlin Sans FB,Calibri", 0, 1252},
-    {0xc318b0af, L"MyriadProLight", L"Calibri,STFangsong,Times New Roman", 0,
+    {0x909b516a, "Century", "Arial", 2, 1252},
+    {0x92ae370d, "MSOutlook", "Arial", 4, 42},
+    {0x93c9fbf1, "LucidaFax", "Arial", 2, 1252},
+    {0x9565085e, "BookAntiqua", "Arial", 2, 1252},
+    {0x9856d95d, "AdobeMingStd", "Arial,Arial Unicode MS,Cambria,BatangChe", 0,
+     949},
+    {0x9bbadd6b, "ColonnaMT", "Arial", 0, 1252},
+    {0x9cbd16a4, "ShowcardGothic-Reg", "Arial", 0, 1252},
+    {0x9d73008e, "MSSansSerif", "Arial", 0, 1252},
+    {0xa0607db1, "GungsuhChe", "Arial", 1, 1252},
+    {0xa0bcf6a1, "LatinWide", "Arial", 2, 1252},
+    {0xa1429b36, "Symbol", "Arial", 6, 42},
+    {0xa1fa5abc, "Wingdings2", "Arial", 6, 42},
+    {0xa1fa5abd, "Wingdings3", "Arial", 6, 42},
+    {0xa427bad4, "InformalRoman-Regular", "Arial", 8, 1252},
+    {0xa8b92ece, "FZSTK--GBK1-0", "Arial", 0, 936},
+    {0xa8d83ece, "CalifornianFB", "Arial", 2, 1252},
+    {0xaa3e082c, "Kingsoft-Phonetic", "Arial", 0, 1252},
+    {0xaa6bcabe, "HarlowSolidItalic", "Arial", 0, 1252},
+    {0xade5337c, "MSUIGothic", "Arial", 0, 1252},
+    {0xb08dd941, "WideLatin", "Arial", 2, 1252},
+    {0xb207f05d, "PoorRichard", "Arial", 2, 1252},
+    {0xb3bc492f, "JuiceITC-Regular", "Arial", 0, 1252},
+    {0xb5545399, "Marlett", "Arial", 4, 42},
+    {0xb5dd1ebb, "BritannicBold", "Arial", 0, 1252},
+    {0xb699c1c5, "LucidaCalligraphy-Italic", "Arial", 0, 1252},
+    {0xb725d629, "TimesNewRoman", "Arial", 2, 1252},
+    {0xb7eaebeb, "AdobeHeitiStdR", "Batang,Century,Dotum", 0, 936},
+    {0xbd29c486, "BerlinSansFBDemi-Bold", "Arial", 0, 1252},
+    {0xbe8a8db4, "BookshelfSymbolSeven", "Arial", 0, 1252},
+    {0xc16c0118, "AdobeHebrew", "Bell MT,Berlin Sans FB,Calibri", 0, 1252},
+    {0xc318b0af, "MyriadProLight", "Calibri,STFangsong,Times New Roman", 0,
      1252},
-    {0xc65e5659, L"CambriaMath", L"Arial", 2, 1252},
-    {0xc75c8f05, L"LucidaConsole", L"Arial", 1, 1252},
-    {0xca7c35d6, L"Calibri", L"Arial", 0, 1252},
-    {0xcb053f53, L"MicrosoftYaHei", L"Arial", 0, 936},
-    {0xcb7190f9, L"Magneto-Bold", L"Arial", 0, 1252},
-    {0xcca00cc5, L"System", L"Arial", 0, 1252},
-    {0xccad6f76, L"Jokerman-Regular", L"Arial", 0, 1252},
-    {0xccc5818c, L"EuroSign", L"Arial", 0, 1252},
-    {0xcf3d7234, L"LucidaHandwriting-Italic", L"Arial", 0, 1252},
-    {0xcf7b8fdb, L"MinionPro",
-     L"Bell MT,Corbel,Times New Roman,Cambria,Berlin Sans FB", 0, 1252},
-    {0xcfe5755f, L"Simhei", L"Arial", 1, 936},
-    {0xd011f4ee, L"MSPGothic", L"Arial", 0, 1252},
-    {0xd060e7ef, L"Vivaldi", L"Arial", 8, 1252},
-    {0xd07edec1, L"FranklinGothic-Medium", L"Arial", 0, 1252},
-    {0xd107243f, L"SimSun", L"Arial", 0, 936},
-    {0xd1881562, L"ArialNarrow", L"Arial Narrow", 0, 1252},
-    {0xd22b7dce, L"BodoniMTPosterCompressed", L"Arial", 0, 1252},
-    {0xd22bfa60, L"ComicSansMS", L"Arial", 8, 1252},
-    {0xd3bd0e35, L"Bauhaus93", L"Arial", 0, 1252},
-    {0xd429ee7a, L"STFangsong", L"Arial", 0, 936},
-    {0xd6679c12, L"BernardMTCondensed", L"Arial", 0, 1252},
-    {0xd8e8a027, L"LucidaSans", L"Arial", 0, 1252},
-    {0xd9fe7761, L"HighTowerText-Reg", L"Arial", 2, 1252},
-    {0xda7e551e, L"STSong", L"Arial", 0, 936},
-    {0xdaa6842d, L"STZhongsong", L"Arial", 0, 936},
-    {0xdaaab93f, L"STFangsong", L"Arial", 0, 936},
-    {0xdaeb0713, L"STSong", L"Arial", 0, 936},
-    {0xdafedbef, L"STCaiyun", L"Arial", 0, 936},
-    {0xdb00a3d9, L"Broadway", L"Arial", 0, 1252},
-    {0xdb1f5ad4, L"STXinwei", L"Arial", 0, 936},
-    {0xdb326e7f, L"STKaiti", L"Arial", 0, 936},
-    {0xdb69595a, L"STHupo", L"Arial", 0, 936},
-    {0xdba0082c, L"STXihei", L"Arial", 0, 936},
-    {0xdbd0ab18, L"STXingkai", L"Arial", 0, 936},
-    {0xdc1a7db1, L"STLiti", L"Arial", 0, 936},
-    {0xdc33075f, L"KristenITC-Regular", L"Arial", 8, 1252},
-    {0xdcc7009c, L"Harrington", L"Arial", 0, 1252},
-    {0xdd712466, L"ArialBlack", L"Arial", 0, 1252},
-    {0xdde87b3e, L"Impact", L"Arial", 0, 1252},
-    {0xdf69fb32, L"SnapITC", L"Arial", 0, 1252},
-    {0xdf8b25e8, L"CenturyGothic", L"Arial", 0, 1252},
-    {0xe0f705c0, L"KristenITC", L"Arial", 8, 1252},
-    {0xe1427573, L"Raavi", L"Arial", 0, 1252},
-    {0xe2cea0cb, L"Magneto", L"Arial", 0, 1252},
-    {0xe36a9e17, L"Ravie", L"Arial", 0, 1252},
-    {0xe433f8e2, L"Parchment", L"Arial", 8, 1252},
-    {0xe43dff4a, L"Wingdings", L"Arial", 4, 42},
-    {0xe4e2c405, L"MTExtra", L"Arial", 6, 42},
-    {0xe618cc35, L"InformalRoman", L"Arial", 8, 1252},
-    {0xe6c27ffc, L"Mistral", L"Arial", 8, 1252},
-    {0xe7ebf4b9, L"Courier", L"Courier New", 0, 1252},
-    {0xe8bc4a9d, L"MSReferenceSpecialty", L"Arial", 0, 1252},
-    {0xe90fb013, L"TempusSansITC", L"Arial", 0, 1252},
-    {0xec637b42, L"Consolas", L"Verdana", 1, 1252},
-    {0xed3a683b, L"STXinwei", L"Arial", 0, 936},
-    {0xef264cd1, L"LucidaHandwriting", L"Arial", 0, 1252},
-    {0xf086bca2, L"BaskervilleOldFace", L"Arial", 0, 1252},
-    {0xf1028030, L"Mangal", L"Arial", 2, 1252},
-    {0xf1da7eb9, L"ShowcardGothic", L"Arial", 0, 1252},
-    {0xf210f06a, L"ArialMT", L"Arial", 0, 1252},
-    {0xf477f16a, L"Latha", L"Arial", 0, 1252},
-    {0xf616f3dd, L"LiSu", L"Arial", 1, 936},
-    {0xfa479aa6, L"MicrosoftYaHei", L"Arial", 0, 936},
-    {0xfcd19697, L"BookmanOldStyle", L"Arial", 0, 1252},
-    {0xfe209a82, L"LucidaCalligraphy", L"Arial", 0, 1252},
-    {0xfef135f8, L"AdobeHeitiStd-Regular", L"Batang,Century,Dotum", 0, 936},
+    {0xc65e5659, "CambriaMath", "Arial", 2, 1252},
+    {0xc75c8f05, "LucidaConsole", "Arial", 1, 1252},
+    {0xca7c35d6, "Calibri", "Arial", 0, 1252},
+    {0xcb053f53, "MicrosoftYaHei", "Arial", 0, 936},
+    {0xcb7190f9, "Magneto-Bold", "Arial", 0, 1252},
+    {0xcca00cc5, "System", "Arial", 0, 1252},
+    {0xccad6f76, "Jokerman-Regular", "Arial", 0, 1252},
+    {0xccc5818c, "EuroSign", "Arial", 0, 1252},
+    {0xcf3d7234, "LucidaHandwriting-Italic", "Arial", 0, 1252},
+    {0xcf7b8fdb, "MinionPro",
+     "Bell MT,Corbel,Times New Roman,Cambria,Berlin Sans FB", 0, 1252},
+    {0xcfe5755f, "Simhei", "Arial", 1, 936},
+    {0xd011f4ee, "MSPGothic", "Arial", 0, 1252},
+    {0xd060e7ef, "Vivaldi", "Arial", 8, 1252},
+    {0xd07edec1, "FranklinGothic-Medium", "Arial", 0, 1252},
+    {0xd107243f, "SimSun", "Arial", 0, 936},
+    {0xd1881562, "ArialNarrow", "Arial Narrow", 0, 1252},
+    {0xd22b7dce, "BodoniMTPosterCompressed", "Arial", 0, 1252},
+    {0xd22bfa60, "ComicSansMS", "Arial", 8, 1252},
+    {0xd3bd0e35, "Bauhaus93", "Arial", 0, 1252},
+    {0xd429ee7a, "STFangsong", "Arial", 0, 936},
+    {0xd6679c12, "BernardMTCondensed", "Arial", 0, 1252},
+    {0xd8e8a027, "LucidaSans", "Arial", 0, 1252},
+    {0xd9fe7761, "HighTowerText-Reg", "Arial", 2, 1252},
+    {0xda7e551e, "STSong", "Arial", 0, 936},
+    {0xdaa6842d, "STZhongsong", "Arial", 0, 936},
+    {0xdaaab93f, "STFangsong", "Arial", 0, 936},
+    {0xdaeb0713, "STSong", "Arial", 0, 936},
+    {0xdafedbef, "STCaiyun", "Arial", 0, 936},
+    {0xdb00a3d9, "Broadway", "Arial", 0, 1252},
+    {0xdb1f5ad4, "STXinwei", "Arial", 0, 936},
+    {0xdb326e7f, "STKaiti", "Arial", 0, 936},
+    {0xdb69595a, "STHupo", "Arial", 0, 936},
+    {0xdba0082c, "STXihei", "Arial", 0, 936},
+    {0xdbd0ab18, "STXingkai", "Arial", 0, 936},
+    {0xdc1a7db1, "STLiti", "Arial", 0, 936},
+    {0xdc33075f, "KristenITC-Regular", "Arial", 8, 1252},
+    {0xdcc7009c, "Harrington", "Arial", 0, 1252},
+    {0xdd712466, "ArialBlack", "Arial", 0, 1252},
+    {0xdde87b3e, "Impact", "Arial", 0, 1252},
+    {0xdf69fb32, "SnapITC", "Arial", 0, 1252},
+    {0xdf8b25e8, "CenturyGothic", "Arial", 0, 1252},
+    {0xe0f705c0, "KristenITC", "Arial", 8, 1252},
+    {0xe1427573, "Raavi", "Arial", 0, 1252},
+    {0xe2cea0cb, "Magneto", "Arial", 0, 1252},
+    {0xe36a9e17, "Ravie", "Arial", 0, 1252},
+    {0xe433f8e2, "Parchment", "Arial", 8, 1252},
+    {0xe43dff4a, "Wingdings", "Arial", 4, 42},
+    {0xe4e2c405, "MTExtra", "Arial", 6, 42},
+    {0xe618cc35, "InformalRoman", "Arial", 8, 1252},
+    {0xe6c27ffc, "Mistral", "Arial", 8, 1252},
+    {0xe7ebf4b9, "Courier", "Courier New", 0, 1252},
+    {0xe8bc4a9d, "MSReferenceSpecialty", "Arial", 0, 1252},
+    {0xe90fb013, "TempusSansITC", "Arial", 0, 1252},
+    {0xec637b42, "Consolas", "Verdana", 1, 1252},
+    {0xed3a683b, "STXinwei", "Arial", 0, 936},
+    {0xef264cd1, "LucidaHandwriting", "Arial", 0, 1252},
+    {0xf086bca2, "BaskervilleOldFace", "Arial", 0, 1252},
+    {0xf1028030, "Mangal", "Arial", 2, 1252},
+    {0xf1da7eb9, "ShowcardGothic", "Arial", 0, 1252},
+    {0xf210f06a, "ArialMT", "Arial", 0, 1252},
+    {0xf477f16a, "Latha", "Arial", 0, 1252},
+    {0xf616f3dd, "LiSu", "Arial", 1, 936},
+    {0xfa479aa6, "MicrosoftYaHei", "Arial", 0, 936},
+    {0xfcd19697, "BookmanOldStyle", "Arial", 0, 1252},
+    {0xfe209a82, "LucidaCalligraphy", "Arial", 0, 1252},
+    {0xfef135f8, "AdobeHeitiStd-Regular", "Batang,Century,Dotum", 0, 936},
 };
 #elif _FX_PLATFORM_ == _FX_PLATFORM_LINUX_
 const FGAS_FontInfo g_XFAFontsMap[] = {
-    {0x01d5d33e, L"SimSun",
-     L"WenQuanYi Zen Hei Mono,AR PL UMing CN,AR PL UMing HK,AR PL UMing TW,AR "
-     L"PL UMing TW MBE",
+    {0x01d5d33e, "SimSun",
+     "WenQuanYi Zen Hei Mono,AR PL UMing CN,AR PL UMing HK,AR PL UMing TW,AR "
+     "PL UMing TW MBE",
      0, 936},
-    {0x01e4f102, L"YouYuan",
-     L"WenQuanYi Zen Hei Mono,AR PL UMing CN,AR PL UMing HK,AR PL UMing TW,AR "
-     L"PL UMing TW MBE",
+    {0x01e4f102, "YouYuan",
+     "WenQuanYi Zen Hei Mono,AR PL UMing CN,AR PL UMing HK,AR PL UMing TW,AR "
+     "PL UMing TW MBE",
      1, 936},
-    {0x030549dc, L"LiSu",
-     L"WenQuanYi Zen Hei,WenQuanYi Zen Hei Sharp,WenQuanYi Zen Hei "
-     L"Mono,WenQuanYi Micro Hei",
+    {0x030549dc, "LiSu",
+     "WenQuanYi Zen Hei,WenQuanYi Zen Hei Sharp,WenQuanYi Zen Hei "
+     "Mono,WenQuanYi Micro Hei",
      1, 936},
-    {0x032edd44, L"Simhei",
-     L"WenQuanYi Zen Hei,WenQuanYi Zen Hei Sharp,WenQuanYi Zen Hei "
-     L"Mono,WenQuanYi Micro Hei",
+    {0x032edd44, "Simhei",
+     "WenQuanYi Zen Hei,WenQuanYi Zen Hei Sharp,WenQuanYi Zen Hei "
+     "Mono,WenQuanYi Micro Hei",
      1, 936},
-    {0x03eac6fc, L"PoorRichard-Regular", L"Droid Sans Japanese,FreeSerif", 2,
+    {0x03eac6fc, "PoorRichard-Regular", "Droid Sans Japanese,FreeSerif", 2,
      1252},
-    {0x03ed90e6, L"Nina", L"FreeSerif", 0, 1252},
-    {0x077b56b3, L"KingsoftPhoneticPlain",
-     L"Tibetan Machine Uni,LKLUG,Samyak Gujarati,Droid Sans Thai,Droid Sans "
-     L"Armenian,Untitled1,utkal,Lohit Oriya",
+    {0x03ed90e6, "Nina", "FreeSerif", 0, 1252},
+    {0x077b56b3, "KingsoftPhoneticPlain",
+     "Tibetan Machine Uni,LKLUG,Samyak Gujarati,Droid Sans Thai,Droid Sans "
+     "Armenian,Untitled1,utkal,Lohit Oriya",
      0, 1252},
-    {0x078ed524, L"MicrosoftSansSerif",
-     L"Droid Sans Japanese,FreeSerif,WenQuanYi Micro Hei", 0, 1252},
-    {0x089b18a9, L"Arial",
-     L"Droid Sans Japanese,DejaVu Sans Condensed,FreeSerif,WenQuanYi Micro Hei",
+    {0x078ed524, "MicrosoftSansSerif",
+     "Droid Sans Japanese,FreeSerif,WenQuanYi Micro Hei", 0, 1252},
+    {0x089b18a9, "Arial",
+     "Droid Sans Japanese,DejaVu Sans Condensed,FreeSerif,WenQuanYi Micro Hei",
      0, 1252},
-    {0x0b2cad72, L"MonotypeCorsiva", L"Droid Sans Japanese,FreeSerif", 8, 1252},
-    {0x0bb003e7, L"Kartika",
-     L"FreeSans,Liberation Sans,Liberation Sans Narrow,Nimbus Sans "
-     L"L,Garuda,FreeSerif,WenQuanYi Micro Hei",
+    {0x0b2cad72, "MonotypeCorsiva", "Droid Sans Japanese,FreeSerif", 8, 1252},
+    {0x0bb003e7, "Kartika",
+     "FreeSans,Liberation Sans,Liberation Sans Narrow,Nimbus Sans "
+     "L,Garuda,FreeSerif,WenQuanYi Micro Hei",
      2, 1252},
-    {0x0bb469df, L"VinerHandITC",
-     L"Droid Sans Japanese,Ubuntu,Liberation Sans,Liberation Serif", 8, 1252},
-    {0x0bc1a851, L"SegoeUI", L"Droid Sans Japanese,DejaVu Sans", 0, 1252},
-    {0x0c112ebd, L"KozukaGothicPro-VIM", L"FreeSerif", 0, 1252},
-    {0x0cfcb9c1, L"AdobeThai", L"Droid Sans Japanese,Waree", 0, 847},
-    {0x0e7de0f9, L"Playbill",
-     L"KacstQurn,Droid Arabic Naskh,Droid Sans Ethiopic,mry_KacstQurn,Droid "
-     L"Sans Ethiopic,Droid Sans Japanese,FreeSerif",
+    {0x0bb469df, "VinerHandITC",
+     "Droid Sans Japanese,Ubuntu,Liberation Sans,Liberation Serif", 8, 1252},
+    {0x0bc1a851, "SegoeUI", "Droid Sans Japanese,DejaVu Sans", 0, 1252},
+    {0x0c112ebd, "KozukaGothicPro-VIM", "FreeSerif", 0, 1252},
+    {0x0cfcb9c1, "AdobeThai", "Droid Sans Japanese,Waree", 0, 847},
+    {0x0e7de0f9, "Playbill",
+     "KacstQurn,Droid Arabic Naskh,Droid Sans Ethiopic,mry_KacstQurn,Droid "
+     "Sans Ethiopic,Droid Sans Japanese,FreeSerif",
      0, 1252},
-    {0x0eff47c3, L"STHupo", L"AR PL UKai HK,AR PL UMing HK,AR PL UKai CN", 0,
+    {0x0eff47c3, "STHupo", "AR PL UKai HK,AR PL UMing HK,AR PL UKai CN", 0,
      936},
-    {0x107ad374, L"Constantia",
-     L"Droid Sans Japanese,FreeSerif,WenQuanYi Micro Hei,Ubuntu", 2, 1252},
-    {0x12194c2d, L"KunstlerScript", L"Droid Sans Japanese,Liberation Serif", 8,
+    {0x107ad374, "Constantia",
+     "Droid Sans Japanese,FreeSerif,WenQuanYi Micro Hei,Ubuntu", 2, 1252},
+    {0x12194c2d, "KunstlerScript", "Droid Sans Japanese,Liberation Serif", 8,
      1252},
-    {0x135ef6a1, L"MinionProSmBd", L"Liberation Serif", 0, 1252},
-    {0x158c4049, L"Garamond",
-     L"Droid Sans Japanese,Liberation Serif,Ubuntu,FreeSerif", 2, 1252},
-    {0x160ecb24, L"STZhongsong",
-     L"WenQuanYi Zen Hei Mono,WenQuanYi Zen Hei,WenQuanYi Zen Hei "
-     L"Sharp,WenQuanYi Micro Hei",
+    {0x135ef6a1, "MinionProSmBd", "Liberation Serif", 0, 1252},
+    {0x158c4049, "Garamond",
+     "Droid Sans Japanese,Liberation Serif,Ubuntu,FreeSerif", 2, 1252},
+    {0x160ecb24, "STZhongsong",
+     "WenQuanYi Zen Hei Mono,WenQuanYi Zen Hei,WenQuanYi Zen Hei "
+     "Sharp,WenQuanYi Micro Hei",
      0, 936},
-    {0x161ed07e, L"MSGothic",
-     L"WenQuanYi Micro Hei Mono,WenQuanYi Zen Hei Mono,WenQuanYi Zen Hei,AR PL "
-     L"UMing CN,AR PL UMing HK,AR PL UMing TW",
+    {0x161ed07e, "MSGothic",
+     "WenQuanYi Micro Hei Mono,WenQuanYi Zen Hei Mono,WenQuanYi Zen Hei,AR PL "
+     "UMing CN,AR PL UMing HK,AR PL UMing TW",
      1, 1252},
-    {0x171d1ed1, L"SnapITC-Regular",
-     L"Liberation Sans Narrow,Ubuntu Condensed,Nimbus Sans L,DejaVu Sans", 0,
+    {0x171d1ed1, "SnapITC-Regular",
+     "Liberation Sans Narrow,Ubuntu Condensed,Nimbus Sans L,DejaVu Sans", 0,
      1252},
-    {0x18d1188f, L"Cambria", L"Droid Sans Japanese,FreeSerif,FreeMono", 2,
-     1252},
-    {0x18eaf350, L"ArialUnicodeMS",
-     L"WenQuanYi Zen Hei Mono,WenQuanYi Zen Hei,WenQuanYi Zen Hei "
-     L"Sharp,WenQuanYi Micro Hei",
+    {0x18d1188f, "Cambria", "Droid Sans Japanese,FreeSerif,FreeMono", 2, 1252},
+    {0x18eaf350, "ArialUnicodeMS",
+     "WenQuanYi Zen Hei Mono,WenQuanYi Zen Hei,WenQuanYi Zen Hei "
+     "Sharp,WenQuanYi Micro Hei",
      0, 936},
-    {0x1a92d115, L"MingLiU",
-     L"WenQuanYi Zen Hei Mono,WenQuanYi Zen Hei,WenQuanYi Zen Hei "
-     L"Sharp,WenQuanYi Micro Hei",
+    {0x1a92d115, "MingLiU",
+     "WenQuanYi Zen Hei Mono,WenQuanYi Zen Hei,WenQuanYi Zen Hei "
+     "Sharp,WenQuanYi Micro Hei",
      1, 1252},
-    {0x1cc217c6, L"TrebuchetMS",
-     L"Droid Sans Japanese,Liberation Serif,FreeSerif,Ubuntu", 0, 1252},
-    {0x1d649596, L"BasemicTimes",
-     L"Liberation Serif,Times New Roman,Droid Sans Japanese,FreeSerif,Ubuntu",
-     0, 1252},
-    {0x1e34ee60, L"BellMT",
-     L"KacstQurn,Droid Sans Japanese,Ubuntu,Liberation Serif", 2, 1252},
-    {0x1eb36945, L"CooperBlack",
-     L"KacstQurn,Droid Sans Japanese,FreeMono,Liberation Mono, WenQuanYi Micro "
-     L"Hei Mono",
+    {0x1cc217c6, "TrebuchetMS",
+     "Droid Sans Japanese,Liberation Serif,FreeSerif,Ubuntu", 0, 1252},
+    {0x1d649596, "BasemicTimes",
+     "Liberation Serif,Times New Roman,Droid Sans Japanese,FreeSerif,Ubuntu", 0,
+     1252},
+    {0x1e34ee60, "BellMT",
+     "KacstQurn,Droid Sans Japanese,Ubuntu,Liberation Serif", 2, 1252},
+    {0x1eb36945, "CooperBlack",
+     "KacstQurn,Droid Sans Japanese,FreeMono,Liberation Mono, WenQuanYi Micro "
+     "Hei Mono",
      2, 1252},
-    {0x1ef7787d, L"BatangChe",
-     L"WenQuanYi Zen Hei Mono,AR PL UMing CN,AR PL UMing HK,AR PL UMing "
-     L"TW,WenQuanYi Zen Hei,WenQuanYi Micro Hei",
+    {0x1ef7787d, "BatangChe",
+     "WenQuanYi Zen Hei Mono,AR PL UMing CN,AR PL UMing HK,AR PL UMing "
+     "TW,WenQuanYi Zen Hei,WenQuanYi Micro Hei",
      1, 1252},
-    {0x20b3bd3a, L"BrushScriptMT",
-     L"KacstQurn,Droid Arabic Naskh,Droid Sans Ethiopic,Droid Sans "
-     L"Japanese,URW Chancery L,Liberation Sans",
+    {0x20b3bd3a, "BrushScriptMT",
+     "KacstQurn,Droid Arabic Naskh,Droid Sans Ethiopic,Droid Sans "
+     "Japanese,URW Chancery L,Liberation Sans",
      8, 1252},
-    {0x220877aa, L"Candara", L"Droid Sans Japanese,DejaVu Sans", 0, 1252},
-    {0x22135007, L"FreestyleScript-Regular",
-     L"KacstQurn,Droid Sans Japanese,Liberation Sans", 8, 1252},
-    {0x251059c3, L"Chiller",
-     L"KacstQurn,Droid Arabic Naskh,Droid Sans Ethiopic,Droid Sans "
-     L"Japanese,Liberation Sans",
+    {0x220877aa, "Candara", "Droid Sans Japanese,DejaVu Sans", 0, 1252},
+    {0x22135007, "FreestyleScript-Regular",
+     "KacstQurn,Droid Sans Japanese,Liberation Sans", 8, 1252},
+    {0x251059c3, "Chiller",
+     "KacstQurn,Droid Arabic Naskh,Droid Sans Ethiopic,Droid Sans "
+     "Japanese,Liberation Sans",
      0, 1252},
-    {0x25bed6dd, L"MSReferenceSansSerif",
-     L"DejaVu Sans Condensed,Ubuntu Condensed,Droid Sans Japanese,AR PL UKai "
-     L"HK",
+    {0x25bed6dd, "MSReferenceSansSerif",
+     "DejaVu Sans Condensed,Ubuntu Condensed,Droid Sans Japanese,AR PL UKai "
+     "HK",
      0, 1252},
-    {0x28154c81, L"Parchment-Regular", L"Droid Sans Japanese,Liberation Sans",
-     8, 1252},
-    {0x29711eb9, L"STLiti", L"AR PL UKai HK", 0, 936},
-    {0x2b1993b4, L"Basemic",
-     L"Liberation Serif,Droid Sans Japanese,Liberation Sans", 0, 1252},
-    {0x2b316339, L"NiagaraSolid-Reg", L"Droid Sans Japanese,Liberation Sans", 0,
+    {0x28154c81, "Parchment-Regular", "Droid Sans Japanese,Liberation Sans", 8,
      1252},
-    {0x2c147529, L"FootlightMTLight",
-     L"KacstQurn,Droid Sans Japanese,Liberation Sans", 0, 1252},
-    {0x2c198928, L"HarlowSolid",
-     L"KacstQurn,Droid Sans Japanese,Liberation Sans", 0, 1252},
-    {0x2c6ac6b2, L"LucidaBright",
-     L"KacstQurn,Droid Arabic Naskh,Droid Sans Ethiopic,mry_KacstQurn,Droid "
-     L"Sans Japanese,Liberation Sans",
+    {0x29711eb9, "STLiti", "AR PL UKai HK", 0, 936},
+    {0x2b1993b4, "Basemic",
+     "Liberation Serif,Droid Sans Japanese,Liberation Sans", 0, 1252},
+    {0x2b316339, "NiagaraSolid-Reg", "Droid Sans Japanese,Liberation Sans", 0,
+     1252},
+    {0x2c147529, "FootlightMTLight",
+     "KacstQurn,Droid Sans Japanese,Liberation Sans", 0, 1252},
+    {0x2c198928, "HarlowSolid", "KacstQurn,Droid Sans Japanese,Liberation Sans",
+     0, 1252},
+    {0x2c6ac6b2, "LucidaBright",
+     "KacstQurn,Droid Arabic Naskh,Droid Sans Ethiopic,mry_KacstQurn,Droid "
+     "Sans Japanese,Liberation Sans",
      2, 1252},
-    {0x2c9f38e2, L"KozukaMinchoPro-VIR", L"DejaVu Sans", 0, 1252},
-    {0x2d5a47b0, L"STCaiyun", L"AR PL UKai HK", 0, 936},
-    {0x2def26bf, L"BernardMT-Condensed",
-     L"KacstQurn,Droid Sans Japanese,DejaVu Serif", 0, 1252},
-    {0x2fd8930b, L"KozukaMinchoPr6NR", L"DejaVu Serif", 0, 1252},
-    {0x3115525a, L"FangSong_GB2312",
-     L"WenQuanYi Zen Hei Mono,WenQuanYi Zen Hei,WenQuanYi Zen Hei "
-     L"Sharp,WenQuanYi Micro Hei",
+    {0x2c9f38e2, "KozukaMinchoPro-VIR", "DejaVu Sans", 0, 1252},
+    {0x2d5a47b0, "STCaiyun", "AR PL UKai HK", 0, 936},
+    {0x2def26bf, "BernardMT-Condensed",
+     "KacstQurn,Droid Sans Japanese,DejaVu Serif", 0, 1252},
+    {0x2fd8930b, "KozukaMinchoPr6NR", "DejaVu Serif", 0, 1252},
+    {0x3115525a, "FangSong_GB2312",
+     "WenQuanYi Zen Hei Mono,WenQuanYi Zen Hei,WenQuanYi Zen Hei "
+     "Sharp,WenQuanYi Micro Hei",
      0, 1252},
-    {0x31327817, L"MyriadPro",
-     L"Ubuntu Condensed,Droid Sans Japanese, FreeSerif", 0, 1252},
-    {0x32244975, L"Helvetica",
-     L"Ubuntu,DejaVu Sans Condensed,Liberation Sans,Liberation Sans "
-     L"Narrow,Nimbus Sans L",
+    {0x31327817, "MyriadPro", "Ubuntu Condensed,Droid Sans Japanese, FreeSerif",
      0, 1252},
-    {0x32ac995c, L"Terminal", L"DejaVu Serif", 0, 1252},
-    {0x338d648a, L"NiagaraEngraved-Reg", L"Droid Sans Japanese,DejaVu Serif", 0,
+    {0x32244975, "Helvetica",
+     "Ubuntu,DejaVu Sans Condensed,Liberation Sans,Liberation Sans "
+     "Narrow,Nimbus Sans ",
+     0, 1252},
+    {0x32ac995c, "Terminal", "DejaVu Serif", 0, 1252},
+    {0x338d648a, "NiagaraEngraved-Reg", "Droid Sans Japanese,DejaVu Serif", 0,
      1252},
-    {0x33bb65f2, L"Sylfaen", L"Droid Sans Japanese,DejaVu Sans", 2, 1252},
-    {0x3402c30e, L"MSPMincho",
-     L"WenQuanYi Zen Hei Mono,AR PL UMing CN,AR PL UMing HK,AR PL UMing TW", 2,
+    {0x33bb65f2, "Sylfaen", "Droid Sans Japanese,DejaVu Sans", 2, 1252},
+    {0x3402c30e, "MSPMincho",
+     "WenQuanYi Zen Hei Mono,AR PL UMing CN,AR PL UMing HK,AR PL UMing TW", 2,
      1252},
-    {0x3412bf31, L"SimSun-PUA",
-     L"WenQuanYi Zen Hei Mono,AR PL UMing CN,AR PL UMing CN,AR PL UMing HK", 0,
+    {0x3412bf31, "SimSun-PUA",
+     "WenQuanYi Zen Hei Mono,AR PL UMing CN,AR PL UMing CN,AR PL UMing HK", 0,
      936},
-    {0x36eb39b9, L"BerlinSansFB",
-     L"Droid Sans Japanese,Liberation Serif,Ubuntu,FreeSerif", 0, 1252},
-    {0x36f42055, L"UniversATT", L"Microsoft Sans Serif", 0, 1252},
-    {0x3864c4f6, L"HighTowerText", L"Droid Sans Japanese,DejaVu Serif", 2,
-     1252},
-    {0x3a257d03, L"FangSong_GB2312",
-     L"WenQuanYi Zen Hei Mono,WenQuanYi Zen Hei", 0, 1252},
-    {0x3c7d1d07, L"Garamond3LTStd",
-     L"Droid Sans Japanese,Ubuntu Condensed,DejaVu Sans Condensed,Liberation "
-     L"Serif,Ubuntu,FreeSerif",
+    {0x36eb39b9, "BerlinSansFB",
+     "Droid Sans Japanese,Liberation Serif,Ubuntu,FreeSerif", 0, 1252},
+    {0x36f42055, "UniversATT", "Microsoft Sans Serif", 0, 1252},
+    {0x3864c4f6, "HighTowerText", "Droid Sans Japanese,DejaVu Serif", 2, 1252},
+    {0x3a257d03, "FangSong_GB2312", "WenQuanYi Zen Hei Mono,WenQuanYi Zen Hei",
+     0, 1252},
+    {0x3c7d1d07, "Garamond3LTStd",
+     "Droid Sans Japanese,Ubuntu Condensed,DejaVu Sans Condensed,Liberation "
+     "Serif,Ubuntu,FreeSerif",
      2, 1252},
-    {0x3cdae668, L"FreestyleScript",
-     L"KacstQurn,Droid Sans Japanese,DejaVu Sans", 8, 1252},
-    {0x3d55aed7, L"Jokerman", L"Droid Sans Japanese,DejaVu Sans", 0, 1252},
-    {0x3d5b4385, L"PMingLiU",
-     L"WenQuanYi Zen Hei Mono,WenQuanYi Zen Hei,WenQuanYi Zen Hei "
-     L"Sharp,WenQuanYi Micro Hei",
+    {0x3cdae668, "FreestyleScript", "KacstQurn,Droid Sans Japanese,DejaVu Sans",
+     8, 1252},
+    {0x3d55aed7, "Jokerman", "Droid Sans Japanese,DejaVu Sans", 0, 1252},
+    {0x3d5b4385, "PMingLiU",
+     "WenQuanYi Zen Hei Mono,WenQuanYi Zen Hei,WenQuanYi Zen Hei "
+     "Sharp,WenQuanYi Micro Hei",
      2, 1252},
-    {0x3d9b7669, L"EstrangeloEdessa", L"Droid Sans Japanese,DejaVu Sans", 0,
+    {0x3d9b7669, "EstrangeloEdessa", "Droid Sans Japanese,DejaVu Sans", 0,
      1252},
-    {0x3e532d74, L"FranklinGothicMedium", L"Droid Sans Japanese,Ubuntu", 0,
-     1252},
-    {0x3e6aa32d, L"NSimSun",
-     L"WenQuanYi Zen Hei Mono,WenQuanYi Zen Hei,WenQuanYi Zen Hei "
-     L"Sharp,WenQuanYi Micro Hei",
+    {0x3e532d74, "FranklinGothicMedium", "Droid Sans Japanese,Ubuntu", 0, 1252},
+    {0x3e6aa32d, "NSimSun",
+     "WenQuanYi Zen Hei Mono,WenQuanYi Zen Hei,WenQuanYi Zen Hei "
+     "Sharp,WenQuanYi Micro Hei",
      1, 936},
-    {0x3f6c36a8, L"Gautami",
-     L"Droid Arabic Naskh,Droid Sans Ethiopic, mry_KacstQurn,Droid Sans "
-     L"Japanese,FreeSans",
+    {0x3f6c36a8, "Gautami",
+     "Droid Arabic Naskh,Droid Sans Ethiopic, mry_KacstQurn,Droid Sans "
+     "Japanese,FreeSans",
      0, 1252},
-    {0x3ff32662, L"Chiller-Regular",
-     L"KacstQurn,Droid Arabic Naskh,Droid Sans Ethiopic,FreeSans", 0, 1252},
-    {0x409de312, L"ModernNo.20",
-     L"KacstQurn,Droid Sans Japanese,Nimbus Sans L,Nimbus Sans L,FreeSans", 2,
+    {0x3ff32662, "Chiller-Regular",
+     "KacstQurn,Droid Arabic Naskh,Droid Sans Ethiopic,FreeSans", 0, 1252},
+    {0x409de312, "ModernNo.20",
+     "KacstQurn,Droid Sans Japanese,Nimbus Sans L,Nimbus Sans L,FreeSans", 2,
      1252},
-    {0x41443c5e, L"Georgia", L"Droid Sans Japanese,FreeSans", 2, 1252},
-    {0x4160ade5, L"BellGothicStdBlack", L"FreeSans", 0, 1252},
-    {0x421976c4, L"Modern-Regular", L"FreeSans", 2, 1252},
-    {0x422a7252, L"Stencil", L"Droid Sans Japanese,FreeSans,Liberation Sans", 0,
+    {0x41443c5e, "Georgia", "Droid Sans Japanese,FreeSans", 2, 1252},
+    {0x4160ade5, "BellGothicStdBlack", "FreeSans", 0, 1252},
+    {0x421976c4, "Modern-Regular", "FreeSans", 2, 1252},
+    {0x422a7252, "Stencil", "Droid Sans Japanese,FreeSans,Liberation Sans", 0,
      1252},
-    {0x42c8554f, L"Fixedsys", L"FreeSerif", 0, 1252},
-    {0x435cb41d, L"Roman", L"FreeSerif", 0, 1252},
-    {0x47882383, L"CourierNew",
-     L"FreeMono,WenQuanYi Micro Hei Mono,AR PL UKai CN,AR PL UKai HK,AR PL "
-     L"UKai TW,AR PL UKai TW MBE,DejaVu Sans",
+    {0x42c8554f, "Fixedsys", "FreeSerif", 0, 1252},
+    {0x435cb41d, "Roman", "FreeSerif", 0, 1252},
+    {0x47882383, "CourierNew",
+     "FreeMono,WenQuanYi Micro Hei Mono,AR PL UKai CN,AR PL UKai HK,AR PL "
+     "UKai TW,AR PL UKai TW MBE,DejaVu Sans",
      1, 1252},
-    {0x480a2338, L"BerlinSansFBDemi", L"Droid Sans Japanese,Liberation Serif",
-     0, 1252},
-    {0x480bf7a4, L"CourierStd", L"DejaVu Sans", 0, 1252},
-    {0x481ad6ed, L"VladimirScript", L"Droid Sans Japanese,DejaVu Serif", 8,
+    {0x480a2338, "BerlinSansFBDemi", "Droid Sans Japanese,Liberation Serif", 0,
      1252},
-    {0x4911577a, L"YouYuan",
-     L"WenQuanYi Zen Hei Mono,AR PL UMing CN,AR PL UMing HK,AR PL UMing TW", 1,
+    {0x480bf7a4, "CourierStd", "DejaVu Sans", 0, 1252},
+    {0x481ad6ed, "VladimirScript", "Droid Sans Japanese,DejaVu Serif", 8, 1252},
+    {0x4911577a, "YouYuan",
+     "WenQuanYi Zen Hei Mono,AR PL UMing CN,AR PL UMing HK,AR PL UMing TW", 1,
      936},
-    {0x4a788d72, L"STXingkai", L"AR PL UKai HK,AR PL UMing HK,AR PL UKai CN", 0,
+    {0x4a788d72, "STXingkai", "AR PL UKai HK,AR PL UMing HK,AR PL UKai CN", 0,
      936},
-    {0x4bf88566, L"SegoeCondensed", L"FreeSerif", 0, 1252},
-    {0x4ccf51a4, L"BerlinSansFB-Reg", L"Droid Sans Japanese,Liberation Serif",
-     0, 1252},
-    {0x4ea967ce, L"GulimChe",
-     L"WenQuanYi Zen Hei Mono,AR PL UKai CN,AR PL UKai HK,AR PL UKai TW,AR PL "
-     L"UKai TW MBE",
-     1, 1252},
-    {0x4f68bd79, L"LetterGothicStd",
-     L"FreeMono,Liberation Mono,Andale Mono,WenQuanYi Micro Hei Mono", 0, 1252},
-    {0x51a0d0e6, L"KozukaGothicPr6NM", L"FreeSerif", 0, 1252},
-    {0x531b3dea, L"BasemicSymbol", L"FreeSerif", 0, 1252},
-    {0x5333fd39, L"CalifornianFB-Reg",
-     L"Droid Sans Japanese,URW Chancery L,FreeSerif", 2, 1252},
-    {0x53561a54, L"FZYTK--GBK1-0",
-     L"WenQuanYi Zen Hei Mono,WenQuanYi Zen Hei,WenQuanYi Zen Hei "
-     L"Sharp,WenQuanYi Micro Hei",
-     0, 936},
-    {0x55e0dde6, L"LucidaSansTypewriter",
-     L"Ubuntu Mono,DejaVu Sans Mono,Nimbus Mono L,Liberation Mono,Courier 10 "
-     L"Pitch,FreeMono",
-     0, 1252},
-    {0x574d4d3d, L"AdobeArabic", L"Droid Sans Japanese,DejaVu Sans", 0, 1252},
-    {0x5792e759, L"STKaiti", L"WenQuanYi Micro Hei Mono", 0, 936},
-    {0x5921978e, L"LucidaSansUnicode", L"Droid Sans Japanese,DejaVu Sans", 0,
+    {0x4bf88566, "SegoeCondensed", "FreeSerif", 0, 1252},
+    {0x4ccf51a4, "BerlinSansFB-Reg", "Droid Sans Japanese,Liberation Serif", 0,
      1252},
-    {0x594e2da4, L"Vrinda",
-     L"Droid Arabic Naskh,Droid Sans Ethiopic,Droid Arabic "
-     L"Naskh,mry_KacstQurn,Droid Sans Japanese,FreeSans,FreeSerif",
-     0, 1252},
-    {0x59baa9a2, L"KaiTi_GB2312",
-     L"WenQuanYi Zen Hei Mono,WenQuanYi Zen Hei,WenQuanYi Zen Hei "
-     L"Sharp,WenQuanYi Micro Hei",
-     0, 1252},
-    {0x5cfedf4f, L"BaskOldFace",
-     L"KacstQurn,Droid Sans Japanese,Ubuntu,Liberation Serif", 0, 1252},
-    {0x5e16ac91, L"TrajanPro",
-     L"Nimbus Sans L,AR PL UMing HK,AR PL UKai HK,AR PL UMing TW,AR PL UMing "
-     L"TW MBE,DejaVu Sans,DejaVu Serif",
-     0, 1252},
-    {0x5f388196, L"ITCLegacySansStdMedium",
-     L"Liberation Serif,FreeSerif,FreeSans,Ubuntu", 0, 1252},
-    {0x5f97921c, L"AdobeMyungjoStdM",
-     L"WenQuanYi Zen Hei Mono,WenQuanYi Zen Hei,WenQuanYi Zen Hei "
-     L"Sharp,WenQuanYi Micro Hei",
+    {0x4ea967ce, "GulimChe",
+     "WenQuanYi Zen Hei Mono,AR PL UKai CN,AR PL UKai HK,AR PL UKai TW,AR PL "
+     "UKai TW MBE",
+     1, 1252},
+    {0x4f68bd79, "LetterGothicStd",
+     "FreeMono,Liberation Mono,Andale Mono,WenQuanYi Micro Hei Mono", 0, 1252},
+    {0x51a0d0e6, "KozukaGothicPr6NM", "FreeSerif", 0, 1252},
+    {0x531b3dea, "BasemicSymbol", "FreeSerif", 0, 1252},
+    {0x5333fd39, "CalifornianFB-Reg",
+     "Droid Sans Japanese,URW Chancery L,FreeSerif", 2, 1252},
+    {0x53561a54, "FZYTK--GBK1-0",
+     "WenQuanYi Zen Hei Mono,WenQuanYi Zen Hei,WenQuanYi Zen Hei "
+     "Sharp,WenQuanYi Micro Hei",
      0, 936},
-    {0x5fefbfad, L"Batang",
-     L"WenQuanYi Zen Hei Mono,WenQuanYi Zen Hei,WenQuanYi Zen Hei "
-     L"Sharp,WenQuanYi Micro Hei",
+    {0x55e0dde6, "LucidaSansTypewriter",
+     "Ubuntu Mono,DejaVu Sans Mono,Nimbus Mono L,Liberation Mono,Courier 10 "
+     "Pitch,FreeMono",
+     0, 1252},
+    {0x574d4d3d, "AdobeArabic", "Droid Sans Japanese,DejaVu Sans", 0, 1252},
+    {0x5792e759, "STKaiti", "WenQuanYi Micro Hei Mono", 0, 936},
+    {0x5921978e, "LucidaSansUnicode", "Droid Sans Japanese,DejaVu Sans", 0,
+     1252},
+    {0x594e2da4, "Vrinda",
+     "Droid Arabic Naskh,Droid Sans Ethiopic,Droid Arabic "
+     "Naskh,mry_KacstQurn,Droid Sans Japanese,FreeSans,FreeSerif",
+     0, 1252},
+    {0x59baa9a2, "KaiTi_GB2312",
+     "WenQuanYi Zen Hei Mono,WenQuanYi Zen Hei,WenQuanYi Zen Hei "
+     "Sharp,WenQuanYi Micro Hei",
+     0, 1252},
+    {0x5cfedf4f, "BaskOldFace",
+     "KacstQurn,Droid Sans Japanese,Ubuntu,Liberation Serif", 0, 1252},
+    {0x5e16ac91, "TrajanPro",
+     "Nimbus Sans L,AR PL UMing HK,AR PL UKai HK,AR PL UMing TW,AR PL UMing "
+     "TW MBE,DejaVu Sans,DejaVu Serif",
+     0, 1252},
+    {0x5f388196, "ITCLegacySansStdMedium",
+     "Liberation Serif,FreeSerif,FreeSans,Ubuntu", 0, 1252},
+    {0x5f97921c, "AdobeMyungjoStdM",
+     "WenQuanYi Zen Hei Mono,WenQuanYi Zen Hei,WenQuanYi Zen Hei "
+     "Sharp,WenQuanYi Micro Hei",
+     0, 936},
+    {0x5fefbfad, "Batang",
+     "WenQuanYi Zen Hei Mono,WenQuanYi Zen Hei,WenQuanYi Zen Hei "
+     "Sharp,WenQuanYi Micro Hei",
      2, 1252},
-    {0x605342b9, L"DotumChe",
-     L"WenQuanYi Zen Hei Mono,AR PL UMing CN,AR PL UMing HK,AR PL UMing TW", 1,
+    {0x605342b9, "DotumChe",
+     "WenQuanYi Zen Hei Mono,AR PL UMing CN,AR PL UMing HK,AR PL UMing TW", 1,
      1252},
-    {0x608c5f9a, L"KaiTi_GB2312",
-     L"WenQuanYi Zen Hei Mono,WenQuanYi Zen Hei,WenQuanYi Zen Hei "
-     L"Sharp,WenQuanYi Micro Hei",
+    {0x608c5f9a, "KaiTi_GB2312",
+     "WenQuanYi Zen Hei Mono,WenQuanYi Zen Hei,WenQuanYi Zen Hei "
+     "Sharp,WenQuanYi Micro Hei",
      0, 936},
-    {0x61efd0d1, L"MaturaMTScriptCapitals",
-     L"KacstQurn,Droid Arabic Naskh,Droid Sans Ethiopic,mry_KacstQurn,Droid "
-     L"Sans Japanese,DejaVu Serif,DejaVu Sans",
+    {0x61efd0d1, "MaturaMTScriptCapitals",
+     "KacstQurn,Droid Arabic Naskh,Droid Sans Ethiopic,mry_KacstQurn,Droid "
+     "Sans Japanese,DejaVu Serif,DejaVu Sans",
      0, 1252},
-    {0x626608a9, L"MVBoli",
-     L"Droid Arabic Naskh,Droid Sans Ethiopic,mry_KacstQurn,Droid Sans "
-     L"Ethiopic,Droid Sans Japanese,DejaVu Sans",
+    {0x626608a9, "MVBoli",
+     "Droid Arabic Naskh,Droid Sans Ethiopic,mry_KacstQurn,Droid Sans "
+     "Ethiopic,Droid Sans Japanese,DejaVu Sans",
      0, 1252},
-    {0x630501a3, L"SmallFonts", L"DejaVu Serif", 0, 1252},
-    {0x65d0e2a9, L"FZYTK--GBK1-0",
-     L"WenQuanYi Zen Hei Mono,WenQuanYi Zen Hei,WenQuanYi Zen Hei "
-     L"Sharp,WenQuanYi Micro Hei",
+    {0x630501a3, "SmallFonts", "DejaVu Serif", 0, 1252},
+    {0x65d0e2a9, "FZYTK--GBK1-0",
+     "WenQuanYi Zen Hei Mono,WenQuanYi Zen Hei,WenQuanYi Zen Hei "
+     "Sharp,WenQuanYi Micro Hei",
      0, 936},
-    {0x669f29e1, L"FZSTK--GBK1-0",
-     L"AR PL UMing CN,AR PL UKai CN, AR PL UMing HK", 0, 936},
-    {0x673a9e5f, L"Tunga",
-     L"Droid Arabic Naskh,Droid Sans Ethiopic,mry_KacstQurn,Droid Sans "
-     L"Japanese,DejaVu Serif",
+    {0x669f29e1, "FZSTK--GBK1-0",
+     "AR PL UMing CN,AR PL UKai CN, AR PL UMing HK", 0, 936},
+    {0x673a9e5f, "Tunga",
+     "Droid Arabic Naskh,Droid Sans Ethiopic,mry_KacstQurn,Droid Sans "
+     "Japanese,DejaVu Serif",
      0, 1252},
-    {0x691aa4ce, L"NiagaraSolid", L"Droid Sans Japanese,DejaVu Serif", 0, 1252},
-    {0x696259b7, L"Corbel", L"Droid Sans Japanese,DejaVu Sans", 0, 1252},
-    {0x696ee9be, L"STXihei", L"WenQuanYi Micro Hei Mono", 0, 936},
-    {0x6c59cf69, L"Dotum", L"WenQuanYi Zen Hei Mono", 0, 1252},
-    {0x707fa561, L"Gungsuh", L"WenQuanYi Zen Hei Mono", 2, 1252},
-    {0x71416bb2, L"ZWAdobeF",
-     L"KacstArt,KacstBookm,KacstDecorative,KacstDigital,KacstFarsi,KacstLetter,"
-     L"KacstOffice,Dingbats,FreeSerif",
+    {0x691aa4ce, "NiagaraSolid", "Droid Sans Japanese,DejaVu Serif", 0, 1252},
+    {0x696259b7, "Corbel", "Droid Sans Japanese,DejaVu Sans", 0, 1252},
+    {0x696ee9be, "STXihei", "WenQuanYi Micro Hei Mono", 0, 936},
+    {0x6c59cf69, "Dotum", "WenQuanYi Zen Hei Mono", 0, 1252},
+    {0x707fa561, "Gungsuh", "WenQuanYi Zen Hei Mono", 2, 1252},
+    {0x71416bb2, "ZWAdobeF",
+     "KacstArt,KacstBookm,KacstDecorative,KacstDigital,KacstFarsi,KacstLetter,"
+     "KacstOffice,Dingbats,FreeSerif",
      0, 1252},
-    {0x71b41801, L"Verdana",
-     L"DejaVu Sans Condensed,Ubuntu Condensed,Droid Sans Japanese,DejaVu Sans",
+    {0x71b41801, "Verdana",
+     "DejaVu Sans Condensed,Ubuntu Condensed,Droid Sans Japanese,DejaVu Sans",
      0, 1252},
-    {0x73f25e4c, L"PalatinoLinotype", L"Droid Sans Japanese,FreeSerif", 0,
+    {0x73f25e4c, "PalatinoLinotype", "Droid Sans Japanese,FreeSerif", 0, 1252},
+    {0x73f4d19f, "NiagaraEngraved", "Droid Sans Japanese,FreeSerif", 0, 1252},
+    {0x74001694, "MyriadProBlack", "Droid Sans Japanese,AR PL UKai HK", 0,
      1252},
-    {0x73f4d19f, L"NiagaraEngraved", L"Droid Sans Japanese,FreeSerif", 0, 1252},
-    {0x74001694, L"MyriadProBlack", L"Droid Sans Japanese,AR PL UKai HK", 0,
+    {0x74b14d8f, "Haettenschweiler", "Droid Sans Japanese,DejaVu Serif", 0,
      1252},
-    {0x74b14d8f, L"Haettenschweiler", L"Droid Sans Japanese,DejaVu Serif", 0,
-     1252},
-    {0x74cb44ee, L"NSimSun", L"WenQuanYi Zen Hei Mono", 1, 936},
-    {0x76b4d7ff, L"Shruti",
-     L"Droid Arabic Naskh,Droid Sans Ethiopic,mry_KacstQurn,Droid Sans "
-     L"Japanese,FreeSans",
+    {0x74cb44ee, "NSimSun", "WenQuanYi Zen Hei Mono", 1, 936},
+    {0x76b4d7ff, "Shruti",
+     "Droid Arabic Naskh,Droid Sans Ethiopic,mry_KacstQurn,Droid Sans "
+     "Japanese,FreeSans",
      0, 1252},
-    {0x788b3533, L"Webdings", L"FreeSans", 6, 42},
-    {0x797dde99, L"MSSerif", L"FreeSans", 0, 1252},
-    {0x7a0f9e9e, L"MSMincho",
-     L"WenQuanYi Micro Hei Mono,AR PL UMing CN,AR PL UMing HK,AR PL UMing TW",
-     1, 1252},
-    {0x7b439caf, L"OldEnglishTextMT",
-     L"Droid Sans Japanese,Liberation Sans,Ubuntu", 0, 1252},
-    {0x8213a433, L"LucidaSans-Typewriter",
-     L"Ubuntu Mono,Liberation Mono,DejaVu Sans Mono", 0, 1252},
-    {0x82fec929, L"AdobeSongStdL",
-     L"WenQuanYi Zen Hei Mono,WenQuanYi Zen Hei,WenQuanYi Zen Hei "
-     L"Sharp,WenQuanYi Micro Hei",
+    {0x788b3533, "Webdings", "FreeSans", 6, 42},
+    {0x797dde99, "MSSerif", "FreeSans", 0, 1252},
+    {0x7a0f9e9e, "MSMincho",
+     "WenQuanYi Micro Hei Mono,AR PL UMing CN,AR PL UMing HK,AR PL UMing TW", 1,
+     1252},
+    {0x7b439caf, "OldEnglishTextMT",
+     "Droid Sans Japanese,Liberation Sans,Ubuntu", 0, 1252},
+    {0x8213a433, "LucidaSans-Typewriter",
+     "Ubuntu Mono,Liberation Mono,DejaVu Sans Mono", 0, 1252},
+    {0x82fec929, "AdobeSongStd",
+     "WenQuanYi Zen Hei Mono,WenQuanYi Zen Hei,WenQuanYi Zen Hei "
+     "Sharp,WenQuanYi Micro Hei",
      0, 936},
-    {0x83581825, L"Modern", L"FreeSans", 0, 1252},
-    {0x835a2823, L"Algerian",
-     L"KacstQurn,Droid Sans Japanese,FreeSans,Liberation Sans,Ubuntu", 0, 1252},
-    {0x83dab9f5, L"Script", L"FreeSans", 0, 1252},
-    {0x847b56da, L"Tahoma",
-     L"Droid Sans Japanese,DejaVu Sans Condensed,FreeSerif", 0, 1252},
-    {0x8a783cb2, L"SimSun-PUA",
-     L"WenQuanYi Zen Hei Mono,WenQuanYi Zen Hei,WenQuanYi Zen Hei "
-     L"Sharp,WenQuanYi Micro Hei",
+    {0x83581825, "Modern", "FreeSans", 0, 1252},
+    {0x835a2823, "Algerian",
+     "KacstQurn,Droid Sans Japanese,FreeSans,Liberation Sans,Ubuntu", 0, 1252},
+    {0x83dab9f5, "Script", "FreeSans", 0, 1252},
+    {0x847b56da, "Tahoma",
+     "Droid Sans Japanese,DejaVu Sans Condensed,FreeSerif", 0, 1252},
+    {0x8a783cb2, "SimSun-PUA",
+     "WenQuanYi Zen Hei Mono,WenQuanYi Zen Hei,WenQuanYi Zen Hei "
+     "Sharp,WenQuanYi Micro Hei",
      0, 1252},
-    {0x8b5cac0e, L"Onyx", L"Droid Sans Japanese,Liberation Sans", 0, 1252},
-    {0x8c6a499e, L"Gulim",
-     L"WenQuanYi Zen Hei Mono,WenQuanYi Zen Hei,WenQuanYi Zen Hei "
-     L"Sharp,WenQuanYi Micro Hei",
+    {0x8b5cac0e, "Onyx", "Droid Sans Japanese,Liberation Sans", 0, 1252},
+    {0x8c6a499e, "Gulim",
+     "WenQuanYi Zen Hei Mono,WenQuanYi Zen Hei,WenQuanYi Zen Hei "
+     "Sharp,WenQuanYi Micro Hei",
      0, 1252},
-    {0x8e0af790, L"JuiceITC", L"Droid Sans Japanese,Liberation Sans", 0, 1252},
-    {0x8e8d43b2, L"Centaur",
-     L"KacstQurn,Droid Sans Japanese,Khmer OS,Khmer OS System", 2, 1252},
-    {0x8ee4dcca, L"BookshelfSymbol7", L"Liberation Sans", 0, 1252},
-    {0x90794800, L"BellGothicStdLight", L"Liberation Sans", 0, 1252},
-    {0x909b516a, L"Century",
-     L"Droid Sans Japanese,Liberation Sans,Liberation Mono,Liberation Serif", 2,
+    {0x8e0af790, "JuiceITC", "Droid Sans Japanese,Liberation Sans", 0, 1252},
+    {0x8e8d43b2, "Centaur",
+     "KacstQurn,Droid Sans Japanese,Khmer OS,Khmer OS System", 2, 1252},
+    {0x8ee4dcca, "BookshelfSymbol7", "Liberation Sans", 0, 1252},
+    {0x90794800, "BellGothicStdLight", "Liberation Sans", 0, 1252},
+    {0x909b516a, "Century",
+     "Droid Sans Japanese,Liberation Sans,Liberation Mono,Liberation Serif", 2,
      1252},
-    {0x92ae370d, L"MSOutlook", L"Liberation Sans", 4, 42},
-    {0x93c9fbf1, L"LucidaFax",
-     L"KacstQurn,Droid Arabic Naskh,Droid Sans "
-     L"Ethiopic,mry_KacstQurn,Liberation Sans",
+    {0x92ae370d, "MSOutlook", "Liberation Sans", 4, 42},
+    {0x93c9fbf1, "LucidaFax",
+     "KacstQurn,Droid Arabic Naskh,Droid Sans "
+     "Ethiopic,mry_KacstQurn,Liberation Sans",
      2, 1252},
-    {0x9565085e, L"BookAntiqua",
-     L"Droid Sans Japanese,Liberation Sans,Liberation Serif", 2, 1252},
-    {0x9856d95d, L"AdobeMingStdL", L"AR PL UMing HK", 0, 949},
-    {0x9bbadd6b, L"ColonnaMT",
-     L"KacstQurn,Droid Sans Japanese,Khmer OS,Khmer OS System", 0, 1252},
-    {0x9cbd16a4, L"ShowcardGothic-Reg",
-     L"Droid Sans Japanese,Liberation Sans,Ubuntu", 0, 1252},
-    {0x9d73008e, L"MSSansSerif", L"FreeSerif", 0, 1252},
-    {0xa0607db1, L"GungsuhChe",
-     L"WenQuanYi Zen Hei Mono,WenQuanYi Zen Hei,WenQuanYi Zen Hei "
-     L"Sharp,WenQuanYi Micro Hei",
+    {0x9565085e, "BookAntiqua",
+     "Droid Sans Japanese,Liberation Sans,Liberation Serif", 2, 1252},
+    {0x9856d95d, "AdobeMingStd", "AR PL UMing HK", 0, 949},
+    {0x9bbadd6b, "ColonnaMT",
+     "KacstQurn,Droid Sans Japanese,Khmer OS,Khmer OS System", 0, 1252},
+    {0x9cbd16a4, "ShowcardGothic-Reg",
+     "Droid Sans Japanese,Liberation Sans,Ubuntu", 0, 1252},
+    {0x9d73008e, "MSSansSerif", "FreeSerif", 0, 1252},
+    {0xa0607db1, "GungsuhChe",
+     "WenQuanYi Zen Hei Mono,WenQuanYi Zen Hei,WenQuanYi Zen Hei "
+     "Sharp,WenQuanYi Micro Hei",
      1, 1252},
-    {0xa0bcf6a1, L"LatinWide", L"FreeSerif", 2, 1252},
-    {0xa1429b36, L"Symbol", L"FreeSerif", 6, 42},
-    {0xa1fa5abc, L"Wingdings2", L"FreeSerif", 6, 42},
-    {0xa1fa5abd, L"Wingdings3", L"FreeSerif", 6, 42},
-    {0xa427bad4, L"InformalRoman-Regular",
-     L"Droid Arabic Naskh,Droid Sans Ethiopic,mry_KacstQurn,Droid Sans "
-     L"Japanese,FreeSerif",
+    {0xa0bcf6a1, "LatinWide", "FreeSerif", 2, 1252},
+    {0xa1429b36, "Symbol", "FreeSerif", 6, 42},
+    {0xa1fa5abc, "Wingdings2", "FreeSerif", 6, 42},
+    {0xa1fa5abd, "Wingdings3", "FreeSerif", 6, 42},
+    {0xa427bad4, "InformalRoman-Regular",
+     "Droid Arabic Naskh,Droid Sans Ethiopic,mry_KacstQurn,Droid Sans "
+     "Japanese,FreeSerif",
      8, 1252},
-    {0xa8b92ece, L"FZSTK--GBK1-0", L"AR PL UMing CN", 0, 936},
-    {0xa8d83ece, L"CalifornianFB", L"Droid Sans Japanese,FreeSerif", 2, 1252},
-    {0xaa3e082c, L"Kingsoft-Phonetic",
-     L"Tibetan Machine Uni,LKLUG,Samyak Gujarati,Droid Sans "
-     L"Thai,utkal,Kedage,Mallige,AR PL UKai CN",
+    {0xa8b92ece, "FZSTK--GBK1-0", "AR PL UMing CN", 0, 936},
+    {0xa8d83ece, "CalifornianFB", "Droid Sans Japanese,FreeSerif", 2, 1252},
+    {0xaa3e082c, "Kingsoft-Phonetic",
+     "Tibetan Machine Uni,LKLUG,Samyak Gujarati,Droid Sans "
+     "Thai,utkal,Kedage,Mallige,AR PL UKai CN",
      0, 1252},
-    {0xaa6bcabe, L"HarlowSolidItalic",
-     L"KacstQurn,Droid Sans Japanese,Liberation Serif", 0, 1252},
-    {0xade5337c, L"MSUIGothic",
-     L"WenQuanYi Zen Hei Mono,WenQuanYi Zen Hei,WenQuanYi Zen Hei "
-     L"Sharp,WenQuanYi Micro Hei",
+    {0xaa6bcabe, "HarlowSolidItalic",
+     "KacstQurn,Droid Sans Japanese,Liberation Serif", 0, 1252},
+    {0xade5337c, "MSUIGothic",
+     "WenQuanYi Zen Hei Mono,WenQuanYi Zen Hei,WenQuanYi Zen Hei "
+     "Sharp,WenQuanYi Micro Hei",
      0, 1252},
-    {0xb08dd941, L"WideLatin",
-     L"KacstQurn,Droid Arabic Naskh,Droid Sans Ethiopic,mry_KacstQurn,Droid "
-     L"Sans Japanese,Liberation Serif",
+    {0xb08dd941, "WideLatin",
+     "KacstQurn,Droid Arabic Naskh,Droid Sans Ethiopic,mry_KacstQurn,Droid "
+     "Sans Japanese,Liberation Serif",
      2, 1252},
-    {0xb12765e0, L"ITCLegacySansStdBook",
-     L"AR PL UMing HK,AR PL UKai HK,FreeSerif,Ubuntu,FreeSans", 0, 1252},
-    {0xb207f05d, L"PoorRichard", L"Droid Sans Japanese,Liberation Serif", 2,
+    {0xb12765e0, "ITCLegacySansStdBook",
+     "AR PL UMing HK,AR PL UKai HK,FreeSerif,Ubuntu,FreeSans", 0, 1252},
+    {0xb207f05d, "PoorRichard", "Droid Sans Japanese,Liberation Serif", 2,
      1252},
-    {0xb3bc492f, L"JuiceITC-Regular", L"Droid Sans Japanese,Liberation Serif",
-     0, 1252},
-    {0xb5545399, L"Marlett", L"Liberation Serif", 4, 42},
-    {0xb5dd1ebb, L"BritannicBold",
-     L"KacstQurn,Droid Arabic Naskh,Droid Sans "
-     L"Ethiopic,mry_KacstQurn,Liberation Serif",
-     0, 1252},
-    {0xb699c1c5, L"LucidaCalligraphy-Italic",
-     L"KacstQurn,Droid Arabic Naskh,Droid Sans Ethiopic,mry_KacstQurn,Droid "
-     L"Sans Japanese,DejaVu Serif",
-     0, 1252},
-    {0xb725d629, L"TimesNewRoman", L"Droid Sans Japanese,Liberation Sans", 2,
+    {0xb3bc492f, "JuiceITC-Regular", "Droid Sans Japanese,Liberation Serif", 0,
      1252},
-    {0xb7eaebeb, L"AdobeHeitiStdR",
-     L"WenQuanYi Zen Hei Mono,WenQuanYi Zen Hei,WenQuanYi Zen Hei "
-     L"Sharp,WenQuanYi Micro Hei",
+    {0xb5545399, "Marlett", "Liberation Serif", 4, 42},
+    {0xb5dd1ebb, "BritannicBold",
+     "KacstQurn,Droid Arabic Naskh,Droid Sans "
+     "Ethiopic,mry_KacstQurn,Liberation Serif",
+     0, 1252},
+    {0xb699c1c5, "LucidaCalligraphy-Italic",
+     "KacstQurn,Droid Arabic Naskh,Droid Sans Ethiopic,mry_KacstQurn,Droid "
+     "Sans Japanese,DejaVu Serif",
+     0, 1252},
+    {0xb725d629, "TimesNewRoman", "Droid Sans Japanese,Liberation Sans", 2,
+     1252},
+    {0xb7eaebeb, "AdobeHeitiStdR",
+     "WenQuanYi Zen Hei Mono,WenQuanYi Zen Hei,WenQuanYi Zen Hei "
+     "Sharp,WenQuanYi Micro Hei",
      0, 936},
-    {0xbd29c486, L"BerlinSansFBDemi-Bold", L"Droid Sans Japanese,DejaVu Serif",
+    {0xbd29c486, "BerlinSansFBDemi-Bold", "Droid Sans Japanese,DejaVu Serif", 0,
+     1252},
+    {0xbe8a8db4, "BookshelfSymbolSeven", "DejaVu Sans", 0, 1252},
+    {0xc16c0118, "AdobeHebrew", "Droid Sans Japanese,Ubuntu,Liberation Serif",
      0, 1252},
-    {0xbe8a8db4, L"BookshelfSymbolSeven", L"DejaVu Sans", 0, 1252},
-    {0xc16c0118, L"AdobeHebrew", L"Droid Sans Japanese,Ubuntu,Liberation Serif",
-     0, 1252},
-    {0xc318b0af, L"MyriadProLight",
-     L"Droid Sans Japanese,AR PL UKai HK,AR PL UMing HK,AR PL UKai CN", 0,
+    {0xc318b0af, "MyriadProLight",
+     "Droid Sans Japanese,AR PL UKai HK,AR PL UMing HK,AR PL UKai CN", 0, 1252},
+    {0xc65e5659, "CambriaMath", "Droid Sans Japanese,FreeSerif,FreeMono", 2,
      1252},
-    {0xc65e5659, L"CambriaMath", L"Droid Sans Japanese,FreeSerif,FreeMono", 2,
+    {0xc75c8f05, "LucidaConsole",
+     "Liberation Mono,DejaVu Sans Mono,FreeMono,WenQuanYi Micro Hei Mono", 1,
      1252},
-    {0xc75c8f05, L"LucidaConsole",
-     L"Liberation Mono,DejaVu Sans Mono,FreeMono,WenQuanYi Micro Hei Mono", 1,
-     1252},
-    {0xca7c35d6, L"Calibri", L"Droid Sans Japanese,DejaVu Sans", 0, 1252},
-    {0xcb053f53, L"MicrosoftYaHei",
-     L"WenQuanYi Zen Hei Mono,WenQuanYi Zen Hei,WenQuanYi Zen Hei "
-     L"Sharp,WenQuanYi Micro Hei",
+    {0xca7c35d6, "Calibri", "Droid Sans Japanese,DejaVu Sans", 0, 1252},
+    {0xcb053f53, "MicrosoftYaHei",
+     "WenQuanYi Zen Hei Mono,WenQuanYi Zen Hei,WenQuanYi Zen Hei "
+     "Sharp,WenQuanYi Micro Hei",
      0, 936},
-    {0xcb7190f9, L"Magneto-Bold",
-     L"Droid Arabic Naskh,Droid Sans Ethiopic,mry_KacstQurn,Droid Sans "
-     L"Japanese,DejaVu Serif",
+    {0xcb7190f9, "Magneto-Bold",
+     "Droid Arabic Naskh,Droid Sans Ethiopic,mry_KacstQurn,Droid Sans "
+     "Japanese,DejaVu Serif",
      0, 1252},
-    {0xcca00cc5, L"System", L"DejaVu Sans", 0, 1252},
-    {0xccad6f76, L"Jokerman-Regular", L"Droid Sans Japanese,DejaVu Sans", 0,
+    {0xcca00cc5, "System", "DejaVu Sans", 0, 1252},
+    {0xccad6f76, "Jokerman-Regular", "Droid Sans Japanese,DejaVu Sans", 0,
      1252},
-    {0xccc5818c, L"EuroSign", L"DejaVu Serif", 0, 1252},
-    {0xcf3d7234, L"LucidaHandwriting-Italic",
-     L"Liberation Sans Narrow,Ubuntu Condensed,Nimbus Sans L,DejaVu Serif", 0,
+    {0xccc5818c, "EuroSign", "DejaVu Serif", 0, 1252},
+    {0xcf3d7234, "LucidaHandwriting-Italic",
+     "Liberation Sans Narrow,Ubuntu Condensed,Nimbus Sans L,DejaVu Serif", 0,
      1252},
-    {0xcf7b8fdb, L"MinionPro", L"DejaVu Sans", 0, 1252},
-    {0xcfe5755f, L"Simhei",
-     L"WenQuanYi Zen Hei Mono,WenQuanYi Zen Hei,WenQuanYi Zen Hei "
-     L"Sharp,WenQuanYi Micro Hei",
+    {0xcf7b8fdb, "MinionPro", "DejaVu Sans", 0, 1252},
+    {0xcfe5755f, "Simhei",
+     "WenQuanYi Zen Hei Mono,WenQuanYi Zen Hei,WenQuanYi Zen Hei "
+     "Sharp,WenQuanYi Micro Hei",
      1, 936},
-    {0xd011f4ee, L"MSPGothic",
-     L"WenQuanYi Zen Hei Mono,AR PL UMing CN,AR PL UMing HK,AR PL UMing TW", 0,
+    {0xd011f4ee, "MSPGothic",
+     "WenQuanYi Zen Hei Mono,AR PL UMing CN,AR PL UMing HK,AR PL UMing TW", 0,
      1252},
-    {0xd060e7ef, L"Vivaldi",
-     L"KacstQurn,Droid Sans Japanese,Liberation Sans,Ubuntu", 8, 1252},
-    {0xd07edec1, L"FranklinGothic-Medium", L"Droid Sans Japanese,Ubuntu", 0,
+    {0xd060e7ef, "Vivaldi",
+     "KacstQurn,Droid Sans Japanese,Liberation Sans,Ubuntu", 8, 1252},
+    {0xd07edec1, "FranklinGothic-Medium", "Droid Sans Japanese,Ubuntu", 0,
      1252},
-    {0xd107243f, L"SimSun", L"WenQuanYi Zen Hei Mono", 0, 936},
-    {0xd1881562, L"ArialNarrow",
-     L"Liberation Sans Narrow,Droid Sans Japanese,FreeSerif", 0, 1252},
-    {0xd22b7dce, L"BodoniMTPosterCompressed",
-     L"Droid Sans Japanese,DejaVu Serif", 0, 1252},
-    {0xd22bfa60, L"ComicSansMS",
-     L"Droid Sans Japanese,FreeMono,Liberation Mono", 8, 1252},
-    {0xd3bd0e35, L"Bauhaus93",
-     L"KacstQurn,Droid Sans Japanese,Liberation Sans,Ubuntu", 0, 1252},
-    {0xd429ee7a, L"STFangsong", L"WenQuanYi Micro Hei Mono", 0, 936},
-    {0xd6679c12, L"BernardMTCondensed",
-     L"KacstQurn,Droid Sans Japanese,Nimbus Sans L,URW Chancery "
-     L"L,KacstOne,Liberation Sans",
+    {0xd107243f, "SimSun", "WenQuanYi Zen Hei Mono", 0, 936},
+    {0xd1881562, "ArialNarrow",
+     "Liberation Sans Narrow,Droid Sans Japanese,FreeSerif", 0, 1252},
+    {0xd22b7dce, "BodoniMTPosterCompressed", "Droid Sans Japanese,DejaVu Serif",
      0, 1252},
-    {0xd8e8a027, L"LucidaSans",
-     L"Liberation Sans Narrow,Nimbus Sans L,KacstQurn,Droid Arabic Naskh,Droid "
-     L"Sans Ethiopic,DejaVu Serif Condensed,Liberation Mono,Ubuntu",
-     0, 1252},
-    {0xd9fe7761, L"HighTowerText-Reg",
-     L"Droid Sans Japanese,Ubuntu,Liberation Serif", 2, 1252},
-    {0xda7e551e, L"STSong", L"WenQuanYi Micro Hei Mono", 0, 936},
-    {0xdaa6842d, L"STZhongsong",
-     L"WenQuanYi Zen Hei Mono,WenQuanYi Zen Hei,WenQuanYi Zen Hei "
-     L"Sharp,WenQuanYi Micro Hei",
-     0, 936},
-    {0xdaaab93f, L"STFangsong",
-     L"WenQuanYi Micro Hei Mono,WenQuanYi Zen Hei Mono,WenQuanYi Zen "
-     L"Hei,WenQuanYi Zen Hei Sharp",
-     0, 936},
-    {0xdaeb0713, L"STSong",
-     L"WenQuanYi Micro Hei Mono,WenQuanYi Zen Hei Mono,WenQuanYi Zen "
-     L"Hei,WenQuanYi Zen Hei Sharp",
-     0, 936},
-    {0xdafedbef, L"STCaiyun", L"AR PL UKai HK,AR PL UMing HK,AR PL UKai CN", 0,
-     936},
-    {0xdb00a3d9, L"Broadway",
-     L"KacstQurn,Droid Sans Japanese,DejaVu Sans,FreeMono,Liberation Mono", 0,
-     1252},
-    {0xdb1f5ad4, L"STXinwei", L"AR PL UKai HK,AR PL UMing HK,AR PL UKai CN", 0,
-     936},
-    {0xdb326e7f, L"STKaiti",
-     L"WenQuanYi Micro Hei Mono,WenQuanYi Zen Hei Mono,WenQuanYi Zen "
-     L"Hei,WenQuanYi Zen Hei Sharp",
-     0, 936},
-    {0xdb69595a, L"STHupo",
-     L"WenQuanYi Micro Hei Mono,WenQuanYi Zen Hei Mono,WenQuanYi Zen "
-     L"Hei,WenQuanYi Zen Hei Sharp",
-     0, 936},
-    {0xdba0082c, L"STXihei",
-     L" WenQuanYi Micro Hei Mono,WenQuanYi Zen Hei Mono,WenQuanYi Zen "
-     L"Hei,WenQuanYi Zen Hei Sharp",
-     0, 936},
-    {0xdbd0ab18, L"STXingkai", L"AR PL UKai HK,AR PL UMing HK,AR PL UKai CN", 0,
-     936},
-    {0xdc1a7db1, L"STLiti", L"AR PL UKai HK,AR PL UMing HK,AR PL UKai CN", 0,
-     936},
-    {0xdc33075f, L"KristenITC-Regular",
-     L"Droid Arabic Naskh,Droid Sans Ethiopic,mry_KacstQurn,DejaVu Sans "
-     L"Condensed,Ubuntu,Liberation Sans",
+    {0xd22bfa60, "ComicSansMS", "Droid Sans Japanese,FreeMono,Liberation Mono",
      8, 1252},
-    {0xdcc7009c, L"Harrington",
-     L"KacstQurn,Droid Sans Japanese,Liberation Serif,FreeSerif,Ubuntu", 0,
-     1252},
-    {0xdd712466, L"ArialBlack",
-     L"Droid Sans Japanese,DejaVu Sans,DejaVu Serif,FreeMono", 0, 1252},
-    {0xdde87b3e, L"Impact", L"Droid Sans Japanese,DejaVu Serif", 0, 1252},
-    {0xdf69fb32, L"SnapITC",
-     L"Liberation Sans Narrow,Ubuntu Condensed,DejaVu Sans,DejaVu "
-     L"Serif,FreeMono",
+    {0xd3bd0e35, "Bauhaus93",
+     "KacstQurn,Droid Sans Japanese,Liberation Sans,Ubuntu", 0, 1252},
+    {0xd429ee7a, "STFangsong", "WenQuanYi Micro Hei Mono", 0, 936},
+    {0xd6679c12, "BernardMTCondensed",
+     "KacstQurn,Droid Sans Japanese,Nimbus Sans L,URW Chancery "
+     "L,KacstOne,Liberation Sans",
      0, 1252},
-    {0xdf8b25e8, L"CenturyGothic",
-     L"Droid Sans Japanese,Liberation Mono,Liberation Sans,Liberation Serif", 0,
+    {0xd8e8a027, "LucidaSans",
+     "Liberation Sans Narrow,Nimbus Sans L,KacstQurn,Droid Arabic Naskh,Droid "
+     "Sans Ethiopic,DejaVu Serif Condensed,Liberation Mono,Ubuntu",
+     0, 1252},
+    {0xd9fe7761, "HighTowerText-Reg",
+     "Droid Sans Japanese,Ubuntu,Liberation Serif", 2, 1252},
+    {0xda7e551e, "STSong", "WenQuanYi Micro Hei Mono", 0, 936},
+    {0xdaa6842d, "STZhongsong",
+     "WenQuanYi Zen Hei Mono,WenQuanYi Zen Hei,WenQuanYi Zen Hei "
+     "Sharp,WenQuanYi Micro Hei",
+     0, 936},
+    {0xdaaab93f, "STFangsong",
+     "WenQuanYi Micro Hei Mono,WenQuanYi Zen Hei Mono,WenQuanYi Zen "
+     "Hei,WenQuanYi Zen Hei Sharp",
+     0, 936},
+    {0xdaeb0713, "STSong",
+     "WenQuanYi Micro Hei Mono,WenQuanYi Zen Hei Mono,WenQuanYi Zen "
+     "Hei,WenQuanYi Zen Hei Sharp",
+     0, 936},
+    {0xdafedbef, "STCaiyun", "AR PL UKai HK,AR PL UMing HK,AR PL UKai CN", 0,
+     936},
+    {0xdb00a3d9, "Broadway",
+     "KacstQurn,Droid Sans Japanese,DejaVu Sans,FreeMono,Liberation Mono", 0,
      1252},
-    {0xe0f705c0, L"KristenITC",
-     L"Droid Arabic Naskh,Droid Sans Ethiopic,mry_KacstQurn,DejaVu Sans "
-     L"Condensed,Ubuntu,Liberation Sans",
+    {0xdb1f5ad4, "STXinwei", "AR PL UKai HK,AR PL UMing HK,AR PL UKai CN", 0,
+     936},
+    {0xdb326e7f, "STKaiti",
+     "WenQuanYi Micro Hei Mono,WenQuanYi Zen Hei Mono,WenQuanYi Zen "
+     "Hei,WenQuanYi Zen Hei Sharp",
+     0, 936},
+    {0xdb69595a, "STHupo",
+     "WenQuanYi Micro Hei Mono,WenQuanYi Zen Hei Mono,WenQuanYi Zen "
+     "Hei,WenQuanYi Zen Hei Sharp",
+     0, 936},
+    {0xdba0082c, "STXihei",
+     " WenQuanYi Micro Hei Mono,WenQuanYi Zen Hei Mono,WenQuanYi Zen "
+     "Hei,WenQuanYi Zen Hei Sharp",
+     0, 936},
+    {0xdbd0ab18, "STXingkai", "AR PL UKai HK,AR PL UMing HK,AR PL UKai CN", 0,
+     936},
+    {0xdc1a7db1, "STLiti", "AR PL UKai HK,AR PL UMing HK,AR PL UKai CN", 0,
+     936},
+    {0xdc33075f, "KristenITC-Regular",
+     "Droid Arabic Naskh,Droid Sans Ethiopic,mry_KacstQurn,DejaVu Sans "
+     "Condensed,Ubuntu,Liberation Sans",
      8, 1252},
-    {0xe1427573, L"Raavi",
-     L"Droid Arabic Naskh,Droid Sans "
-     L"Ethiopic,mry_KacstQurn,FreeSerif,Liberation Serif,Khmer OS",
-     0, 1252},
-    {0xe2cea0cb, L"Magneto",
-     L"Droid Arabic Naskh,Droid Sans Ethiopic,mry_KacstQurn,DejaVu "
-     L"Serif,DejaVu Serif Condensed,DejaVu Sans",
-     0, 1252},
-    {0xe36a9e17, L"Ravie",
-     L"Droid Arabic Naskh,Droid Sans Ethiopic,mry_KacstQurn,DejaVu "
-     L"Serif,DejaVu Sans,FreeMono",
-     0, 1252},
-    {0xe433f8e2, L"Parchment", L"Droid Sans Japanese,DejaVu Serif", 8, 1252},
-    {0xe43dff4a, L"Wingdings", L"DejaVu Serif", 4, 42},
-    {0xe4e2c405, L"MTExtra", L"DejaVu Serif", 6, 42},
-    {0xe618cc35, L"InformalRoman",
-     L"Droid Arabic Naskh,Droid Sans Ethiopic,mry_KacstQurn,Droid Sans "
-     L"Japanese,Nimbus Sans L,DejaVu Sans Condensed,Ubuntu,Liberation Sans",
-     8, 1252},
-    {0xe6c27ffc, L"Mistral", L"Droid Sans Japanese,DejaVu Serif", 8, 1252},
-    {0xe7ebf4b9, L"Courier", L"DejaVu Sans,DejaVu Sans Condensed,FreeSerif", 0,
+    {0xdcc7009c, "Harrington",
+     "KacstQurn,Droid Sans Japanese,Liberation Serif,FreeSerif,Ubuntu", 0,
      1252},
-    {0xe8bc4a9d, L"MSReferenceSpecialty", L"DejaVu Serif", 0, 1252},
-    {0xe90fb013, L"TempusSansITC",
-     L"Droid Sans Japanese,Ubuntu,Liberation Serif,FreeSerif", 0, 1252},
-    {0xec637b42, L"Consolas",
-     L"DejaVu Sans Condensed,AR PL UKai CN,AR PL UKai HK,AR PL UKai "
-     L"TW,FreeSerif,FreeSans",
+    {0xdd712466, "ArialBlack",
+     "Droid Sans Japanese,DejaVu Sans,DejaVu Serif,FreeMono", 0, 1252},
+    {0xdde87b3e, "Impact", "Droid Sans Japanese,DejaVu Serif", 0, 1252},
+    {0xdf69fb32, "SnapITC",
+     "Liberation Sans Narrow,Ubuntu Condensed,DejaVu Sans,DejaVu "
+     "Serif,FreeMono",
+     0, 1252},
+    {0xdf8b25e8, "CenturyGothic",
+     "Droid Sans Japanese,Liberation Mono,Liberation Sans,Liberation Serif", 0,
+     1252},
+    {0xe0f705c0, "KristenITC",
+     "Droid Arabic Naskh,Droid Sans Ethiopic,mry_KacstQurn,DejaVu Sans "
+     "Condensed,Ubuntu,Liberation Sans",
+     8, 1252},
+    {0xe1427573, "Raavi",
+     "Droid Arabic Naskh,Droid Sans "
+     "Ethiopic,mry_KacstQurn,FreeSerif,Liberation Serif,Khmer OS",
+     0, 1252},
+    {0xe2cea0cb, "Magneto",
+     "Droid Arabic Naskh,Droid Sans Ethiopic,mry_KacstQurn,DejaVu "
+     "Serif,DejaVu Serif Condensed,DejaVu Sans",
+     0, 1252},
+    {0xe36a9e17, "Ravie",
+     "Droid Arabic Naskh,Droid Sans Ethiopic,mry_KacstQurn,DejaVu "
+     "Serif,DejaVu Sans,FreeMono",
+     0, 1252},
+    {0xe433f8e2, "Parchment", "Droid Sans Japanese,DejaVu Serif", 8, 1252},
+    {0xe43dff4a, "Wingdings", "DejaVu Serif", 4, 42},
+    {0xe4e2c405, "MTExtra", "DejaVu Serif", 6, 42},
+    {0xe618cc35, "InformalRoman",
+     "Droid Arabic Naskh,Droid Sans Ethiopic,mry_KacstQurn,Droid Sans "
+     "Japanese,Nimbus Sans L,DejaVu Sans Condensed,Ubuntu,Liberation Sans",
+     8, 1252},
+    {0xe6c27ffc, "Mistral", "Droid Sans Japanese,DejaVu Serif", 8, 1252},
+    {0xe7ebf4b9, "Courier", "DejaVu Sans,DejaVu Sans Condensed,FreeSerif", 0,
+     1252},
+    {0xe8bc4a9d, "MSReferenceSpecialty", "DejaVu Serif", 0, 1252},
+    {0xe90fb013, "TempusSansITC",
+     "Droid Sans Japanese,Ubuntu,Liberation Serif,FreeSerif", 0, 1252},
+    {0xec637b42, "Consolas",
+     "DejaVu Sans Condensed,AR PL UKai CN,AR PL UKai HK,AR PL UKai "
+     "TW,FreeSerif,FreeSans",
      1, 1252},
-    {0xed3a683b, L"STXinwei", L"AR PL UKai HK,AR PL UMing HK,AR PL UKai CN", 0,
+    {0xed3a683b, "STXinwei", "AR PL UKai HK,AR PL UMing HK,AR PL UKai CN", 0,
      936},
-    {0xef264cd1, L"LucidaHandwriting",
-     L"Liberation Sans Narrow,Ubuntu Condensed,Nimbus Sans "
-     L"L,KacstQurn,Liberation Mono",
+    {0xef264cd1, "LucidaHandwriting",
+     "Liberation Sans Narrow,Ubuntu Condensed,Nimbus Sans "
+     "L,KacstQurn,Liberation Mono",
      0, 1252},
-    {0xf086bca2, L"BaskervilleOldFace",
-     L"KacstQurn,Droid Sans Japanese,Liberation Serif,Ubuntu,FreeSerif", 0,
+    {0xf086bca2, "BaskervilleOldFace",
+     "KacstQurn,Droid Sans Japanese,Liberation Serif,Ubuntu,FreeSerif", 0,
      1252},
-    {0xf1028030, L"Mangal",
-     L"FreeSans,TSCu_Paranar,Garuda,Liberation Sans,Liberation Sans "
-     L"Narrow,Nimbus Sans L",
+    {0xf1028030, "Mangal",
+     "FreeSans,TSCu_Paranar,Garuda,Liberation Sans,Liberation Sans "
+     "Narrow,Nimbus Sans ",
      2, 1252},
-    {0xf1da7eb9, L"ShowcardGothic",
-     L"Droid Sans Japanese,DejaVu Serif Condensed,DejaVu Sans "
-     L"Condensed,Liberation Sans,Ubuntu",
+    {0xf1da7eb9, "ShowcardGothic",
+     "Droid Sans Japanese,DejaVu Serif Condensed,DejaVu Sans "
+     "Condensed,Liberation Sans,Ubuntu",
      0, 1252},
-    {0xf210f06a, L"ArialMT",
-     L"Liberation Sans,Liberation Sans Narrow,FreeSans,Nimbus Sans L,Khmer OS "
-     L"System,Khmer OS",
+    {0xf210f06a, "ArialMT",
+     "Liberation Sans,Liberation Sans Narrow,FreeSans,Nimbus Sans L,Khmer OS "
+     "System,Khmer OS",
      0, 1252},
-    {0xf477f16a, L"Latha",
-     L"Liberation Sans Narrow,Nimbus Sans L,Droid Arabic "
-     L"Naskh,mry_KacstQurn,FreeSerif,Nimbus Sans L",
+    {0xf477f16a, "Latha",
+     "Liberation Sans Narrow,Nimbus Sans L,Droid Arabic "
+     "Naskh,mry_KacstQurn,FreeSerif,Nimbus Sans ",
      0, 1252},
-    {0xf616f3dd, L"LiSu",
-     L"WenQuanYi Zen Hei Mono,AR PL UMing CN,AR PL UMing HK,AR PL UMing TW,AR "
-     L"PL UMing TW MBE",
+    {0xf616f3dd, "LiSu",
+     "WenQuanYi Zen Hei Mono,AR PL UMing CN,AR PL UMing HK,AR PL UMing TW,AR "
+     "PL UMing TW MBE",
      1, 936},
-    {0xfa479aa6, L"MicrosoftYaHei",
-     L"WenQuanYi Zen Hei Mono,WenQuanYi Zen Hei,WenQuanYi Zen Hei "
-     L"Sharp,WenQuanYi Micro Hei",
+    {0xfa479aa6, "MicrosoftYaHei",
+     "WenQuanYi Zen Hei Mono,WenQuanYi Zen Hei,WenQuanYi Zen Hei "
+     "Sharp,WenQuanYi Micro Hei",
      0, 936},
-    {0xfcd19697, L"BookmanOldStyle",
-     L"Droid Sans Japanese,Liberation Mono,Liberation Sans,Liberation Serif", 0,
+    {0xfcd19697, "BookmanOldStyle",
+     "Droid Sans Japanese,Liberation Mono,Liberation Sans,Liberation Serif", 0,
      1252},
-    {0xfe209a82, L"LucidaCalligraphy",
-     L"KacstQurn,Droid Arabic Naskh,Droid Sans Ethiopic,mry_KacstQurn,Droid "
-     L"Sans Japanese,DejaVu Serif,DejaVu Sans,FreeMono",
+    {0xfe209a82, "LucidaCalligraphy",
+     "KacstQurn,Droid Arabic Naskh,Droid Sans Ethiopic,mry_KacstQurn,Droid "
+     "Sans Japanese,DejaVu Serif,DejaVu Sans,FreeMono",
      0, 1252},
-    {0xfef135f8, L"AdobeHeitiStd-Regular",
-     L"WenQuanYi Zen Hei Mono,WenQuanYi Zen Hei,WenQuanYi Zen Hei "
-     L"Sharp,WenQuanYi Micro Hei",
+    {0xfef135f8, "AdobeHeitiStd-Regular",
+     "WenQuanYi Zen Hei Mono,WenQuanYi Zen Hei,WenQuanYi Zen Hei "
+     "Sharp,WenQuanYi Micro Hei",
      0, 936},
 };
-#elif _FX_PLATFORM_ == _FX_PLATFORM_APPLE_
+#elif defined(OS_MACOSX)
 const FGAS_FontInfo g_XFAFontsMap[] = {
-    {0x01d5d33e, L"SimSun", L"STHeiti,Heiti TC,STFangsong", 0, 936},
-    {0x01e4f102, L"YouYuan", L"STHeiti,Heiti TC,STFangsong", 1, 936},
-    {0x030549dc, L"LiSu", L"STHeiti,Heiti TC,STFangsong", 1, 936},
-    {0x032edd44, L"Simhei", L"STHeiti,Heiti TC,STFangsong", 1, 936},
-    {0x03eac6fc, L"PoorRichard-Regular",
-     L"Noteworthy,Avenir Next Condensed,Impact", 2, 1252},
-    {0x03ed90e6, L"Nina", L"Microsoft Sans Serif", 0, 1252},
-    {0x077b56b3, L"KingsoftPhoneticPlain",
-     L"LastResort,Apple "
-     L"Chancery,STIXVariants,STIXSizeOneSym,STIXSizeOneSym,Apple Braille",
+    {0x01d5d33e, "SimSun", "STHeiti,Heiti TC,STFangsong", 0, 936},
+    {0x01e4f102, "YouYuan", "STHeiti,Heiti TC,STFangsong", 1, 936},
+    {0x030549dc, "LiSu", "STHeiti,Heiti TC,STFangsong", 1, 936},
+    {0x032edd44, "Simhei", "STHeiti,Heiti TC,STFangsong", 1, 936},
+    {0x03eac6fc, "PoorRichard-Regular",
+     "Noteworthy,Avenir Next Condensed,Impact", 2, 1252},
+    {0x03ed90e6, "Nina", "Microsoft Sans Serif", 0, 1252},
+    {0x077b56b3, "KingsoftPhoneticPlain",
+     "LastResort,Apple "
+     "Chancery,STIXVariants,STIXSizeOneSym,STIXSizeOneSym,Apple Braille",
      0, 1252},
-    {0x078ed524, L"MicrosoftSansSerif", L"Songti SC,Apple Symbols", 0, 1252},
-    {0x089b18a9, L"Arial",
-     L"Arial Unicode MS,Microsoft Sans Serif,Apple Symbols", 0, 1252},
-    {0x0b2cad72, L"MonotypeCorsiva", L"Arial Narrow,Impact", 8, 1252},
-    {0x0bb003e7, L"Kartika",
-     L"Arial Unicode MS,Microsoft Sans Serif,Arial Narrow,Damascus", 2, 1252},
-    {0x0bb469df, L"VinerHandITC", L"Comic Sans MS,Songti SC,STSong", 8, 1252},
-    {0x0bc1a851, L"SegoeUI", L"Apple Symbols", 0, 1252},
-    {0x0c112ebd, L"KozukaGothicPro-VIM", L"Microsoft Sans Serif,Apple Symbols",
+    {0x078ed524, "MicrosoftSansSerif", "Songti SC,Apple Symbols", 0, 1252},
+    {0x089b18a9, "Arial", "Arial Unicode MS,Microsoft Sans Serif,Apple Symbols",
      0, 1252},
-    {0x0cfcb9c1, L"AdobeThai", L"Avenir Next Condensed Ultra Light", 0, 847},
-    {0x0e7de0f9, L"Playbill", L"STIXNonUnicode", 0, 1252},
-    {0x0eff47c3, L"STHupo", L"Kaiti SC,Songti SC,STHeiti", 0, 936},
-    {0x107ad374, L"Constantia", L"Arial Unicode MS,Palatino,Baskerville", 2,
+    {0x0b2cad72, "MonotypeCorsiva", "Arial Narrow,Impact", 8, 1252},
+    {0x0bb003e7, "Kartika",
+     "Arial Unicode MS,Microsoft Sans Serif,Arial Narrow,Damascus", 2, 1252},
+    {0x0bb469df, "VinerHandITC", "Comic Sans MS,Songti SC,STSong", 8, 1252},
+    {0x0bc1a851, "SegoeUI", "Apple Symbols", 0, 1252},
+    {0x0c112ebd, "KozukaGothicPro-VIM", "Microsoft Sans Serif,Apple Symbols", 0,
      1252},
-    {0x12194c2d, L"KunstlerScript",
-     L"Avenir Next Condensed Demi Bold,Arial Narrow", 8, 1252},
-    {0x135ef6a1, L"MinionProSmBd", L"Microsoft Sans Serif,Apple Symbols", 0,
+    {0x0cfcb9c1, "AdobeThai", "Avenir Next Condensed Ultra Light", 0, 847},
+    {0x0e7de0f9, "Playbill", "STIXNonUnicode", 0, 1252},
+    {0x0eff47c3, "STHupo", "Kaiti SC,Songti SC,STHeiti", 0, 936},
+    {0x107ad374, "Constantia", "Arial Unicode MS,Palatino,Baskerville", 2,
      1252},
-    {0x158c4049, L"Garamond", L"Impact,Arial Narrow", 2, 1252},
-    {0x160ecb24, L"STZhongsong", L"STFangsong,Songti SC", 0, 936},
-    {0x161ed07e, L"MSGothic",
-     L"WenQuanYi Zen Hei Mono,AR PL UMing CN,AR PL UMing HK,AR PL UMing "
-     L"TW,Microsoft Sans Serif,Apple Symbols",
+    {0x12194c2d, "KunstlerScript",
+     "Avenir Next Condensed Demi Bold,Arial Narrow", 8, 1252},
+    {0x135ef6a1, "MinionProSmBd", "Microsoft Sans Serif,Apple Symbols", 0,
+     1252},
+    {0x158c4049, "Garamond", "Impact,Arial Narrow", 2, 1252},
+    {0x160ecb24, "STZhongsong", "STFangsong,Songti SC", 0, 936},
+    {0x161ed07e, "MSGothic",
+     "WenQuanYi Zen Hei Mono,AR PL UMing CN,AR PL UMing HK,AR PL UMing "
+     "TW,Microsoft Sans Serif,Apple Symbols",
      1, 1252},
-    {0x171d1ed1, L"SnapITC-Regular", L"STHeiti,Arial Black", 0, 1252},
-    {0x18d1188f, L"Cambria", L"Arial Unicode MS", 2, 1252},
-    {0x18eaf350, L"ArialUnicodeMS", L"Microsoft Sans Serif,Apple Symbols", 0,
+    {0x171d1ed1, "SnapITC-Regular", "STHeiti,Arial Black", 0, 1252},
+    {0x18d1188f, "Cambria", "Arial Unicode MS", 2, 1252},
+    {0x18eaf350, "ArialUnicodeMS", "Microsoft Sans Serif,Apple Symbols", 0,
      936},
-    {0x1a92d115, L"MingLiU", L"Heiti SC,STHeiti", 1, 1252},
-    {0x1cc217c6, L"TrebuchetMS", L"Damascus,Impact,Arial Narrow", 0, 1252},
-    {0x1d649596, L"BasemicTimes", L"Liberation Serif,Impact,Arial Narrow", 0,
+    {0x1a92d115, "MingLiU", "Heiti SC,STHeiti", 1, 1252},
+    {0x1cc217c6, "TrebuchetMS", "Damascus,Impact,Arial Narrow", 0, 1252},
+    {0x1d649596, "BasemicTimes", "Liberation Serif,Impact,Arial Narrow", 0,
      1252},
-    {0x1e34ee60, L"BellMT",
-     L"Papyrus,STIXNonUnicode,Microsoft Sans Serif,Avenir Light", 2, 1252},
-    {0x1eb36945, L"CooperBlack",
-     L"Marion,STIXNonUnicode,Arial Rounded MT Bold,Lucida Grande", 2, 1252},
-    {0x1ef7787d, L"BatangChe",
-     L"WenQuanYi Zen Hei Mono,AR PL UMing CN,,AR PL UMing HK,AR PL UMing TW,AR "
-     L"PL UMing TW MBE,Arial Unicode MS,Heiti TC",
+    {0x1e34ee60, "BellMT",
+     "Papyrus,STIXNonUnicode,Microsoft Sans Serif,Avenir Light", 2, 1252},
+    {0x1eb36945, "CooperBlack",
+     "Marion,STIXNonUnicode,Arial Rounded MT Bold,Lucida Grande", 2, 1252},
+    {0x1ef7787d, "BatangChe",
+     "WenQuanYi Zen Hei Mono,AR PL UMing CN,,AR PL UMing HK,AR PL UMing TW,AR "
+     "PL UMing TW MBE,Arial Unicode MS,Heiti TC",
      1, 1252},
-    {0x20b3bd3a, L"BrushScriptMT",
-     L"STIXNonUnicode,Damascus,Arial Narrow,Avenir Next Condensed,Cochin", 8,
+    {0x20b3bd3a, "BrushScriptMT",
+     "STIXNonUnicode,Damascus,Arial Narrow,Avenir Next Condensed,Cochin", 8,
      1252},
-    {0x220877aa, L"Candara", L"Cochin,Baskerville,Marion", 0, 1252},
-    {0x22135007, L"FreestyleScript-Regular",
-     L"STIXNonUnicode,Nadeem,Zapf Dingbats", 8, 1252},
-    {0x251059c3, L"Chiller",
-     L"Zapf Dingbats,Damascus,STIXNonUnicode,Papyrus,KufiStandardGK,Baghdad", 0,
+    {0x220877aa, "Candara", "Cochin,Baskerville,Marion", 0, 1252},
+    {0x22135007, "FreestyleScript-Regular",
+     "STIXNonUnicode,Nadeem,Zapf Dingbats", 8, 1252},
+    {0x251059c3, "Chiller",
+     "Zapf Dingbats,Damascus,STIXNonUnicode,Papyrus,KufiStandardGK,Baghdad", 0,
      1252},
-    {0x25bed6dd, L"MSReferenceSansSerif",
-     L"Tahoma,Apple Symbols,Apple LiGothic,Arial Unicode MS,Lucida "
-     L"Grande,Microsoft Sans Serif",
+    {0x25bed6dd, "MSReferenceSansSerif",
+     "Tahoma,Apple Symbols,Apple LiGothic,Arial Unicode MS,Lucida "
+     "Grande,Microsoft Sans Serif",
      0, 1252},
-    {0x28154c81, L"Parchment-Regular", L"Microsoft Sans Serif,Apple Symbols", 8,
+    {0x28154c81, "Parchment-Regular", "Microsoft Sans Serif,Apple Symbols", 8,
      1252},
-    {0x29711eb9, L"STLiti", L"Kaiti SC,Songti SC", 0, 936},
-    {0x2b1993b4, L"Basemic", L"Impact,Arial Narrow", 0, 1252},
-    {0x2b316339, L"NiagaraSolid-Reg", L"Microsoft Sans Serif,Apple Symbols", 0,
+    {0x29711eb9, "STLiti", "Kaiti SC,Songti SC", 0, 936},
+    {0x2b1993b4, "Basemic", "Impact,Arial Narrow", 0, 1252},
+    {0x2b316339, "NiagaraSolid-Reg", "Microsoft Sans Serif,Apple Symbols", 0,
      1252},
-    {0x2c147529, L"FootlightMTLight",
-     L"STIXNonUnicode,Avenir Next Condensed Heavy,PT Sans,Noteworthy", 0, 1252},
-    {0x2c198928, L"HarlowSolid",
-     L"Avenir Medium,Avenir Next Medium,Arial Unicode MS", 0, 1252},
-    {0x2c6ac6b2, L"LucidaBright",
-     L"PT Sans Narrow,Papyrus,Damascus,STIXNonUnicode,Arial Rounded MT "
-     L"Bold,Comic Sans MS,Avenir Next",
+    {0x2c147529, "FootlightMTLight",
+     "STIXNonUnicode,Avenir Next Condensed Heavy,PT Sans,Noteworthy", 0, 1252},
+    {0x2c198928, "HarlowSolid",
+     "Avenir Medium,Avenir Next Medium,Arial Unicode MS", 0, 1252},
+    {0x2c6ac6b2, "LucidaBright",
+     "PT Sans Narrow,Papyrus,Damascus,STIXNonUnicode,Arial Rounded MT "
+     "Bold,Comic Sans MS,Avenir Next",
      2, 1252},
-    {0x2c9f38e2, L"KozukaMinchoPro-VIR", L"Microsoft Sans Serif,Apple Symbols",
+    {0x2c9f38e2, "KozukaMinchoPro-VIR", "Microsoft Sans Serif,Apple Symbols", 0,
+     1252},
+    {0x2d5a47b0, "STCaiyun", "Kaiti SC,Songti SC", 0, 936},
+    {0x2def26bf, "BernardMT-Condensed",
+     "Impact,Avenir Next Condensed Demi Bold,American Typewriter", 0, 1252},
+    {0x2fd8930b, "KozukaMinchoPr6NR", "Microsoft Sans Serif,Apple Symbols", 0,
+     1252},
+    {0x3115525a, "FangSong_GB2312", "Hiragino Sans GB,STHeiti", 0, 1252},
+    {0x31327817, "MyriadPro", "Microsoft Sans Serif,Apple Symbols", 0, 1252},
+    {0x32244975, "Helvetica",
+     "Arial Narrow,Arial Unicode MS,Damascus,STIXNonUnicode", 0, 1252},
+    {0x32ac995c, "Terminal", "Microsoft Sans Serif,Apple Symbols", 0, 1252},
+    {0x338d648a, "NiagaraEngraved-Reg", "Microsoft Sans Serif,Apple Symbols", 0,
+     1252},
+    {0x33bb65f2, "Sylfaen", "Arial Unicode MS,Marion", 2, 1252},
+    {0x3402c30e, "MSPMincho", "Arial Unicode MS,Apple SD Gothic Neo", 2, 1252},
+    {0x3412bf31, "SimSun-PUA", "STHeiti,Heiti TC,STFangsong", 0, 936},
+    {0x36eb39b9, "BerlinSansFB", "American Typewriter,Impact", 0, 1252},
+    {0x36f42055, "UniversATT", "Microsoft Sans Serif", 0, 1252},
+    {0x3864c4f6, "HighTowerText", "STIXGeneral,.Helvetica Neue Desk UI", 2,
+     1252},
+    {0x3a257d03, "FangSong_GB2312", "Hiragino Sans GB,STHeiti", 0, 1252},
+    {0x3cdae668, "FreestyleScript", "Nadeem,Zapf Dingbats,STIXNonUnicode", 8,
+     1252},
+    {0x3d55aed7, "Jokerman",
+     "Papyrus,Lucida Grande,Heiti TC,American Typewriter", 0, 1252},
+    {0x3d5b4385, "PMingLiU", "Heiti SC,STHeiti", 2, 1252},
+    {0x3d9b7669, "EstrangeloEdessa", "American Typewriter,Marion", 0, 1252},
+    {0x3e532d74, "FranklinGothicMedium", "Impact,Arial Narrow", 0, 1252},
+    {0x3e6aa32d, "NSimSun", "STHeiti,STFangsong", 1, 936},
+    {0x3f6c36a8, "Gautami",
+     "Damascus,STIXNonUnicode,STIXGeneral,American Typewriter", 0, 1252},
+    {0x3ff32662, "Chiller-Regular", "Papyrus,KufiStandardGK,Baghdad", 0, 1252},
+    {0x409de312, "ModernNo.20", "Avenir Next Condensed,Impact", 2, 1252},
+    {0x41443c5e, "Georgia", ".Helvetica Neue Desk UI,Arial Unicode MS", 2,
+     1252},
+    {0x4160ade5, "BellGothicStdBlack", "Microsoft Sans Serif,Apple Symbols", 0,
+     1252},
+    {0x421976c4, "Modern-Regular", "Impact", 2, 1252},
+    {0x422a7252, "Stencil", "STIXNonUnicode,Songti SC,Georgia,Baskerville", 0,
+     1252},
+    {0x42c8554f, "Fixedsys", "Microsoft Sans Serif,Apple Symbols", 0, 1252},
+    {0x435cb41d, "Roman", "Arial Narrow", 0, 1252},
+    {0x47882383, "CourierNew", "PCMyungjo,Osaka,Arial Unicode MS,Songti SC", 1,
+     1252},
+    {0x480a2338, "BerlinSansFBDemi",
+     "STIXNonUnicode,American Typewriter,Avenir Next Condensed Heavy", 0, 1252},
+    {0x480bf7a4, "CourierStd", "Courier New", 0, 1252},
+    {0x481ad6ed, "VladimirScript",
+     "STIXNonUnicode,Avenir Next Condensed,Impact", 8, 1252},
+    {0x4911577a, "YouYuan", "STHeiti,Heiti TC", 1, 936},
+    {0x4a788d72, "STXingkai", "Kaiti SC,Songti SC", 0, 936},
+    {0x4bf88566, "SegoeCondensed", "Microsoft Sans Serif,Apple Symbols", 0,
+     1252},
+    {0x4ccf51a4, "BerlinSansFB-Reg",
+     "STIXNonUnicode,American Typewriter,Impact", 0, 1252},
+    {0x4ea967ce, "GulimChe", "Arial Unicode MS,Heiti TC,STFangsong", 1, 1252},
+    {0x4f68bd79, "LetterGothicStd",
+     "Courier New,Andale Mono,Ayuthaya,PCMyungjo,Osaka", 0, 1252},
+    {0x51a0d0e6, "KozukaGothicPr6NM", "Microsoft Sans Serif,Apple Symbols", 0,
+     1252},
+    {0x531b3dea, "BasemicSymbol", "Microsoft Sans Serif,Apple Symbols", 0,
+     1252},
+    {0x5333fd39, "CalifornianFB-Reg",
+     "American Typewriter,Avenir Next Condensed,Impact", 2, 1252},
+    {0x53561a54, "FZYTK--GBK1-0", "STFangsong,Songti SC,STSong", 0, 936},
+    {0x55e0dde6, "LucidaSansTypewriter", "Menlo,Courier New,Andale Mono", 0,
+     1252},
+    {0x574d4d3d, "AdobeArabic", "Arial Narrow", 0, 1252},
+    {0x5792e759, "STKaiti", "Songti SC,Arial Unicode MS", 0, 936},
+    {0x5921978e, "LucidaSansUnicode", "Lucida Grande,Arial Unicode MS,Menlo", 0,
+     1252},
+    {0x594e2da4, "Vrinda", "Geeza Pro,Damascus,STIXGeneral,Gill Sans", 0, 1252},
+    {0x59baa9a2, "KaiTi_GB2312", "Hiragino Sans GB,STHeiti", 0, 1252},
+    {0x5cfedf4f, "BaskOldFace",
+     "Avenir Next Condensed Heavy,PT Sans,Avenir Next Condensed", 0, 1252},
+    {0x5e16ac91, "TrajanPro", "Arial Narrow,PT Sans Narrow,Damascus", 0, 1252},
+    {0x5f97921c, "AdobeMyungjoStdM",
+     "AppleMyungjo,AppleGothic,Arial Unicode MS", 0, 936},
+    {0x5fefbfad, "Batang", "Arial Unicode MS,Songti SC", 2, 1252},
+    {0x605342b9, "DotumChe", "Arial Unicode MS,Heiti TC", 1, 1252},
+    {0x608c5f9a, "KaiTi_GB2312", "Hiragino Sans GB,STHeiti,Heiti TC", 0, 936},
+    {0x61efd0d1, "MaturaMTScriptCapitals",
+     "Kokonor,Damascus,STIXNonUnicode,STHeiti,Arial Black,Avenir Next Heavy", 0,
+     1252},
+    {0x626608a9, "MVBoli",
+     "Apple Braille,Geeza Pro,Microsoft Sans Serif,Apple Symbols", 0, 1252},
+    {0x630501a3, "SmallFonts", "Microsoft Sans Serif,Apple Symbols", 0, 1252},
+    {0x65d0e2a9, "FZYTK--GBK1-0", "STFangsong,Songti SC,STSong", 0, 936},
+    {0x669f29e1, "FZSTK--GBK1-0", "STHeiti,Heiti TC", 0, 936},
+    {0x673a9e5f, "Tunga",
+     "Damascus,STIXNonUnicode,Avenir Next Condensed,Avenir Next Condensed "
+     "Ultra Light,Futura",
      0, 1252},
-    {0x2d5a47b0, L"STCaiyun", L"Kaiti SC,Songti SC", 0, 936},
-    {0x2def26bf, L"BernardMT-Condensed",
-     L"Impact,Avenir Next Condensed Demi Bold,American Typewriter", 0, 1252},
-    {0x2fd8930b, L"KozukaMinchoPr6NR", L"Microsoft Sans Serif,Apple Symbols", 0,
-     1252},
-    {0x3115525a, L"FangSong_GB2312", L"Hiragino Sans GB,STHeiti", 0, 1252},
-    {0x31327817, L"MyriadPro", L"Microsoft Sans Serif,Apple Symbols", 0, 1252},
-    {0x32244975, L"Helvetica",
-     L"Arial Narrow,Arial Unicode MS,Damascus,STIXNonUnicode", 0, 1252},
-    {0x32ac995c, L"Terminal", L"Microsoft Sans Serif,Apple Symbols", 0, 1252},
-    {0x338d648a, L"NiagaraEngraved-Reg", L"Microsoft Sans Serif,Apple Symbols",
-     0, 1252},
-    {0x33bb65f2, L"Sylfaen", L"Arial Unicode MS,Marion", 2, 1252},
-    {0x3402c30e, L"MSPMincho", L"Arial Unicode MS,Apple SD Gothic Neo", 2,
-     1252},
-    {0x3412bf31, L"SimSun-PUA", L"STHeiti,Heiti TC,STFangsong", 0, 936},
-    {0x36eb39b9, L"BerlinSansFB", L"American Typewriter,Impact", 0, 1252},
-    {0x36f42055, L"UniversATT", L"Microsoft Sans Serif", 0, 1252},
-    {0x3864c4f6, L"HighTowerText", L"STIXGeneral,.Helvetica Neue Desk UI", 2,
-     1252},
-    {0x3a257d03, L"FangSong_GB2312", L"Hiragino Sans GB,STHeiti", 0, 1252},
-    {0x3cdae668, L"FreestyleScript", L"Nadeem,Zapf Dingbats,STIXNonUnicode", 8,
-     1252},
-    {0x3d55aed7, L"Jokerman",
-     L"Papyrus,Lucida Grande,Heiti TC,American Typewriter", 0, 1252},
-    {0x3d5b4385, L"PMingLiU", L"Heiti SC,STHeiti", 2, 1252},
-    {0x3d9b7669, L"EstrangeloEdessa", L"American Typewriter,Marion", 0, 1252},
-    {0x3e532d74, L"FranklinGothicMedium", L"Impact,Arial Narrow", 0, 1252},
-    {0x3e6aa32d, L"NSimSun", L"STHeiti,STFangsong", 1, 936},
-    {0x3f6c36a8, L"Gautami",
-     L"Damascus,STIXNonUnicode,STIXGeneral,American Typewriter", 0, 1252},
-    {0x3ff32662, L"Chiller-Regular", L"Papyrus,KufiStandardGK,Baghdad", 0,
-     1252},
-    {0x409de312, L"ModernNo.20", L"Avenir Next Condensed,Impact", 2, 1252},
-    {0x41443c5e, L"Georgia", L".Helvetica Neue Desk UI,Arial Unicode MS", 2,
-     1252},
-    {0x4160ade5, L"BellGothicStdBlack", L"Microsoft Sans Serif,Apple Symbols",
-     0, 1252},
-    {0x421976c4, L"Modern-Regular", L"Impact", 2, 1252},
-    {0x422a7252, L"Stencil", L"STIXNonUnicode,Songti SC,Georgia,Baskerville", 0,
-     1252},
-    {0x42c8554f, L"Fixedsys", L"Microsoft Sans Serif,Apple Symbols", 0, 1252},
-    {0x435cb41d, L"Roman", L"Arial Narrow", 0, 1252},
-    {0x47882383, L"CourierNew", L"PCMyungjo,Osaka,Arial Unicode MS,Songti SC",
-     1, 1252},
-    {0x480a2338, L"BerlinSansFBDemi",
-     L"STIXNonUnicode,American Typewriter,Avenir Next Condensed Heavy", 0,
-     1252},
-    {0x480bf7a4, L"CourierStd", L"Courier New", 0, 1252},
-    {0x481ad6ed, L"VladimirScript",
-     L"STIXNonUnicode,Avenir Next Condensed,Impact", 8, 1252},
-    {0x4911577a, L"YouYuan", L"STHeiti,Heiti TC", 1, 936},
-    {0x4a788d72, L"STXingkai", L"Kaiti SC,Songti SC", 0, 936},
-    {0x4bf88566, L"SegoeCondensed", L"Microsoft Sans Serif,Apple Symbols", 0,
-     1252},
-    {0x4ccf51a4, L"BerlinSansFB-Reg",
-     L"STIXNonUnicode,American Typewriter,Impact", 0, 1252},
-    {0x4ea967ce, L"GulimChe", L"Arial Unicode MS,Heiti TC,STFangsong", 1, 1252},
-    {0x4f68bd79, L"LetterGothicStd",
-     L"Courier New,Andale Mono,Ayuthaya,PCMyungjo,Osaka", 0, 1252},
-    {0x51a0d0e6, L"KozukaGothicPr6NM", L"Microsoft Sans Serif,Apple Symbols", 0,
-     1252},
-    {0x531b3dea, L"BasemicSymbol", L"Microsoft Sans Serif,Apple Symbols", 0,
-     1252},
-    {0x5333fd39, L"CalifornianFB-Reg",
-     L"American Typewriter,Avenir Next Condensed,Impact", 2, 1252},
-    {0x53561a54, L"FZYTK--GBK1-0", L"STFangsong,Songti SC,STSong", 0, 936},
-    {0x55e0dde6, L"LucidaSansTypewriter", L"Menlo,Courier New,Andale Mono", 0,
-     1252},
-    {0x574d4d3d, L"AdobeArabic", L"Arial Narrow", 0, 1252},
-    {0x5792e759, L"STKaiti", L"Songti SC,Arial Unicode MS", 0, 936},
-    {0x5921978e, L"LucidaSansUnicode", L"Lucida Grande,Arial Unicode MS,Menlo",
-     0, 1252},
-    {0x594e2da4, L"Vrinda", L"Geeza Pro,Damascus,STIXGeneral,Gill Sans", 0,
-     1252},
-    {0x59baa9a2, L"KaiTi_GB2312", L"Hiragino Sans GB,STHeiti", 0, 1252},
-    {0x5cfedf4f, L"BaskOldFace",
-     L"Avenir Next Condensed Heavy,PT Sans,Avenir Next Condensed", 0, 1252},
-    {0x5e16ac91, L"TrajanPro", L"Arial Narrow,PT Sans Narrow,Damascus", 0,
-     1252},
-    {0x5f97921c, L"AdobeMyungjoStdM",
-     L"AppleMyungjo,AppleGothic,Arial Unicode MS", 0, 936},
-    {0x5fefbfad, L"Batang", L"Arial Unicode MS,Songti SC", 2, 1252},
-    {0x605342b9, L"DotumChe", L"Arial Unicode MS,Heiti TC", 1, 1252},
-    {0x608c5f9a, L"KaiTi_GB2312", L"Hiragino Sans GB,STHeiti,Heiti TC", 0, 936},
-    {0x61efd0d1, L"MaturaMTScriptCapitals",
-     L"Kokonor,Damascus,STIXNonUnicode,STHeiti,Arial Black,Avenir Next Heavy",
-     0, 1252},
-    {0x626608a9, L"MVBoli",
-     L"Apple Braille,Geeza Pro,Microsoft Sans Serif,Apple Symbols", 0, 1252},
-    {0x630501a3, L"SmallFonts", L"Microsoft Sans Serif,Apple Symbols", 0, 1252},
-    {0x65d0e2a9, L"FZYTK--GBK1-0", L"STFangsong,Songti SC,STSong", 0, 936},
-    {0x669f29e1, L"FZSTK--GBK1-0", L"STHeiti,Heiti TC", 0, 936},
-    {0x673a9e5f, L"Tunga",
-     L"Damascus,STIXNonUnicode,Avenir Next Condensed,Avenir Next Condensed "
-     L"Ultra Light,Futura",
-     0, 1252},
-    {0x691aa4ce, L"NiagaraSolid", L"Microsoft Sans Serif,Apple Symbols", 0,
-     1252},
-    {0x696259b7, L"Corbel", L"Cochin,Baskerville,Marion", 0, 1252},
-    {0x696ee9be, L"STXihei", L"STHeiti,Heiti TC,Songti SC,Arial Unicode MS", 0,
+    {0x691aa4ce, "NiagaraSolid", "Microsoft Sans Serif,Apple Symbols", 0, 1252},
+    {0x696259b7, "Corbel", "Cochin,Baskerville,Marion", 0, 1252},
+    {0x696ee9be, "STXihei", "STHeiti,Heiti TC,Songti SC,Arial Unicode MS", 0,
      936},
-    {0x6c59cf69, L"Dotum", L"Arial Unicode MS,Songti SC", 0, 1252},
-    {0x707fa561, L"Gungsuh", L"Arial Unicode MS,Heiti TC", 2, 1252},
-    {0x71416bb2, L"ZWAdobeF",
-     L"STIXSizeFourSym,STIXSizeThreeSym,STIXSizeTwoSym,STIXSizeOneSym", 0,
-     1252},
-    {0x71b41801, L"Verdana",
-     L"Tahoma,Marion,Apple Symbols,.Helvetica Neue Desk UI,Lucida "
-     L"Grande,Courier New",
+    {0x6c59cf69, "Dotum", "Arial Unicode MS,Songti SC", 0, 1252},
+    {0x707fa561, "Gungsuh", "Arial Unicode MS,Heiti TC", 2, 1252},
+    {0x71416bb2, "ZWAdobeF",
+     "STIXSizeFourSym,STIXSizeThreeSym,STIXSizeTwoSym,STIXSizeOneSym", 0, 1252},
+    {0x71b41801, "Verdana",
+     "Tahoma,Marion,Apple Symbols,.Helvetica Neue Desk UI,Lucida "
+     "Grande,Courier New",
      0, 1252},
-    {0x73f25e4c, L"PalatinoLinotype", L"Palatino,Arial Unicode MS", 0, 1252},
-    {0x73f4d19f, L"NiagaraEngraved", L"Microsoft Sans Serif,Apple Symbols", 0,
+    {0x73f25e4c, "PalatinoLinotype", "Palatino,Arial Unicode MS", 0, 1252},
+    {0x73f4d19f, "NiagaraEngraved", "Microsoft Sans Serif,Apple Symbols", 0,
      1252},
-    {0x74001694, L"MyriadProBlack", L"Palatino,Baskerville,Marion,Cochin", 0,
+    {0x74001694, "MyriadProBlack", "Palatino,Baskerville,Marion,Cochin", 0,
      1252},
-    {0x74b14d8f, L"Haettenschweiler", L"Microsoft Sans Serif,Apple Symbols", 0,
+    {0x74b14d8f, "Haettenschweiler", "Microsoft Sans Serif,Apple Symbols", 0,
      1252},
-    {0x74cb44ee, L"NSimSun", L"STHeiti,Heiti TC,STFangsong", 1, 936},
-    {0x76b4d7ff, L"Shruti",
-     L"Damascus,STIXNonUnicode,Arial Unicode MS,American Typewriter", 0, 1252},
-    {0x788b3533, L"Webdings", L"Microsoft Sans Serif,Apple Symbols", 6, 42},
-    {0x797dde99, L"MSSerif", L"Microsoft Sans Serif,Apple Symbols", 0, 1252},
-    {0x7a0f9e9e, L"MSMincho",
-     L"WenQuanYi Zen Hei Mono,AR PL UMing CN,AR PL UMing HK,AR PL UMing TW,AR "
-     L"PL UMing TW MBE,Arial Unicode MS,Apple SD Gothic Neo",
+    {0x74cb44ee, "NSimSun", "STHeiti,Heiti TC,STFangsong", 1, 936},
+    {0x76b4d7ff, "Shruti",
+     "Damascus,STIXNonUnicode,Arial Unicode MS,American Typewriter", 0, 1252},
+    {0x788b3533, "Webdings", "Microsoft Sans Serif,Apple Symbols", 6, 42},
+    {0x797dde99, "MSSerif", "Microsoft Sans Serif,Apple Symbols", 0, 1252},
+    {0x7a0f9e9e, "MSMincho",
+     "WenQuanYi Zen Hei Mono,AR PL UMing CN,AR PL UMing HK,AR PL UMing TW,AR "
+     "PL UMing TW MBE,Arial Unicode MS,Apple SD Gothic Neo",
      1, 1252},
-    {0x7b439caf, L"OldEnglishTextMT",
-     L"STIXNonUnicode,Arial Unicode MS,Baskerville,Avenir Next Medium", 0,
+    {0x7b439caf, "OldEnglishTextMT",
+     "STIXNonUnicode,Arial Unicode MS,Baskerville,Avenir Next Medium", 0, 1252},
+    {0x8213a433, "LucidaSans-Typewriter",
+     "Comic Sans MS,Avenir Next,Arial Rounded MT Bold", 0, 1252},
+    {0x82fec929, "AdobeSongStd", "Heiti TC,STHeiti", 0, 936},
+    {0x83581825, "Modern", "Avenir Next Condensed,Impact", 0, 1252},
+    {0x835a2823, "Algerian",
+     "STIXNonUnicode,Baskerville,Avenir Next Medium,American Typewriter", 0,
      1252},
-    {0x8213a433, L"LucidaSans-Typewriter",
-     L"Comic Sans MS,Avenir Next,Arial Rounded MT Bold", 0, 1252},
-    {0x82fec929, L"AdobeSongStdL", L"Heiti TC,STHeiti", 0, 936},
-    {0x83581825, L"Modern", L"Avenir Next Condensed,Impact", 0, 1252},
-    {0x835a2823, L"Algerian",
-     L"STIXNonUnicode,Baskerville,Avenir Next Medium,American Typewriter", 0,
+    {0x83dab9f5, "Script", "Arial Narrow", 0, 1252},
+    {0x847b56da, "Tahoma", "Songti SC,Apple Symbols", 0, 1252},
+    {0x8a783cb2, "SimSun-PUA", "STHeiti,Heiti TC,STFangsong", 0, 1252},
+    {0x8b5cac0e, "Onyx", "Microsoft Sans Serif,Apple Symbols", 0, 1252},
+    {0x8c6a499e, "Gulim", "Arial Unicode MS,Songti SC", 0, 1252},
+    {0x8e0af790, "JuiceITC", "Nadeem,Al Bayan", 0, 1252},
+    {0x8e8d43b2, "Centaur", "Avenir Next Condensed,Noteworthy,Impact", 2, 1252},
+    {0x8ee4dcca, "BookshelfSymbol7", "Microsoft Sans Serif,Apple Symbols", 0,
      1252},
-    {0x83dab9f5, L"Script", L"Arial Narrow", 0, 1252},
-    {0x847b56da, L"Tahoma", L"Songti SC,Apple Symbols", 0, 1252},
-    {0x8a783cb2, L"SimSun-PUA", L"STHeiti,Heiti TC,STFangsong", 0, 1252},
-    {0x8b5cac0e, L"Onyx", L"Microsoft Sans Serif,Apple Symbols", 0, 1252},
-    {0x8c6a499e, L"Gulim", L"Arial Unicode MS,Songti SC", 0, 1252},
-    {0x8e0af790, L"JuiceITC", L"Nadeem,Al Bayan", 0, 1252},
-    {0x8e8d43b2, L"Centaur", L"Avenir Next Condensed,Noteworthy,Impact", 2,
+    {0x90794800, "BellGothicStdLight", "Microsoft Sans Serif,Apple Symbols", 0,
      1252},
-    {0x8ee4dcca, L"BookshelfSymbol7", L"Microsoft Sans Serif,Apple Symbols", 0,
-     1252},
-    {0x90794800, L"BellGothicStdLight", L"Microsoft Sans Serif,Apple Symbols",
-     0, 1252},
-    {0x909b516a, L"Century", L"Damascus,Andale Mono,Songti SC,Arial Unicode MS",
+    {0x909b516a, "Century", "Damascus,Andale Mono,Songti SC,Arial Unicode MS",
      2, 1252},
-    {0x92ae370d, L"MSOutlook", L"Microsoft Sans Serif,Apple Symbols", 4, 42},
-    {0x93c9fbf1, L"LucidaFax",
-     L"PT Sans Narrow,Papyrus,Kokonor,Geeza Pro,Arial Rounded MT Bold,Lucida "
-     L"Grande,Futura",
+    {0x92ae370d, "MSOutlook", "Microsoft Sans Serif,Apple Symbols", 4, 42},
+    {0x93c9fbf1, "LucidaFax",
+     "PT Sans Narrow,Papyrus,Kokonor,Geeza Pro,Arial Rounded MT Bold,Lucida "
+     "Grande,Futura",
      2, 1252},
-    {0x9565085e, L"BookAntiqua", L"Palatino,Microsoft Sans Serif,Apple Symbols",
+    {0x9565085e, "BookAntiqua", "Palatino,Microsoft Sans Serif,Apple Symbols",
      2, 1252},
-    {0x9856d95d, L"AdobeMingStdL", L"AHiragino Sans GB,Heiti TC,STHeiti", 0,
-     949},
-    {0x9bbadd6b, L"ColonnaMT", L"Noteworthy,Avenir Next Condensed,Impact", 0,
+    {0x9856d95d, "AdobeMingStd", "AHiragino Sans GB,Heiti TC,STHeiti", 0, 949},
+    {0x9bbadd6b, "ColonnaMT", "Noteworthy,Avenir Next Condensed,Impact", 0,
      1252},
-    {0x9cbd16a4, L"ShowcardGothic-Reg",
-     L"Arial Unicode MS,Georgia,American Typewriter", 0, 1252},
-    {0x9d73008e, L"MSSansSerif", L"Songti SC,Apple Symbols", 0, 1252},
-    {0xa0607db1, L"GungsuhChe",
-     L"WenQuanYi Zen Hei Mono,AR PL UMing CN,AR PL UMing HK,AR PL UMing TW,AR "
-     L"PL UMing TW MBE,Arial Unicode MS,Heiti TC,STFangsong",
+    {0x9cbd16a4, "ShowcardGothic-Reg",
+     "Arial Unicode MS,Georgia,American Typewriter", 0, 1252},
+    {0x9d73008e, "MSSansSerif", "Songti SC,Apple Symbols", 0, 1252},
+    {0xa0607db1, "GungsuhChe",
+     "WenQuanYi Zen Hei Mono,AR PL UMing CN,AR PL UMing HK,AR PL UMing TW,AR "
+     "PL UMing TW MBE,Arial Unicode MS,Heiti TC,STFangsong",
      1, 1252},
-    {0xa0bcf6a1, L"LatinWide", L"Zapfino,Arial Black,STHeiti", 2, 1252},
-    {0xa1429b36, L"Symbol", L"Microsoft Sans Serif,Apple Symbols", 6, 42},
-    {0xa1fa5abc, L"Wingdings2", L"Microsoft Sans Serif,Apple Symbols", 6, 42},
-    {0xa1fa5abd, L"Wingdings3", L"Microsoft Sans Serif,Apple Symbols", 6, 42},
-    {0xa427bad4, L"InformalRoman-Regular",
-     L"STIXNonUnicode,Arial Narrow,Avenir Next Condensed Demi Bold", 8, 1252},
-    {0xa8b92ece, L"FZSTK--GBK1-0", L"STHeiti,Heiti TC,STFangsong", 0, 936},
-    {0xa8d83ece, L"CalifornianFB",
-     L"American Typewriter,Avenir Next Condensed,Impact", 2, 1252},
-    {0xaa3e082c, L"Kingsoft-Phonetic",
-     L"STIXVariants,STIXSizeOneSym,Apple Braille", 0, 1252},
-    {0xaa6bcabe, L"HarlowSolidItalic",
-     L"STIXNonUnicode,Avenir Medium,Avenir Next Medium,Arial Unicode MS", 0,
+    {0xa0bcf6a1, "LatinWide", "Zapfino,Arial Black,STHeiti", 2, 1252},
+    {0xa1429b36, "Symbol", "Microsoft Sans Serif,Apple Symbols", 6, 42},
+    {0xa1fa5abc, "Wingdings2", "Microsoft Sans Serif,Apple Symbols", 6, 42},
+    {0xa1fa5abd, "Wingdings3", "Microsoft Sans Serif,Apple Symbols", 6, 42},
+    {0xa427bad4, "InformalRoman-Regular",
+     "STIXNonUnicode,Arial Narrow,Avenir Next Condensed Demi Bold", 8, 1252},
+    {0xa8b92ece, "FZSTK--GBK1-0", "STHeiti,Heiti TC,STFangsong", 0, 936},
+    {0xa8d83ece, "CalifornianFB",
+     "American Typewriter,Avenir Next Condensed,Impact", 2, 1252},
+    {0xaa3e082c, "Kingsoft-Phonetic",
+     "STIXVariants,STIXSizeOneSym,Apple Braille", 0, 1252},
+    {0xaa6bcabe, "HarlowSolidItalic",
+     "STIXNonUnicode,Avenir Medium,Avenir Next Medium,Arial Unicode MS", 0,
      1252},
-    {0xade5337c, L"MSUIGothic", L"Arial Unicode MS,Apple SD Gothic Neo", 0,
-     1252},
-    {0xb08dd941, L"WideLatin",
-     L"Marion,Papyrus,Nanum Pen Script,Zapf Dingbats,Damascus,Zapfino,Arial "
-     L"Black,STHeiti",
+    {0xade5337c, "MSUIGothic", "Arial Unicode MS,Apple SD Gothic Neo", 0, 1252},
+    {0xb08dd941, "WideLatin",
+     "Marion,Papyrus,Nanum Pen Script,Zapf Dingbats,Damascus,Zapfino,Arial "
+     "Black,STHeiti",
      2, 1252},
-    {0xb12765e0, L"ITCLegacySansStdBook",
-     L"LastResort,.Helvetica Neue Desk UI,Arial Unicode MS,Palatino", 0, 1252},
-    {0xb207f05d, L"PoorRichard", L"Noteworthy,Avenir Next Condensed,Impact", 2,
+    {0xb12765e0, "ITCLegacySansStdBook",
+     "LastResort,.Helvetica Neue Desk UI,Arial Unicode MS,Palatino", 0, 1252},
+    {0xb207f05d, "PoorRichard", "Noteworthy,Avenir Next Condensed,Impact", 2,
      1252},
-    {0xb3bc492f, L"JuiceITC-Regular", L"Nadeem,Al Bayan,STIXNonUnicode", 0,
+    {0xb3bc492f, "JuiceITC-Regular", "Nadeem,Al Bayan,STIXNonUnicode", 0, 1252},
+    {0xb5545399, "Marlett", "Microsoft Sans Serif,Apple Symbols", 4, 42},
+    {0xb5dd1ebb, "BritannicBold",
+     "Damascus,STIXNonUnicode,Avenir Next Condensed Heavy,PT Sans", 0, 1252},
+    {0xb699c1c5, "LucidaCalligraphy-Italic", "STHeiti,Arial Black", 0, 1252},
+    {0xb725d629, "TimesNewRoman", "Microsoft Sans Serif,Apple Symbols", 2,
      1252},
-    {0xb5545399, L"Marlett", L"Microsoft Sans Serif,Apple Symbols", 4, 42},
-    {0xb5dd1ebb, L"BritannicBold",
-     L"Damascus,STIXNonUnicode,Avenir Next Condensed Heavy,PT Sans", 0, 1252},
-    {0xb699c1c5, L"LucidaCalligraphy-Italic", L"STHeiti,Arial Black", 0, 1252},
-    {0xb725d629, L"TimesNewRoman", L"Microsoft Sans Serif,Apple Symbols", 2,
-     1252},
-    {0xb7eaebeb, L"AdobeHeitiStdR", L"Heiti TC,STHeiti", 0, 936},
-    {0xbd29c486, L"BerlinSansFBDemi-Bold",
-     L"American Typewriter,Avenir Next Condensed Heavy", 0, 1252},
-    {0xbe8a8db4, L"BookshelfSymbolSeven", L"Microsoft Sans Serif,Apple Symbols",
+    {0xb7eaebeb, "AdobeHeitiStdR", "Heiti TC,STHeiti", 0, 936},
+    {0xbd29c486, "BerlinSansFBDemi-Bold",
+     "American Typewriter,Avenir Next Condensed Heavy", 0, 1252},
+    {0xbe8a8db4, "BookshelfSymbolSeven", "Microsoft Sans Serif,Apple Symbols",
      0, 1252},
-    {0xc16c0118, L"AdobeHebrew",
-     L".Helvetica Neue Desk UI,Palatino,American Typewriter", 0, 1252},
-    {0xc318b0af, L"MyriadProLight", L"Palatino,Baskerville,Marion", 0, 1252},
-    {0xc65e5659, L"CambriaMath", L"Arial Unicode MS", 2, 1252},
-    {0xc75c8f05, L"LucidaConsole", L"Courier New,Menlo,Andale Mono", 1, 1252},
-    {0xca7c35d6, L"Calibri", L"Apple Symbols,HeadLineA", 0, 1252},
-    {0xcb053f53, L"MicrosoftYaHei", L"Arial Unicode MS", 0, 936},
-    {0xcb7190f9, L"Magneto-Bold", L"Lucida Grande", 0, 1252},
-    {0xcca00cc5, L"System", L"Microsoft Sans Serif,Apple Symbols", 0, 1252},
-    {0xccad6f76, L"Jokerman-Regular", L"Lucida Grande", 0, 1252},
-    {0xccc5818c, L"EuroSign", L"Microsoft Sans Serif,Apple Symbols", 0, 1252},
-    {0xcf3d7234, L"LucidaHandwriting-Italic",
-     L"Microsoft Sans Serif,Apple Symbols", 0, 1252},
-    {0xcf7b8fdb, L"MinionPro",
-     L"Bell MT,Corbel,Times New Roman,Cambria,Berlin Sans FB", 0, 1252},
-    {0xcfe5755f, L"Simhei", L"STHeiti,Heiti TC,STFangsong", 1, 936},
-    {0xd011f4ee, L"MSPGothic", L"Arial Unicode MS,Apple SD Gothic Neo", 0,
+    {0xc16c0118, "AdobeHebrew",
+     ".Helvetica Neue Desk UI,Palatino,American Typewriter", 0, 1252},
+    {0xc318b0af, "MyriadProLight", "Palatino,Baskerville,Marion", 0, 1252},
+    {0xc65e5659, "CambriaMath", "Arial Unicode MS", 2, 1252},
+    {0xc75c8f05, "LucidaConsole", "Courier New,Menlo,Andale Mono", 1, 1252},
+    {0xca7c35d6, "Calibri", "Apple Symbols,HeadLineA", 0, 1252},
+    {0xcb053f53, "MicrosoftYaHei", "Arial Unicode MS", 0, 936},
+    {0xcb7190f9, "Magneto-Bold", "Lucida Grande", 0, 1252},
+    {0xcca00cc5, "System", "Microsoft Sans Serif,Apple Symbols", 0, 1252},
+    {0xccad6f76, "Jokerman-Regular", "Lucida Grande", 0, 1252},
+    {0xccc5818c, "EuroSign", "Microsoft Sans Serif,Apple Symbols", 0, 1252},
+    {0xcf3d7234, "LucidaHandwriting-Italic",
+     "Microsoft Sans Serif,Apple Symbols", 0, 1252},
+    {0xcf7b8fdb, "MinionPro",
+     "Bell MT,Corbel,Times New Roman,Cambria,Berlin Sans FB", 0, 1252},
+    {0xcfe5755f, "Simhei", "STHeiti,Heiti TC,STFangsong", 1, 936},
+    {0xd011f4ee, "MSPGothic", "Arial Unicode MS,Apple SD Gothic Neo", 0, 1252},
+    {0xd060e7ef, "Vivaldi",
+     "STIXNonUnicode,Arial Unicode MS,Avenir Medium,Avenir Next Medium", 8,
      1252},
-    {0xd060e7ef, L"Vivaldi",
-     L"STIXNonUnicode,Arial Unicode MS,Avenir Medium,Avenir Next Medium", 8,
-     1252},
-    {0xd07edec1, L"FranklinGothic-Medium", L"Impact,Arial Narrow", 0, 1252},
-    {0xd107243f, L"SimSun", L"STHeiti,Heiti TC,STFangsong", 0, 936},
-    {0xd1881562, L"ArialNarrow", L"PT Sans Narrow,Apple Symbols", 0, 1252},
-    {0xd22b7dce, L"BodoniMTPosterCompressed",
-     L"Microsoft Sans Serif,Apple Symbols", 0, 1252},
-    {0xd22bfa60, L"ComicSansMS",
-     L"Damascus,Georgia,.Helvetica Neue Desk UI,Lucida Grande,Arial Unicode MS",
+    {0xd07edec1, "FranklinGothic-Medium", "Impact,Arial Narrow", 0, 1252},
+    {0xd107243f, "SimSun", "STHeiti,Heiti TC,STFangsong", 0, 936},
+    {0xd1881562, "ArialNarrow", "PT Sans Narrow,Apple Symbols", 0, 1252},
+    {0xd22b7dce, "BodoniMTPosterCompressed",
+     "Microsoft Sans Serif,Apple Symbols", 0, 1252},
+    {0xd22bfa60, "ComicSansMS",
+     "Damascus,Georgia,.Helvetica Neue Desk UI,Lucida Grande,Arial Unicode MS",
      8, 1252},
-    {0xd3bd0e35, L"Bauhaus93",
-     L"STIXNonUnicode,Arial Unicode MS,Avenir Next,Avenir", 0, 1252},
-    {0xd429ee7a, L"STFangsong", L"Songti SC,Arial Unicode MS", 0, 936},
-    {0xd6679c12, L"BernardMTCondensed",
-     L"Impact,Avenir Next Condensed Demi Bold", 0, 1252},
-    {0xd8e8a027, L"LucidaSans",
-     L"Arial Narrow,Khmer MN,Kokonor,Damascus,Microsoft Sans Serif,Apple "
-     L"Symbols",
+    {0xd3bd0e35, "Bauhaus93",
+     "STIXNonUnicode,Arial Unicode MS,Avenir Next,Avenir", 0, 1252},
+    {0xd429ee7a, "STFangsong", "Songti SC,Arial Unicode MS", 0, 936},
+    {0xd6679c12, "BernardMTCondensed", "Impact,Avenir Next Condensed Demi Bold",
      0, 1252},
-    {0xd9fe7761, L"HighTowerText-Reg",
-     L"STIXGeneral,.Helvetica Neue Desk UI,Trebuchet MS", 2, 1252},
-    {0xda7e551e, L"STSong", L"Arial Unicode MS", 0, 936},
-    {0xdaa6842d, L"STZhongsong", L"STFangsong,Songti SC,STSong", 0, 936},
-    {0xdaaab93f, L"STFangsong", L"Songti SC,Arial Unicode MS", 0, 936},
-    {0xdaeb0713, L"STSong", L"Songti SC,Arial Unicode MS", 0, 936},
-    {0xdafedbef, L"STCaiyun", L"Kaiti SC,Songti SC,STHeiti", 0, 936},
-    {0xdb00a3d9, L"Broadway",
-     L"Papyrus,STIXNonUnicode,Arial Black,Avenir Next Heavy,Heiti TC", 0, 1252},
-    {0xdb1f5ad4, L"STXinwei", L"Kaiti SC,Songti SC,STHeiti", 0, 936},
-    {0xdb326e7f, L"STKaiti", L"Songti SC,Arial Unicode MS", 0, 936},
-    {0xdb69595a, L"STHupo", L"Kaiti SC,Songti SC,STHeiti", 0, 936},
-    {0xdba0082c, L"STXihei", L"Songti SC,Arial Unicode MS", 0, 936},
-    {0xdbd0ab18, L"STXingkai", L"Kaiti SC,Songti SC", 0, 936},
-    {0xdc1a7db1, L"STLiti", L"Kaiti SC,Songti SC", 0, 936},
-    {0xdc33075f, L"KristenITC-Regular",
-     L"STIXNonUnicode,Damascus,Songti SC,STSong", 8, 1252},
-    {0xdcc7009c, L"Harrington",
-     L"STIXNonUnicode,Avenir Next Condensed Heavy,Noteworthy", 0, 1252},
-    {0xdd712466, L"ArialBlack", L"Geeza Pro,Damascus,Songti SC,STSong", 0,
+    {0xd8e8a027, "LucidaSans",
+     "Arial Narrow,Khmer MN,Kokonor,Damascus,Microsoft Sans Serif,Apple "
+     "Symbols",
+     0, 1252},
+    {0xd9fe7761, "HighTowerText-Reg",
+     "STIXGeneral,.Helvetica Neue Desk UI,Trebuchet MS", 2, 1252},
+    {0xda7e551e, "STSong", "Arial Unicode MS", 0, 936},
+    {0xdaa6842d, "STZhongsong", "STFangsong,Songti SC,STSong", 0, 936},
+    {0xdaaab93f, "STFangsong", "Songti SC,Arial Unicode MS", 0, 936},
+    {0xdaeb0713, "STSong", "Songti SC,Arial Unicode MS", 0, 936},
+    {0xdafedbef, "STCaiyun", "Kaiti SC,Songti SC,STHeiti", 0, 936},
+    {0xdb00a3d9, "Broadway",
+     "Papyrus,STIXNonUnicode,Arial Black,Avenir Next Heavy,Heiti TC", 0, 1252},
+    {0xdb1f5ad4, "STXinwei", "Kaiti SC,Songti SC,STHeiti", 0, 936},
+    {0xdb326e7f, "STKaiti", "Songti SC,Arial Unicode MS", 0, 936},
+    {0xdb69595a, "STHupo", "Kaiti SC,Songti SC,STHeiti", 0, 936},
+    {0xdba0082c, "STXihei", "Songti SC,Arial Unicode MS", 0, 936},
+    {0xdbd0ab18, "STXingkai", "Kaiti SC,Songti SC", 0, 936},
+    {0xdc1a7db1, "STLiti", "Kaiti SC,Songti SC", 0, 936},
+    {0xdc33075f, "KristenITC-Regular",
+     "STIXNonUnicode,Damascus,Songti SC,STSong", 8, 1252},
+    {0xdcc7009c, "Harrington",
+     "STIXNonUnicode,Avenir Next Condensed Heavy,Noteworthy", 0, 1252},
+    {0xdd712466, "ArialBlack", "Geeza Pro,Damascus,Songti SC,STSong", 0, 1252},
+    {0xdde87b3e, "Impact", "Arial Narrow,Marion", 0, 1252},
+    {0xdf69fb32, "SnapITC",
+     "Arial Narrow,PT Sans Narrow,Marion,STHeiti,Arial Black", 0, 1252},
+    {0xdf8b25e8, "CenturyGothic",
+     "Damascus,Andale Mono,Songti SC,Arial Unicode MS", 0, 1252},
+    {0xe0f705c0, "KristenITC", "Songti SC,STSong", 8, 1252},
+    {0xe1427573, "Raavi",
+     "Damascus,STIXNonUnicode,Marion,Papyrus,Avenir Next Condensed "
+     "Heavy,American Typewriter",
+     0, 1252},
+    {0xe2cea0cb, "Magneto",
+     "STIXNonUnicode,Damascus,Geeza Pro,Lucida Grande,Georgia,Heiti TC", 0,
      1252},
-    {0xdde87b3e, L"Impact", L"Arial Narrow,Marion", 0, 1252},
-    {0xdf69fb32, L"SnapITC",
-     L"Arial Narrow,PT Sans Narrow,Marion,STHeiti,Arial Black", 0, 1252},
-    {0xdf8b25e8, L"CenturyGothic",
-     L"Damascus,Andale Mono,Songti SC,Arial Unicode MS", 0, 1252},
-    {0xe0f705c0, L"KristenITC", L"Songti SC,STSong", 8, 1252},
-    {0xe1427573, L"Raavi",
-     L"Damascus,STIXNonUnicode,Marion,Papyrus,Avenir Next Condensed "
-     L"Heavy,American Typewriter",
+    {0xe36a9e17, "Ravie", "STHeiti,Arial Black", 0, 1252},
+    {0xe433f8e2, "Parchment", "Microsoft Sans Serif,Apple Symbols", 8, 1252},
+    {0xe43dff4a, "Wingdings", "Microsoft Sans Serif,Apple Symbols", 4, 42},
+    {0xe4e2c405, "MTExtra", "Microsoft Sans Serif,Apple Symbols", 6, 42},
+    {0xe618cc35, "InformalRoman", "Arial Narrow", 8, 1252},
+    {0xe6c27ffc, "Mistral", "Apple Symbols", 8, 1252},
+    {0xe7ebf4b9, "Courier", "Courier New", 0, 1252},
+    {0xe8bc4a9d, "MSReferenceSpecialty", "Microsoft Sans Serif,Apple Symbols",
      0, 1252},
-    {0xe2cea0cb, L"Magneto",
-     L"STIXNonUnicode,Damascus,Geeza Pro,Lucida Grande,Georgia,Heiti TC", 0,
-     1252},
-    {0xe36a9e17, L"Ravie", L"STHeiti,Arial Black", 0, 1252},
-    {0xe433f8e2, L"Parchment", L"Microsoft Sans Serif,Apple Symbols", 8, 1252},
-    {0xe43dff4a, L"Wingdings", L"Microsoft Sans Serif,Apple Symbols", 4, 42},
-    {0xe4e2c405, L"MTExtra", L"Microsoft Sans Serif,Apple Symbols", 6, 42},
-    {0xe618cc35, L"InformalRoman", L"Arial Narrow", 8, 1252},
-    {0xe6c27ffc, L"Mistral", L"Apple Symbols", 8, 1252},
-    {0xe7ebf4b9, L"Courier", L"Courier New", 0, 1252},
-    {0xe8bc4a9d, L"MSReferenceSpecialty", L"Microsoft Sans Serif,Apple Symbols",
-     0, 1252},
-    {0xe90fb013, L"TempusSansITC",
-     L"STIXNonUnicode,Microsoft Sans Serif,Avenir Light", 0, 1252},
-    {0xec637b42, L"Consolas",
-     L"AR PL UKai CN,AR PL UKai HK,AR PL UKai TW,AR PL UKai TW MBE,AR PL UMing "
-     L"CN,AR PL UMing HK,Microsoft Sans Serif,Tahoma",
+    {0xe90fb013, "TempusSansITC",
+     "STIXNonUnicode,Microsoft Sans Serif,Avenir Light", 0, 1252},
+    {0xec637b42, "Consolas",
+     "AR PL UKai CN,AR PL UKai HK,AR PL UKai TW,AR PL UKai TW MBE,AR PL UMing "
+     "CN,AR PL UMing HK,Microsoft Sans Serif,Tahoma",
      1, 1252},
-    {0xed3a683b, L"STXinwei", L"Kaiti SC,Songti SC,", 0, 936},
-    {0xef264cd1, L"LucidaHandwriting",
-     L"Arial Narrow,Avenir Next Condensed Demi Bold,Avenir Next "
-     L"Condensed,Avenir Next Condensed Medium,STHeiti,Arial Black",
+    {0xed3a683b, "STXinwei", "Kaiti SC,Songti SC,", 0, 936},
+    {0xef264cd1, "LucidaHandwriting",
+     "Arial Narrow,Avenir Next Condensed Demi Bold,Avenir Next "
+     "Condensed,Avenir Next Condensed Medium,STHeiti,Arial Black",
      0, 1252},
-    {0xf086bca2, L"BaskervilleOldFace",
-     L"STIXNonUnicode,Avenir Next Condensed Heavy,PT Sans", 0, 1252},
-    {0xf1028030, L"Mangal",
-     L"Arial Unicode MS,Microsoft Sans Serif,Arial Narrow,Tahoma", 2, 1252},
-    {0xf1da7eb9, L"ShowcardGothic",
-     L"Papyrus,Arial Unicode MS,Georgia,American Typewriter", 0, 1252},
-    {0xf210f06a, L"ArialMT",
-     L"Arial Unicode MS,Arial Narrow,STIXNonUnicode,Damascus,Avenir Next "
-     L"Condensed Demi Bold,Avenir Next Condensed Medium,Avenir Next Condensed",
+    {0xf086bca2, "BaskervilleOldFace",
+     "STIXNonUnicode,Avenir Next Condensed Heavy,PT Sans", 0, 1252},
+    {0xf1028030, "Mangal",
+     "Arial Unicode MS,Microsoft Sans Serif,Arial Narrow,Tahoma", 2, 1252},
+    {0xf1da7eb9, "ShowcardGothic",
+     "Papyrus,Arial Unicode MS,Georgia,American Typewriter", 0, 1252},
+    {0xf210f06a, "ArialMT",
+     "Arial Unicode MS,Arial Narrow,STIXNonUnicode,Damascus,Avenir Next "
+     "Condensed Demi Bold,Avenir Next Condensed Medium,Avenir Next Condensed",
      0, 1252},
-    {0xf477f16a, L"Latha",
-     L"Arial Narrow,Damascus,STIXNonUnicode,American Typewriter", 0, 1252},
-    {0xf616f3dd, L"LiSu", L"STHeiti,Heiti TC,STFangsong", 1, 936},
-    {0xfa479aa6, L"MicrosoftYaHei", L"Arial Unicode MS", 0, 936},
-    {0xfcd19697, L"BookmanOldStyle",
-     L"Geeza Pro,Damascus,Andale Mono,Songti SC,Arial Unicode MS", 0, 1252},
-    {0xfe209a82, L"LucidaCalligraphy",
-     L"Kokonor,Damascus,STIXNonUnicode,STHeiti,Arial Black", 0, 1252},
-    {0xfef135f8, L"AdobeHeitiStd-Regular", L"Heiti TC,STHeiti", 0, 936},
+    {0xf477f16a, "Latha",
+     "Arial Narrow,Damascus,STIXNonUnicode,American Typewriter", 0, 1252},
+    {0xf616f3dd, "LiSu", "STHeiti,Heiti TC,STFangsong", 1, 936},
+    {0xfa479aa6, "MicrosoftYaHei", "Arial Unicode MS", 0, 936},
+    {0xfcd19697, "BookmanOldStyle",
+     "Geeza Pro,Damascus,Andale Mono,Songti SC,Arial Unicode MS", 0, 1252},
+    {0xfe209a82, "LucidaCalligraphy",
+     "Kokonor,Damascus,STIXNonUnicode,STHeiti,Arial Black", 0, 1252},
+    {0xfef135f8, "AdobeHeitiStd-Regular", "Heiti TC,STHeiti", 0, 936},
 };
-#elif _FX_PLATFORM_ == _FX_PLATFORM_ANDROID_
+#elif defined(OS_ANDROID)
 const FGAS_FontInfo g_XFAFontsMap[] = {
-    {0x01d5d33e, L"SimSun", L"Droid Sans Fallback", 0, 936},
-    {0x01e4f102, L"YouYuan", L"Droid Sans Fallback", 1, 936},
-    {0x030549dc, L"LiSu", L"Droid Sans Fallback", 1, 936},
-    {0x032edd44, L"Simhei", L"Droid Sans Fallback", 1, 936},
-    {0x03eac6fc, L"PoorRichard-Regular",
-     L"Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback,Droid Arabic "
-     L"Naskh,Droid Sans Ethiopic",
+    {0x01d5d33e, "SimSun", "Droid Sans Fallback", 0, 936},
+    {0x01e4f102, "YouYuan", "Droid Sans Fallback", 1, 936},
+    {0x030549dc, "LiSu", "Droid Sans Fallback", 1, 936},
+    {0x032edd44, "Simhei", "Droid Sans Fallback", 1, 936},
+    {0x03eac6fc, "PoorRichard-Regular",
+     "Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback,Droid Arabic "
+     "Naskh,Droid Sans Ethiopic",
      2, 1252},
-    {0x03ed90e6, L"Nina",
-     L"Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
-    {0x077b56b3, L"KingsoftPhoneticPlain",
-     L"Droid Sans Thai,Droid Sans Armenian,Droid Arabic Naskh,Droid Sans "
-     L"Ethiopic,Droid Sans Fallback",
+    {0x03ed90e6, "Nina",
+     "Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
+    {0x077b56b3, "KingsoftPhoneticPlain",
+     "Droid Sans Thai,Droid Sans Armenian,Droid Arabic Naskh,Droid Sans "
+     "Ethiopic,Droid Sans Fallback",
      0, 1252},
-    {0x078ed524, L"MicrosoftSansSerif", L"Droid Sans Fallback", 0, 1252},
-    {0x089b18a9, L"Arial", L"Droid Sans Fallback", 0, 1252},
-    {0x0b2cad72, L"MonotypeCorsiva",
-     L"Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 8, 1252},
-    {0x0bb003e7, L"Kartika",
-     L"Droid Arabic Naskh,Droid Sans Ethiopic,Roboto,Droid Serif,Droid Sans "
-     L"Mono",
+    {0x078ed524, "MicrosoftSansSerif", "Droid Sans Fallback", 0, 1252},
+    {0x089b18a9, "Arial", "Droid Sans Fallback", 0, 1252},
+    {0x0b2cad72, "MonotypeCorsiva",
+     "Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 8, 1252},
+    {0x0bb003e7, "Kartika",
+     "Droid Arabic Naskh,Droid Sans Ethiopic,Roboto,Droid Serif,Droid Sans "
+     "Mono",
      2, 1252},
-    {0x0bb469df, L"VinerHandITC",
-     L"Droid Serif,Roboto,Droid Sans Mono,Droid Sans Fallback", 8, 1252},
-    {0x0bc1a851, L"SegoeUI", L"Droid Sans Fallback", 0, 1252},
-    {0x0c112ebd, L"KozukaGothicPro-VIM",
-     L"Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
-    {0x0cfcb9c1, L"AdobeThai",
-     L"Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 0, 847},
-    {0x0e7de0f9, L"Playbill",
-     L"Droid Arabic Naskh,Droid Sans Ethiopic,Roboto,Droid Serif,Droid Sans "
-     L"Mono",
+    {0x0bb469df, "VinerHandITC",
+     "Droid Serif,Roboto,Droid Sans Mono,Droid Sans Fallback", 8, 1252},
+    {0x0bc1a851, "SegoeUI", "Droid Sans Fallback", 0, 1252},
+    {0x0c112ebd, "KozukaGothicPro-VIM",
+     "Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
+    {0x0cfcb9c1, "AdobeThai",
+     "Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 0, 847},
+    {0x0e7de0f9, "Playbill",
+     "Droid Arabic Naskh,Droid Sans Ethiopic,Roboto,Droid Serif,Droid Sans "
+     "Mono",
      0, 1252},
-    {0x0eff47c3, L"STHupo", L"Droid Sans Fallback", 0, 936},
-    {0x107ad374, L"Constantia",
-     L"Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 2, 1252},
-    {0x12194c2d, L"KunstlerScript",
-     L"Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 8, 1252},
-    {0x135ef6a1, L"MinionProSmBd",
-     L"Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
-    {0x158c4049, L"Garamond",
-     L"Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 2, 1252},
-    {0x160ecb24, L"STZhongsong", L"Droid Sans Fallback", 0, 936},
-    {0x161ed07e, L"MSGothic", L"Droid Sans Fallback", 1, 1252},
-    {0x171d1ed1, L"SnapITC-Regular",
-     L"Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
-    {0x18d1188f, L"Cambria", L"Droid Sans Fallback", 2, 1252},
-    {0x18eaf350, L"ArialUnicodeMS", L"Droid Sans Fallback", 0, 936},
-    {0x1a92d115, L"MingLiU", L"Droid Sans Fallback", 1, 1252},
-    {0x1cc217c6, L"TrebuchetMS",
-     L"Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
-    {0x1d649596, L"BasemicTimes",
-     L"Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
-    {0x1e34ee60, L"BellMT",
-     L"Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 2, 1252},
-    {0x1eb36945, L"CooperBlack",
-     L"Droid Serif,Roboto,Droid Sans Mono,Droid Sans Fallback", 2, 1252},
-    {0x1ef7787d, L"BatangChe", L"Droid Sans Fallback", 1, 1252},
-    {0x20b3bd3a, L"BrushScriptMT", L"Droid Arabic Naskh,Droid Sans Ethiopic", 8,
+    {0x0eff47c3, "STHupo", "Droid Sans Fallback", 0, 936},
+    {0x107ad374, "Constantia",
+     "Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 2, 1252},
+    {0x12194c2d, "KunstlerScript",
+     "Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 8, 1252},
+    {0x135ef6a1, "MinionProSmBd",
+     "Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
+    {0x158c4049, "Garamond",
+     "Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 2, 1252},
+    {0x160ecb24, "STZhongsong", "Droid Sans Fallback", 0, 936},
+    {0x161ed07e, "MSGothic", "Droid Sans Fallback", 1, 1252},
+    {0x171d1ed1, "SnapITC-Regular",
+     "Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
+    {0x18d1188f, "Cambria", "Droid Sans Fallback", 2, 1252},
+    {0x18eaf350, "ArialUnicodeMS", "Droid Sans Fallback", 0, 936},
+    {0x1a92d115, "MingLiU", "Droid Sans Fallback", 1, 1252},
+    {0x1cc217c6, "TrebuchetMS",
+     "Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
+    {0x1d649596, "BasemicTimes",
+     "Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
+    {0x1e34ee60, "BellMT",
+     "Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 2, 1252},
+    {0x1eb36945, "CooperBlack",
+     "Droid Serif,Roboto,Droid Sans Mono,Droid Sans Fallback", 2, 1252},
+    {0x1ef7787d, "BatangChe", "Droid Sans Fallback", 1, 1252},
+    {0x20b3bd3a, "BrushScriptMT", "Droid Arabic Naskh,Droid Sans Ethiopic", 8,
      1252},
-    {0x220877aa, L"Candara",
-     L"Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
-    {0x22135007, L"FreestyleScript-Regular",
-     L"Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 8, 1252},
-    {0x251059c3, L"Chiller",
-     L"Droid Arabic Naskh,Droid Sans Ethiopic,Roboto,Droid Serif", 0, 1252},
-    {0x25bed6dd, L"MSReferenceSansSerif", L"Droid Sans Fallback", 0, 1252},
-    {0x28154c81, L"Parchment-Regular",
-     L"Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 8, 1252},
-    {0x29711eb9, L"STLiti", L"Droid Sans Fallback", 0, 936},
-    {0x2b1993b4, L"Basemic",
-     L"Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
-    {0x2b316339, L"NiagaraSolid-Reg",
-     L"Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
-    {0x2c147529, L"FootlightMTLight",
-     L"Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
-    {0x2c198928, L"HarlowSolid",
-     L"Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
-    {0x2c6ac6b2, L"LucidaBright",
-     L"Droid Arabic Naskh,Droid Sans Ethiopic,Droid Serif,Roboto", 2, 1252},
-    {0x2c9f38e2, L"KozukaMinchoPro-VIR",
-     L"Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
-    {0x2d5a47b0, L"STCaiyun", L"Droid Sans Fallback", 0, 936},
-    {0x2def26bf, L"BernardMT-Condensed",
-     L"Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
-    {0x2fd8930b, L"KozukaMinchoPr6NR",
-     L"Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
-    {0x3115525a, L"FangSong_GB2312", L"Droid Sans Fallback", 0, 1252},
-    {0x31327817, L"MyriadPro",
-     L"Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
-    {0x32244975, L"Helvetica",
-     L"Droid Arabic Naskh,Droid Sans Ethiopic,Droid Serif,Roboto", 0, 1252},
-    {0x32ac995c, L"Terminal",
-     L"Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
-    {0x338d648a, L"NiagaraEngraved-Reg",
-     L"Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
-    {0x33bb65f2, L"Sylfaen",
-     L"Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 2, 1252},
-    {0x3402c30e, L"MSPMincho", L"Droid Sans Fallback", 2, 1252},
-    {0x3412bf31, L"SimSun-PUA", L"Droid Sans Fallback", 0, 936},
-    {0x36eb39b9, L"BerlinSansFB",
-     L"Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
-    {0x36f42055, L"UniversATT", L"Microsoft Sans Serif", 0, 1252},
-    {0x3864c4f6, L"HighTowerText",
-     L"Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 2, 1252},
-    {0x3a257d03, L"FangSong_GB2312", L"Droid Sans Fallback", 0, 1252},
-    {0x3cdae668, L"FreestyleScript",
-     L"Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 8, 1252},
-    {0x3d55aed7, L"Jokerman",
-     L"Droid Serif,Roboto,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
-    {0x3d5b4385, L"PMingLiU", L"Droid Sans Fallback", 2, 1252},
-    {0x3d9b7669, L"EstrangeloEdessa",
-     L"Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
-    {0x3e532d74, L"FranklinGothicMedium",
-     L"Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
-    {0x3e6aa32d, L"NSimSun", L"Droid Sans Fallback", 1, 936},
-    {0x3f6c36a8, L"Gautami",
-     L"Droid Arabic Naskh,Droid Sans Ethiopic,Roboto,Droid Serif,Droid Sans "
-     L"Mono,Droid Sans Fallback",
+    {0x220877aa, "Candara",
+     "Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
+    {0x22135007, "FreestyleScript-Regular",
+     "Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 8, 1252},
+    {0x251059c3, "Chiller",
+     "Droid Arabic Naskh,Droid Sans Ethiopic,Roboto,Droid Serif", 0, 1252},
+    {0x25bed6dd, "MSReferenceSansSerif", "Droid Sans Fallback", 0, 1252},
+    {0x28154c81, "Parchment-Regular",
+     "Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 8, 1252},
+    {0x29711eb9, "STLiti", "Droid Sans Fallback", 0, 936},
+    {0x2b1993b4, "Basemic",
+     "Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
+    {0x2b316339, "NiagaraSolid-Reg",
+     "Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
+    {0x2c147529, "FootlightMTLight",
+     "Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
+    {0x2c198928, "HarlowSolid",
+     "Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
+    {0x2c6ac6b2, "LucidaBright",
+     "Droid Arabic Naskh,Droid Sans Ethiopic,Droid Serif,Roboto", 2, 1252},
+    {0x2c9f38e2, "KozukaMinchoPro-VIR",
+     "Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
+    {0x2d5a47b0, "STCaiyun", "Droid Sans Fallback", 0, 936},
+    {0x2def26bf, "BernardMT-Condensed",
+     "Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
+    {0x2fd8930b, "KozukaMinchoPr6NR",
+     "Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
+    {0x3115525a, "FangSong_GB2312", "Droid Sans Fallback", 0, 1252},
+    {0x31327817, "MyriadPro",
+     "Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
+    {0x32244975, "Helvetica",
+     "Droid Arabic Naskh,Droid Sans Ethiopic,Droid Serif,Roboto", 0, 1252},
+    {0x32ac995c, "Terminal",
+     "Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
+    {0x338d648a, "NiagaraEngraved-Reg",
+     "Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
+    {0x33bb65f2, "Sylfaen",
+     "Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 2, 1252},
+    {0x3402c30e, "MSPMincho", "Droid Sans Fallback", 2, 1252},
+    {0x3412bf31, "SimSun-PUA", "Droid Sans Fallback", 0, 936},
+    {0x36eb39b9, "BerlinSansFB",
+     "Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
+    {0x36f42055, "UniversATT", "Microsoft Sans Serif", 0, 1252},
+    {0x3864c4f6, "HighTowerText",
+     "Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 2, 1252},
+    {0x3a257d03, "FangSong_GB2312", "Droid Sans Fallback", 0, 1252},
+    {0x3cdae668, "FreestyleScript",
+     "Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 8, 1252},
+    {0x3d55aed7, "Jokerman",
+     "Droid Serif,Roboto,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
+    {0x3d5b4385, "PMingLiU", "Droid Sans Fallback", 2, 1252},
+    {0x3d9b7669, "EstrangeloEdessa",
+     "Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
+    {0x3e532d74, "FranklinGothicMedium",
+     "Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
+    {0x3e6aa32d, "NSimSun", "Droid Sans Fallback", 1, 936},
+    {0x3f6c36a8, "Gautami",
+     "Droid Arabic Naskh,Droid Sans Ethiopic,Roboto,Droid Serif,Droid Sans "
+     "Mono,Droid Sans Fallback",
      0, 1252},
-    {0x3ff32662, L"Chiller-Regular",
-     L"Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
-    {0x409de312, L"ModernNo.20",
-     L"Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 2, 1252},
-    {0x41443c5e, L"Georgia",
-     L"Droid Serif,Roboto,Droid Sans Mono,Droid Sans Fallback", 2, 1252},
-    {0x4160ade5, L"BellGothicStdBlack",
-     L"Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
-    {0x421976c4, L"Modern-Regular",
-     L"Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 2, 1252},
-    {0x422a7252, L"Stencil",
-     L"Droid Serif,Roboto,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
-    {0x42c8554f, L"Fixedsys",
-     L"Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
-    {0x435cb41d, L"Roman",
-     L"Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
-    {0x47882383, L"CourierNew", L"Droid Sans Fallback", 1, 1252},
-    {0x480a2338, L"BerlinSansFBDemi",
-     L"Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
-    {0x480bf7a4, L"CourierStd", L"Droid Sans Fallback", 0, 1252},
-    {0x481ad6ed, L"VladimirScript",
-     L"Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 8, 1252},
-    {0x4911577a, L"YouYuan", L"Droid Sans Fallback", 1, 936},
-    {0x4a788d72, L"STXingkai", L"Droid Sans Fallback", 0, 936},
-    {0x4bf88566, L"SegoeCondensed",
-     L"Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
-    {0x4ccf51a4, L"BerlinSansFB-Reg",
-     L"Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
-    {0x4ea967ce, L"GulimChe", L"Droid Sans Fallback", 1, 1252},
-    {0x4f68bd79, L"LetterGothicStd",
-     L"Droid Sans Mono,Droid Arabic Naskh,Droid Sans Ethiopic,Droid Sans "
-     L"Mono,Droid Serif,Droid Sans Fallback",
+    {0x3ff32662, "Chiller-Regular",
+     "Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
+    {0x409de312, "ModernNo.20",
+     "Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 2, 1252},
+    {0x41443c5e, "Georgia",
+     "Droid Serif,Roboto,Droid Sans Mono,Droid Sans Fallback", 2, 1252},
+    {0x4160ade5, "BellGothicStdBlack",
+     "Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
+    {0x421976c4, "Modern-Regular",
+     "Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 2, 1252},
+    {0x422a7252, "Stencil",
+     "Droid Serif,Roboto,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
+    {0x42c8554f, "Fixedsys",
+     "Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
+    {0x435cb41d, "Roman",
+     "Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
+    {0x47882383, "CourierNew", "Droid Sans Fallback", 1, 1252},
+    {0x480a2338, "BerlinSansFBDemi",
+     "Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
+    {0x480bf7a4, "CourierStd", "Droid Sans Fallback", 0, 1252},
+    {0x481ad6ed, "VladimirScript",
+     "Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 8, 1252},
+    {0x4911577a, "YouYuan", "Droid Sans Fallback", 1, 936},
+    {0x4a788d72, "STXingkai", "Droid Sans Fallback", 0, 936},
+    {0x4bf88566, "SegoeCondensed",
+     "Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
+    {0x4ccf51a4, "BerlinSansFB-Reg",
+     "Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
+    {0x4ea967ce, "GulimChe", "Droid Sans Fallback", 1, 1252},
+    {0x4f68bd79, "LetterGothicStd",
+     "Droid Sans Mono,Droid Arabic Naskh,Droid Sans Ethiopic,Droid Sans "
+     "Mono,Droid Serif,Droid Sans Fallback",
      0, 1252},
-    {0x51a0d0e6, L"KozukaGothicPr6NM",
-     L"Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
-    {0x531b3dea, L"BasemicSymbol",
-     L"Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
-    {0x5333fd39, L"CalifornianFB-Reg",
-     L"Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 2, 1252},
-    {0x53561a54, L"FZYTK--GBK1-0", L"Droid Sans Fallback", 0, 936},
-    {0x55e0dde6, L"LucidaSansTypewriter",
-     L"Droid Sans Mono,Droid Arabic Naskh,Droid Sans Ethiopic", 0, 1252},
-    {0x574d4d3d, L"AdobeArabic",
-     L"Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
-    {0x5792e759, L"STKaiti", L"Droid Sans Fallback", 0, 936},
-    {0x5921978e, L"LucidaSansUnicode", L"Droid Sans Fallback", 0, 1252},
-    {0x594e2da4, L"Vrinda",
-     L"Droid Arabic Naskh,Droid Sans Ethiopic,Roboto,Droid Serif,Droid Sans "
-     L"Mono",
+    {0x51a0d0e6, "KozukaGothicPr6NM",
+     "Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
+    {0x531b3dea, "BasemicSymbol",
+     "Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
+    {0x5333fd39, "CalifornianFB-Reg",
+     "Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 2, 1252},
+    {0x53561a54, "FZYTK--GBK1-0", "Droid Sans Fallback", 0, 936},
+    {0x55e0dde6, "LucidaSansTypewriter",
+     "Droid Sans Mono,Droid Arabic Naskh,Droid Sans Ethiopic", 0, 1252},
+    {0x574d4d3d, "AdobeArabic",
+     "Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
+    {0x5792e759, "STKaiti", "Droid Sans Fallback", 0, 936},
+    {0x5921978e, "LucidaSansUnicode", "Droid Sans Fallback", 0, 1252},
+    {0x594e2da4, "Vrinda",
+     "Droid Arabic Naskh,Droid Sans Ethiopic,Roboto,Droid Serif,Droid Sans "
+     "Mono",
      0, 1252},
-    {0x59baa9a2, L"KaiTi_GB2312", L"Droid Sans Fallback", 0, 1252},
-    {0x5cfedf4f, L"BaskOldFace",
-     L"Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
-    {0x5f97921c, L"AdobeMyungjoStdM", L"Droid Sans Fallback", 0, 936},
-    {0x5fefbfad, L"Batang", L"Droid Sans Fallback", 2, 1252},
-    {0x605342b9, L"DotumChe", L"Droid Sans Fallback", 1, 1252},
-    {0x608c5f9a, L"KaiTi_GB2312", L"Droid Sans Fallback", 0, 936},
-    {0x61efd0d1, L"MaturaMTScriptCapitals",
-     L"Droid Arabic Naskh,Droid Sans Ethiopic,Droid Serif,Roboto,Droid Sans "
-     L"Mono",
+    {0x59baa9a2, "KaiTi_GB2312", "Droid Sans Fallback", 0, 1252},
+    {0x5cfedf4f, "BaskOldFace",
+     "Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
+    {0x5f97921c, "AdobeMyungjoStdM", "Droid Sans Fallback", 0, 936},
+    {0x5fefbfad, "Batang", "Droid Sans Fallback", 2, 1252},
+    {0x605342b9, "DotumChe", "Droid Sans Fallback", 1, 1252},
+    {0x608c5f9a, "KaiTi_GB2312", "Droid Sans Fallback", 0, 936},
+    {0x61efd0d1, "MaturaMTScriptCapitals",
+     "Droid Arabic Naskh,Droid Sans Ethiopic,Droid Serif,Roboto,Droid Sans "
+     "Mono",
      0, 1252},
-    {0x626608a9, L"MVBoli",
-     L"Droid Arabic Naskh,Droid Sans Ethiopic,Droid Serif,Roboto,Droid Sans "
-     L"Mono",
+    {0x626608a9, "MVBoli",
+     "Droid Arabic Naskh,Droid Sans Ethiopic,Droid Serif,Roboto,Droid Sans "
+     "Mono",
      0, 1252},
-    {0x630501a3, L"SmallFonts",
-     L"Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
-    {0x65d0e2a9, L"FZYTK--GBK1-0", L"Droid Sans Fallback", 0, 936},
-    {0x669f29e1, L"FZSTK--GBK1-0", L"Droid Sans Fallback", 0, 936},
-    {0x673a9e5f, L"Tunga",
-     L"Droid Arabic Naskh,Droid Sans Ethiopic,Roboto,Droid Serif,Droid Sans "
-     L"Mono,Droid Sans Fallback",
+    {0x630501a3, "SmallFonts",
+     "Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
+    {0x65d0e2a9, "FZYTK--GBK1-0", "Droid Sans Fallback", 0, 936},
+    {0x669f29e1, "FZSTK--GBK1-0", "Droid Sans Fallback", 0, 936},
+    {0x673a9e5f, "Tunga",
+     "Droid Arabic Naskh,Droid Sans Ethiopic,Roboto,Droid Serif,Droid Sans "
+     "Mono,Droid Sans Fallback",
      0, 1252},
-    {0x691aa4ce, L"NiagaraSolid",
-     L"Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
-    {0x696259b7, L"Corbel",
-     L"Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
-    {0x696ee9be, L"STXihei", L"Droid Sans Fallback", 0, 936},
-    {0x6c59cf69, L"Dotum", L"Droid Sans Fallback", 0, 1252},
-    {0x707fa561, L"Gungsuh", L"Droid Sans Fallback", 2, 1252},
-    {0x71416bb2, L"ZWAdobeF",
-     L"Droid Arabic Naskh,Droid Sans Armenian,Droid Sans Ethiopic,Droid Sans "
-     L"Georgian,Droid Sans Hebrew,Droid Sans Thai",
+    {0x691aa4ce, "NiagaraSolid",
+     "Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
+    {0x696259b7, "Corbel",
+     "Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
+    {0x696ee9be, "STXihei", "Droid Sans Fallback", 0, 936},
+    {0x6c59cf69, "Dotum", "Droid Sans Fallback", 0, 1252},
+    {0x707fa561, "Gungsuh", "Droid Sans Fallback", 2, 1252},
+    {0x71416bb2, "ZWAdobeF",
+     "Droid Arabic Naskh,Droid Sans Armenian,Droid Sans Ethiopic,Droid Sans "
+     "Georgian,Droid Sans Hebrew,Droid Sans Thai",
      0, 1252},
-    {0x71b41801, L"Verdana",
-     L"Droid Serif,Roboto,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
-    {0x73f25e4c, L"PalatinoLinotype", L"Droid Sans Fallback", 0, 1252},
-    {0x73f4d19f, L"NiagaraEngraved",
-     L"Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
-    {0x74001694, L"MyriadProBlack", L"Book Antiqua,Constantia,Dotum,Georgia", 0,
+    {0x71b41801, "Verdana",
+     "Droid Serif,Roboto,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
+    {0x73f25e4c, "PalatinoLinotype", "Droid Sans Fallback", 0, 1252},
+    {0x73f4d19f, "NiagaraEngraved",
+     "Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
+    {0x74001694, "MyriadProBlack", "Book Antiqua,Constantia,Dotum,Georgia", 0,
      1252},
-    {0x74b14d8f, L"Haettenschweiler",
-     L"Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
-    {0x74cb44ee, L"NSimSun", L"Droid Sans Fallback", 1, 936},
-    {0x76b4d7ff, L"Shruti",
-     L"Droid Arabic Naskh,Droid Sans Ethiopic,Roboto,Droid Serif,Droid Sans "
-     L"Mono",
+    {0x74b14d8f, "Haettenschweiler",
+     "Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
+    {0x74cb44ee, "NSimSun", "Droid Sans Fallback", 1, 936},
+    {0x76b4d7ff, "Shruti",
+     "Droid Arabic Naskh,Droid Sans Ethiopic,Roboto,Droid Serif,Droid Sans "
+     "Mono",
      0, 1252},
-    {0x788b3533, L"Webdings",
-     L"Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 6, 42},
-    {0x797dde99, L"MSSerif",
-     L"Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
-    {0x7a0f9e9e, L"MSMincho", L"Droid Sans Fallback", 1, 1252},
-    {0x7b439caf, L"OldEnglishTextMT",
-     L"Droid Serif,Roboto,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
-    {0x8213a433, L"LucidaSans-Typewriter",
-     L"Droid Sans Mono,Droid Serif,Roboto,Droid Sans Fallback", 0, 1252},
-    {0x82fec929, L"AdobeSongStdL", L"Droid Sans Fallback", 0, 936},
-    {0x83581825, L"Modern",
-     L"Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
-    {0x835a2823, L"Algerian",
-     L"Droid Serif,Roboto,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
-    {0x83dab9f5, L"Script",
-     L"Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
-    {0x847b56da, L"Tahoma", L"Droid Sans Fallback", 0, 1252},
-    {0x8a783cb2, L"SimSun-PUA", L"Droid Sans Fallback", 0, 1252},
-    {0x8b5cac0e, L"Onyx",
-     L"Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
-    {0x8c6a499e, L"Gulim", L"Droid Sans Fallback", 0, 1252},
-    {0x8e0af790, L"JuiceITC",
-     L"Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
-    {0x8e8d43b2, L"Centaur",
-     L"Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 2, 1252},
-    {0x8ee4dcca, L"BookshelfSymbol7",
-     L"Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
-    {0x90794800, L"BellGothicStdLight",
-     L"Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
-    {0x909b516a, L"Century",
-     L"Droid Serif,Roboto,Droid Sans Mono,Droid Sans Fallback", 2, 1252},
-    {0x92ae370d, L"MSOutlook",
-     L"Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 4, 42},
-    {0x93c9fbf1, L"LucidaFax",
-     L"Droid Arabic Naskh,Droid Sans Ethiopic,Droid Serif,Roboto,Droid Sans "
-     L"Mono",
+    {0x788b3533, "Webdings",
+     "Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 6, 42},
+    {0x797dde99, "MSSerif",
+     "Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
+    {0x7a0f9e9e, "MSMincho", "Droid Sans Fallback", 1, 1252},
+    {0x7b439caf, "OldEnglishTextMT",
+     "Droid Serif,Roboto,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
+    {0x8213a433, "LucidaSans-Typewriter",
+     "Droid Sans Mono,Droid Serif,Roboto,Droid Sans Fallback", 0, 1252},
+    {0x82fec929, "AdobeSongStd", "Droid Sans Fallback", 0, 936},
+    {0x83581825, "Modern",
+     "Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
+    {0x835a2823, "Algerian",
+     "Droid Serif,Roboto,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
+    {0x83dab9f5, "Script",
+     "Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
+    {0x847b56da, "Tahoma", "Droid Sans Fallback", 0, 1252},
+    {0x8a783cb2, "SimSun-PUA", "Droid Sans Fallback", 0, 1252},
+    {0x8b5cac0e, "Onyx",
+     "Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
+    {0x8c6a499e, "Gulim", "Droid Sans Fallback", 0, 1252},
+    {0x8e0af790, "JuiceITC",
+     "Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
+    {0x8e8d43b2, "Centaur",
+     "Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 2, 1252},
+    {0x8ee4dcca, "BookshelfSymbol7",
+     "Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
+    {0x90794800, "BellGothicStdLight",
+     "Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
+    {0x909b516a, "Century",
+     "Droid Serif,Roboto,Droid Sans Mono,Droid Sans Fallback", 2, 1252},
+    {0x92ae370d, "MSOutlook",
+     "Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 4, 42},
+    {0x93c9fbf1, "LucidaFax",
+     "Droid Arabic Naskh,Droid Sans Ethiopic,Droid Serif,Roboto,Droid Sans "
+     "Mono",
      2, 1252},
-    {0x9565085e, L"BookAntiqua",
-     L"Droid Serif,Roboto,Droid Sans Mono,Droid Sans Fallback", 2, 1252},
-    {0x9856d95d, L"AdobeMingStdL", L"Droid Sans Fallback", 0, 949},
-    {0x9bbadd6b, L"ColonnaMT",
-     L"Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
-    {0x9cbd16a4, L"ShowcardGothic-Reg",
-     L"Droid Serif,Roboto,Droid Sans Mono,Droid Sans Fallbac", 0, 1252},
-    {0x9d73008e, L"MSSansSerif",
-     L"Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
-    {0xa0607db1, L"GungsuhChe", L"Droid Sans Fallback", 1, 1252},
-    {0xa0bcf6a1, L"LatinWide",
-     L"Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 2, 1252},
-    {0xa1429b36, L"Symbol",
-     L"Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 6, 42},
-    {0xa1fa5abc, L"Wingdings2",
-     L"Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 6, 42},
-    {0xa1fa5abd, L"Wingdings3",
-     L"Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 6, 42},
-    {0xa427bad4, L"InformalRoman-Regular",
-     L"Droid Arabic Naskh,Droid Sans Ethiopic", 8, 1252},
-    {0xa8b92ece, L"FZSTK--GBK1-0", L"Droid Sans Fallback", 0, 936},
-    {0xa8d83ece, L"CalifornianFB",
-     L"Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 2, 1252},
-    {0xaa3e082c, L"Kingsoft-Phonetic",
-     L"Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
-    {0xaa6bcabe, L"HarlowSolidItalic",
-     L"Droid Serif,Roboto,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
-    {0xade5337c, L"MSUIGothic",
-     L"Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
-    {0xb08dd941, L"WideLatin",
-     L"Droid Arabic Naskh,Droid Sans Ethiopic,Droid Serif,Roboto,Droid Sans "
-     L"Mono",
+    {0x9565085e, "BookAntiqua",
+     "Droid Serif,Roboto,Droid Sans Mono,Droid Sans Fallback", 2, 1252},
+    {0x9856d95d, "AdobeMingStd", "Droid Sans Fallback", 0, 949},
+    {0x9bbadd6b, "ColonnaMT",
+     "Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
+    {0x9cbd16a4, "ShowcardGothic-Reg",
+     "Droid Serif,Roboto,Droid Sans Mono,Droid Sans Fallbac", 0, 1252},
+    {0x9d73008e, "MSSansSerif",
+     "Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
+    {0xa0607db1, "GungsuhChe", "Droid Sans Fallback", 1, 1252},
+    {0xa0bcf6a1, "LatinWide",
+     "Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 2, 1252},
+    {0xa1429b36, "Symbol",
+     "Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 6, 42},
+    {0xa1fa5abc, "Wingdings2",
+     "Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 6, 42},
+    {0xa1fa5abd, "Wingdings3",
+     "Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 6, 42},
+    {0xa427bad4, "InformalRoman-Regular",
+     "Droid Arabic Naskh,Droid Sans Ethiopic", 8, 1252},
+    {0xa8b92ece, "FZSTK--GBK1-0", "Droid Sans Fallback", 0, 936},
+    {0xa8d83ece, "CalifornianFB",
+     "Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 2, 1252},
+    {0xaa3e082c, "Kingsoft-Phonetic",
+     "Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
+    {0xaa6bcabe, "HarlowSolidItalic",
+     "Droid Serif,Roboto,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
+    {0xade5337c, "MSUIGothic",
+     "Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
+    {0xb08dd941, "WideLatin",
+     "Droid Arabic Naskh,Droid Sans Ethiopic,Droid Serif,Roboto,Droid Sans "
+     "Mono",
      2, 1252},
-    {0xb207f05d, L"PoorRichard",
-     L"Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 2, 1252},
-    {0xb3bc492f, L"JuiceITC-Regular",
-     L"Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
-    {0xb5545399, L"Marlett",
-     L"Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 4, 42},
-    {0xb5dd1ebb, L"BritannicBold", L"Droid Arabic Naskh,Droid Sans Ethiopic", 0,
+    {0xb207f05d, "PoorRichard",
+     "Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 2, 1252},
+    {0xb3bc492f, "JuiceITC-Regular",
+     "Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
+    {0xb5545399, "Marlett",
+     "Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 4, 42},
+    {0xb5dd1ebb, "BritannicBold", "Droid Arabic Naskh,Droid Sans Ethiopic", 0,
      1252},
-    {0xb699c1c5, L"LucidaCalligraphy-Italic",
-     L"Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
-    {0xb725d629, L"TimesNewRoman", L"Droid Sans Fallback", 2, 1252},
-    {0xb7eaebeb, L"AdobeHeitiStdR", L"Droid Sans Fallback", 0, 936},
-    {0xbd29c486, L"BerlinSansFBDemi-Bold",
-     L"Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
-    {0xbe8a8db4, L"BookshelfSymbolSeven",
-     L"Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
-    {0xc16c0118, L"AdobeHebrew",
-     L"Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback,Droid Arabic "
-     L"Naskh,Droid Sans Ethiopic",
+    {0xb699c1c5, "LucidaCalligraphy-Italic",
+     "Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
+    {0xb725d629, "TimesNewRoman", "Droid Sans Fallback", 2, 1252},
+    {0xb7eaebeb, "AdobeHeitiStdR", "Droid Sans Fallback", 0, 936},
+    {0xbd29c486, "BerlinSansFBDemi-Bold",
+     "Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
+    {0xbe8a8db4, "BookshelfSymbolSeven",
+     "Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
+    {0xc16c0118, "AdobeHebrew",
+     "Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback,Droid Arabic "
+     "Naskh,Droid Sans Ethiopic",
      0, 1252},
-    {0xc318b0af, L"MyriadProLight",
-     L"Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
-    {0xc65e5659, L"CambriaMath", L"Droid Sans Fallback", 2, 1252},
-    {0xc75c8f05, L"LucidaConsole",
-     L"Droid Sans Mono,Droid Serif,Roboto,Droid Sans Fallback", 1, 1252},
-    {0xca7c35d6, L"Calibri", L"Droid Sans Fallback", 0, 1252},
-    {0xcb053f53, L"MicrosoftYaHei", L"Droid Sans Fallback", 0, 936},
-    {0xcb7190f9, L"Magneto-Bold",
-     L"Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
-    {0xcca00cc5, L"System",
-     L"Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
-    {0xccad6f76, L"Jokerman-Regular",
-     L"Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
-    {0xccc5818c, L"EuroSign",
-     L"Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
-    {0xcf3d7234, L"LucidaHandwriting-Italic",
-     L"Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
-    {0xcf7b8fdb, L"MinionPro",
-     L"Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
-    {0xcfe5755f, L"Simhei", L"Droid Sans Fallback", 1, 936},
-    {0xd011f4ee, L"MSPGothic", L"Droid Sans Fallback", 0, 1252},
-    {0xd060e7ef, L"Vivaldi",
-     L"Droid Serif,Roboto,Droid Sans Mono,Droid Sans Fallback", 8, 1252},
-    {0xd07edec1, L"FranklinGothic-Medium",
-     L"Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
-    {0xd107243f, L"SimSun", L"Droid Sans Fallback", 0, 936},
-    {0xd1881562, L"ArialNarrow",
-     L"Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
-    {0xd22b7dce, L"BodoniMTPosterCompressed",
-     L"Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
-    {0xd22bfa60, L"ComicSansMS", L"Droid Serif,Roboto,Droid Sans Fallback", 8,
+    {0xc318b0af, "MyriadProLight",
+     "Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
+    {0xc65e5659, "CambriaMath", "Droid Sans Fallback", 2, 1252},
+    {0xc75c8f05, "LucidaConsole",
+     "Droid Sans Mono,Droid Serif,Roboto,Droid Sans Fallback", 1, 1252},
+    {0xca7c35d6, "Calibri", "Droid Sans Fallback", 0, 1252},
+    {0xcb053f53, "MicrosoftYaHei", "Droid Sans Fallback", 0, 936},
+    {0xcb7190f9, "Magneto-Bold",
+     "Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
+    {0xcca00cc5, "System",
+     "Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
+    {0xccad6f76, "Jokerman-Regular",
+     "Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
+    {0xccc5818c, "EuroSign",
+     "Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
+    {0xcf3d7234, "LucidaHandwriting-Italic",
+     "Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
+    {0xcf7b8fdb, "MinionPro",
+     "Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
+    {0xcfe5755f, "Simhei", "Droid Sans Fallback", 1, 936},
+    {0xd011f4ee, "MSPGothic", "Droid Sans Fallback", 0, 1252},
+    {0xd060e7ef, "Vivaldi",
+     "Droid Serif,Roboto,Droid Sans Mono,Droid Sans Fallback", 8, 1252},
+    {0xd07edec1, "FranklinGothic-Medium",
+     "Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
+    {0xd107243f, "SimSun", "Droid Sans Fallback", 0, 936},
+    {0xd1881562, "ArialNarrow",
+     "Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
+    {0xd22b7dce, "BodoniMTPosterCompressed",
+     "Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
+    {0xd22bfa60, "ComicSansMS", "Droid Serif,Roboto,Droid Sans Fallback", 8,
      1252},
-    {0xd3bd0e35, L"Bauhaus93",
-     L"Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
-    {0xd429ee7a, L"STFangsong", L"Droid Sans Fallback", 0, 936},
-    {0xd6679c12, L"BernardMTCondensed",
-     L"Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
-    {0xd8e8a027, L"LucidaSans",
-     L"Droid Arabic Naskh,Droid Sans Ethiopic,Droid Serif,Roboto", 0, 1252},
-    {0xd9fe7761, L"HighTowerText-Reg",
-     L"Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 2, 1252},
-    {0xda7e551e, L"STSong", L"Droid Sans Fallback", 0, 936},
-    {0xdaa6842d, L"STZhongsong", L"Droid Sans Fallback", 0, 936},
-    {0xdaaab93f, L"STFangsong", L"Droid Sans Fallback", 0, 936},
-    {0xdaeb0713, L"STSong",
-     L"Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 0, 936},
-    {0xdafedbef, L"STCaiyun", L"Droid Sans Fallback", 0, 936},
-    {0xdb00a3d9, L"Broadway",
-     L"Droid Serif,Roboto,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
-    {0xdb1f5ad4, L"STXinwei", L"Droid Sans Fallback", 0, 936},
-    {0xdb326e7f, L"STKaiti", L"Droid Sans Fallback", 0, 936},
-    {0xdb69595a, L"STHupo", L"Droid Sans Fallback", 0, 936},
-    {0xdba0082c, L"STXihei", L"Droid Sans Fallback", 0, 936},
-    {0xdbd0ab18, L"STXingkai", L"Droid Sans Fallback", 0, 936},
-    {0xdc1a7db1, L"STLiti", L"Droid Sans Fallback", 0, 936},
-    {0xdc33075f, L"KristenITC-Regular",
-     L"Droid Arabic Naskh,Droid Sans Ethiopic,Droid Serif,Roboto", 8, 1252},
-    {0xdcc7009c, L"Harrington",
-     L"Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
-    {0xdd712466, L"ArialBlack",
-     L"Droid Serif,Roboto,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
-    {0xdde87b3e, L"Impact",
-     L"Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
-    {0xdf69fb32, L"SnapITC",
-     L"Droid Arabic Naskh,Droid Sans Ethiopic,Droid Serif,Roboto,Droid Sans "
-     L"Mono",
+    {0xd3bd0e35, "Bauhaus93",
+     "Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
+    {0xd429ee7a, "STFangsong", "Droid Sans Fallback", 0, 936},
+    {0xd6679c12, "BernardMTCondensed",
+     "Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
+    {0xd8e8a027, "LucidaSans",
+     "Droid Arabic Naskh,Droid Sans Ethiopic,Droid Serif,Roboto", 0, 1252},
+    {0xd9fe7761, "HighTowerText-Reg",
+     "Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 2, 1252},
+    {0xda7e551e, "STSong", "Droid Sans Fallback", 0, 936},
+    {0xdaa6842d, "STZhongsong", "Droid Sans Fallback", 0, 936},
+    {0xdaaab93f, "STFangsong", "Droid Sans Fallback", 0, 936},
+    {0xdaeb0713, "STSong",
+     "Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 0, 936},
+    {0xdafedbef, "STCaiyun", "Droid Sans Fallback", 0, 936},
+    {0xdb00a3d9, "Broadway",
+     "Droid Serif,Roboto,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
+    {0xdb1f5ad4, "STXinwei", "Droid Sans Fallback", 0, 936},
+    {0xdb326e7f, "STKaiti", "Droid Sans Fallback", 0, 936},
+    {0xdb69595a, "STHupo", "Droid Sans Fallback", 0, 936},
+    {0xdba0082c, "STXihei", "Droid Sans Fallback", 0, 936},
+    {0xdbd0ab18, "STXingkai", "Droid Sans Fallback", 0, 936},
+    {0xdc1a7db1, "STLiti", "Droid Sans Fallback", 0, 936},
+    {0xdc33075f, "KristenITC-Regular",
+     "Droid Arabic Naskh,Droid Sans Ethiopic,Droid Serif,Roboto", 8, 1252},
+    {0xdcc7009c, "Harrington",
+     "Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
+    {0xdd712466, "ArialBlack",
+     "Droid Serif,Roboto,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
+    {0xdde87b3e, "Impact",
+     "Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
+    {0xdf69fb32, "SnapITC",
+     "Droid Arabic Naskh,Droid Sans Ethiopic,Droid Serif,Roboto,Droid Sans "
+     "Mono",
      0, 1252},
-    {0xdf8b25e8, L"CenturyGothic",
-     L"Droid Serif,Roboto,Droid Serif,Droid Sans Mono", 0, 1252},
-    {0xe0f705c0, L"KristenITC",
-     L"Droid Arabic Naskh,Droid Sans Ethiopic,Droid Serif,Roboto", 8, 1252},
-    {0xe1427573, L"Raavi",
-     L"Droid Arabic Naskh,Droid Sans Ethiopic,Roboto,Droid Serif,Droid Sans "
-     L"Mono",
+    {0xdf8b25e8, "CenturyGothic",
+     "Droid Serif,Roboto,Droid Serif,Droid Sans Mono", 0, 1252},
+    {0xe0f705c0, "KristenITC",
+     "Droid Arabic Naskh,Droid Sans Ethiopic,Droid Serif,Roboto", 8, 1252},
+    {0xe1427573, "Raavi",
+     "Droid Arabic Naskh,Droid Sans Ethiopic,Roboto,Droid Serif,Droid Sans "
+     "Mono",
      0, 1252},
-    {0xe2cea0cb, L"Magneto",
-     L"Droid Arabic Naskh,Droid Sans Ethiopic,Droid Serif,Roboto,Droid Sans "
-     L"Mono",
+    {0xe2cea0cb, "Magneto",
+     "Droid Arabic Naskh,Droid Sans Ethiopic,Droid Serif,Roboto,Droid Sans "
+     "Mono",
      0, 1252},
-    {0xe36a9e17, L"Ravie",
-     L"Droid Arabic Naskh,Droid Sans Ethiopic,Roboto,Droid Serif,Droid Sans "
-     L"Mono",
+    {0xe36a9e17, "Ravie",
+     "Droid Arabic Naskh,Droid Sans Ethiopic,Roboto,Droid Serif,Droid Sans "
+     "Mono",
      0, 1252},
-    {0xe433f8e2, L"Parchment",
-     L"Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 8, 1252},
-    {0xe43dff4a, L"Wingdings",
-     L"Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 4, 42},
-    {0xe4e2c405, L"MTExtra",
-     L"Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 6, 42},
-    {0xe618cc35, L"InformalRoman",
-     L"Droid Arabic Naskh,Droid Sans Ethiopic,Roboto,Droid Serif", 8, 1252},
-    {0xe6c27ffc, L"Mistral",
-     L"Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 8, 1252},
-    {0xe7ebf4b9, L"Courier", L"Droid Sans Fallback", 0, 1252},
-    {0xe8bc4a9d, L"MSReferenceSpecialty",
-     L"Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
-    {0xe90fb013, L"TempusSansITC",
-     L"Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
-    {0xec637b42, L"Consolas", L"Droid Sans Fallback", 1, 1252},
-    {0xed3a683b, L"STXinwei", L"Droid Sans Fallback", 0, 936},
-    {0xef264cd1, L"LucidaHandwriting",
-     L"Droid Arabic Naskh,Droid Sans Ethiopic,Droid Serif,Roboto,Droid Sans "
-     L"Mono",
+    {0xe433f8e2, "Parchment",
+     "Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 8, 1252},
+    {0xe43dff4a, "Wingdings",
+     "Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 4, 42},
+    {0xe4e2c405, "MTExtra",
+     "Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 6, 42},
+    {0xe618cc35, "InformalRoman",
+     "Droid Arabic Naskh,Droid Sans Ethiopic,Roboto,Droid Serif", 8, 1252},
+    {0xe6c27ffc, "Mistral",
+     "Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 8, 1252},
+    {0xe7ebf4b9, "Courier", "Droid Sans Fallback", 0, 1252},
+    {0xe8bc4a9d, "MSReferenceSpecialty",
+     "Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
+    {0xe90fb013, "TempusSansITC",
+     "Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
+    {0xec637b42, "Consolas", "Droid Sans Fallback", 1, 1252},
+    {0xed3a683b, "STXinwei", "Droid Sans Fallback", 0, 936},
+    {0xef264cd1, "LucidaHandwriting",
+     "Droid Arabic Naskh,Droid Sans Ethiopic,Droid Serif,Roboto,Droid Sans "
+     "Mono",
      0, 1252},
-    {0xf086bca2, L"BaskervilleOldFace",
-     L"Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
-    {0xf1028030, L"Mangal",
-     L"Droid Arabic Naskh,Droid Sans Ethiopic,Droid Serif,Roboto,Droid Sans "
-     L"Mono",
+    {0xf086bca2, "BaskervilleOldFace",
+     "Roboto,Droid Serif,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
+    {0xf1028030, "Mangal",
+     "Droid Arabic Naskh,Droid Sans Ethiopic,Droid Serif,Roboto,Droid Sans "
+     "Mono",
      2, 1252},
-    {0xf1da7eb9, L"ShowcardGothic",
-     L"Droid Serif,Roboto,Droid Sans Mono,Droid Sans Fallbac", 0, 1252},
-    {0xf210f06a, L"ArialMT",
-     L"Droid Arabic Naskh,Droid Sans Ethiopic,Roboto,Droid Serif", 0, 1252},
-    {0xf477f16a, L"Latha",
-     L"Droid Arabic Naskh,Droid Sans Ethiopic,Roboto,Droid Serif,Droid Sans "
-     L"Mono",
+    {0xf1da7eb9, "ShowcardGothic",
+     "Droid Serif,Roboto,Droid Sans Mono,Droid Sans Fallbac", 0, 1252},
+    {0xf210f06a, "ArialMT",
+     "Droid Arabic Naskh,Droid Sans Ethiopic,Roboto,Droid Serif", 0, 1252},
+    {0xf477f16a, "Latha",
+     "Droid Arabic Naskh,Droid Sans Ethiopic,Roboto,Droid Serif,Droid Sans "
+     "Mono",
      0, 1252},
-    {0xf616f3dd, L"LiSu", L"Droid Sans Fallback", 1, 936},
-    {0xfa479aa6, L"MicrosoftYaHei", L"Droid Sans Fallback", 0, 936},
-    {0xfcd19697, L"BookmanOldStyle",
-     L"Droid Serif,Roboto,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
-    {0xfe209a82, L"LucidaCalligraphy",
-     L"Droid Arabic Naskh,Droid Sans Ethiopic,Droid Serif,Roboto,Droid Sans "
-     L"Mono",
+    {0xf616f3dd, "LiSu", "Droid Sans Fallback", 1, 936},
+    {0xfa479aa6, "MicrosoftYaHei", "Droid Sans Fallback", 0, 936},
+    {0xfcd19697, "BookmanOldStyle",
+     "Droid Serif,Roboto,Droid Sans Mono,Droid Sans Fallback", 0, 1252},
+    {0xfe209a82, "LucidaCalligraphy",
+     "Droid Arabic Naskh,Droid Sans Ethiopic,Droid Serif,Roboto,Droid Sans "
+     "Mono",
      0, 1252},
-    {0xfef135f8, L"AdobeHeitiStd-Regular", L"Droid Sans Fallback", 0, 936},
+    {0xfef135f8, "AdobeHeitiStd-Regular", "Droid Sans Fallback", 0, 936},
 };
 #endif
 
 }  // namespace
 
-const FGAS_FONTUSB* FGAS_GetUnicodeBitField(wchar_t wUnicode) {
-  int32_t iEnd = sizeof(g_FXGdiFontUSBTable) / sizeof(FGAS_FONTUSB) - 1;
-  ASSERT(iEnd >= 0);
-
-  int32_t iStart = 0;
-  int32_t iMid;
-  do {
-    iMid = (iStart + iEnd) / 2;
-    const FGAS_FONTUSB& usb = g_FXGdiFontUSBTable[iMid];
-    if (wUnicode < usb.wStartUnicode)
-      iEnd = iMid - 1;
-    else if (wUnicode > usb.wEndUnicode)
-      iStart = iMid + 1;
-    else
-      return &usb;
-  } while (iStart <= iEnd);
+const FGAS_FONTUSB* FGAS_GetUnicodeBitField(wchar_t unicode) {
+  // This search is trying to find the entry where the unicode character falls
+  // bewtween start and end. std::upper_bound needs to be used here instead of
+  // lower_bound, because they return the first value that meets the
+  // requirement, as though they are linearly searching. For lower_bound this
+  // means the first element less then the value, and for upper_bound this means
+  // the first element greater then the value. Since the entries are sorted in
+  // ascending order, the correct entry is the first one with an end greater,
+  // aka after, the value.
+  auto* result = std::upper_bound(
+      std::begin(g_FXGdiFontUSBTable), std::end(g_FXGdiFontUSBTable), unicode,
+      [](const wchar_t unicode, const FGAS_FONTUSB& iter) {
+        return iter.wEndUnicode > unicode;
+      });
+  if (result != std::end(g_FXGdiFontUSBTable) &&
+      result->wStartUnicode <= unicode && result->wEndUnicode >= unicode)
+    return result;
   return nullptr;
 }
 
-WideString FGAS_FontNameToEnglishName(const WideStringView& wsLocalName) {
+WideString FGAS_FontNameToEnglishName(WideStringView wsLocalName) {
   uint32_t dwLocalNameHash = FX_HashCode_GetW(wsLocalName, true);
   const FGAS_FontInfo* pEnd = g_XFAFontsMap + FX_ArraySize(g_XFAFontsMap);
   const FGAS_FontInfo* pFontInfo =
@@ -1896,11 +1878,11 @@
                          return entry.dwFontNameHash < hash;
                        });
   if (pFontInfo < pEnd && pFontInfo->dwFontNameHash == dwLocalNameHash)
-    return pFontInfo->pPsName;
+    return WideString::FromASCII(ByteStringView(pFontInfo->pPsName));
   return WideString(wsLocalName);
 }
 
-const FGAS_FontInfo* FGAS_FontInfoByFontName(const WideStringView& wsFontName) {
+const FGAS_FontInfo* FGAS_FontInfoByFontName(WideStringView wsFontName) {
   WideString wsFontNameTemp(wsFontName);
   wsFontNameTemp.Remove(L' ');
   uint32_t dwCurFontNameHash =
diff --git a/xfa/fgas/font/fgas_fontutils.h b/xfa/fgas/font/fgas_fontutils.h
index 3bfd939..91998d5 100644
--- a/xfa/fgas/font/fgas_fontutils.h
+++ b/xfa/fgas/font/fgas_fontutils.h
@@ -19,15 +19,15 @@
 const FGAS_FONTUSB* FGAS_GetUnicodeBitField(wchar_t wUnicode);
 
 struct FGAS_FontInfo {
-  uint32_t dwFontNameHash;
-  const wchar_t* pPsName;
-  const wchar_t* pReplaceFont;
+  uint32_t dwFontNameHash;   // WideString hash.
+  const char* pPsName;       // Raw, POD struct.
+  const char* pReplaceFont;  // Raw, POD struct.
   uint16_t dwStyles;
   uint16_t wCodePage;
 };
 
-WideString FGAS_FontNameToEnglishName(const WideStringView& wsLocalName);
+WideString FGAS_FontNameToEnglishName(WideStringView wsLocalName);
 
-const FGAS_FontInfo* FGAS_FontInfoByFontName(const WideStringView& wsFontName);
+const FGAS_FontInfo* FGAS_FontInfoByFontName(WideStringView wsFontName);
 
 #endif  // XFA_FGAS_FONT_FGAS_FONTUTILS_H_
diff --git a/xfa/fgas/layout/BUILD.gn b/xfa/fgas/layout/BUILD.gn
new file mode 100644
index 0000000..61d2e75
--- /dev/null
+++ b/xfa/fgas/layout/BUILD.gn
@@ -0,0 +1,60 @@
+# Copyright 2018 The 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.
+
+import("../../../pdfium.gni")
+import("../../../testing/test.gni")
+
+assert(pdf_enable_xfa)
+
+source_set("layout") {
+  sources = [
+    "cfx_break.cpp",
+    "cfx_break.h",
+    "cfx_breakline.cpp",
+    "cfx_breakline.h",
+    "cfx_breakpiece.cpp",
+    "cfx_breakpiece.h",
+    "cfx_char.cpp",
+    "cfx_char.h",
+    "cfx_linkuserdata.cpp",
+    "cfx_linkuserdata.h",
+    "cfx_rtfbreak.cpp",
+    "cfx_rtfbreak.h",
+    "cfx_textpiece.cpp",
+    "cfx_textpiece.h",
+    "cfx_textuserdata.cpp",
+    "cfx_textuserdata.h",
+    "cfx_txtbreak.cpp",
+    "cfx_txtbreak.h",
+    "fx_arabic.cpp",
+    "fx_arabic.h",
+    "fx_linebreak.cpp",
+    "fx_linebreak.h",
+  ]
+  deps = [
+    "../:fgas",
+    "../../../core/fxcrt",
+    "../../../core/fxcrt/css",
+    "../../../core/fxge",
+  ]
+  configs += [
+    "../../../:pdfium_core_config",
+    "../../:xfa_warnings",
+  ]
+  visibility = [ "../../../*" ]
+}
+
+pdfium_unittest_source_set("unittests") {
+  sources = [
+    "cfx_rtfbreak_unittest.cpp",
+    "cfx_txtbreak_unittest.cpp",
+  ]
+  deps = [
+    ":layout",
+    "../:fgas",
+    "../../../core/fxge",
+    "../../../testing:unit_test_support",
+  ]
+  pdfium_root_dir = "../../../"
+}
diff --git a/xfa/fgas/layout/cfx_break.cpp b/xfa/fgas/layout/cfx_break.cpp
index 0f52a2d..6330a51 100644
--- a/xfa/fgas/layout/cfx_break.cpp
+++ b/xfa/fgas/layout/cfx_break.cpp
@@ -9,44 +9,22 @@
 #include <algorithm>
 #include <vector>
 
+#include "core/fxcrt/fx_safe_types.h"
 #include "third_party/base/stl_util.h"
 #include "xfa/fgas/font/cfgas_gefont.h"
 
-namespace {
-
-const int kMinimumTabWidth = 160000;
-
-}  // namespace
+const float CFX_Break::kConversionFactor = 20000.0f;
+const int CFX_Break::kMinimumTabWidth = 160000;
 
 CFX_Break::CFX_Break(uint32_t dwLayoutStyles)
-    : m_eCharType(FX_CHARTYPE_Unknown),
-      m_bSingleLine(false),
-      m_bCombText(false),
-      m_dwIdentity(0),
-      m_dwLayoutStyles(dwLayoutStyles),
-      m_iLineStart(0),
-      m_iLineWidth(2000000),
-      m_wParagraphBreakChar(L'\n'),
-      m_iFontSize(240),
-      m_iTabWidth(720000),
-      m_iHorizontalScale(100),
-      m_iVerticalScale(100),
-      m_iTolerance(0),
-      m_iCharSpace(0),
-      m_iDefChar(0),
-      m_wDefChar(0xFEFF),
-      m_pFont(nullptr),
-      m_pCurLine(nullptr),
-      m_iReadyLineIndex(-1) {
-  m_pCurLine = &m_Line[0];
-}
+    : m_dwLayoutStyles(dwLayoutStyles), m_pCurLine(&m_Lines[0]) {}
 
-CFX_Break::~CFX_Break() {}
+CFX_Break::~CFX_Break() = default;
 
 void CFX_Break::Reset() {
-  m_eCharType = FX_CHARTYPE_Unknown;
-  m_Line[0].Clear();
-  m_Line[1].Clear();
+  m_eCharType = FX_CHARTYPE::kUnknown;
+  for (CFX_BreakLine& line : m_Lines)
+    line.Clear();
 }
 
 void CFX_Break::SetLayoutStyles(uint32_t dwLayoutStyles) {
@@ -80,61 +58,43 @@
 
   SetBreakStatus();
   m_pFont = pFont;
-  FontChanged();
 }
 
 void CFX_Break::SetFontSize(float fFontSize) {
-  int32_t iFontSize = FXSYS_round(fFontSize * 20.0f);
+  int32_t iFontSize = FXSYS_roundf(fFontSize * 20.0f);
   if (m_iFontSize == iFontSize)
     return;
 
   SetBreakStatus();
   m_iFontSize = iFontSize;
-  FontChanged();
 }
 
 void CFX_Break::SetBreakStatus() {
   ++m_dwIdentity;
-  int32_t iCount = m_pCurLine->CountChars();
-  if (iCount < 1)
+  if (m_pCurLine->m_LineChars.empty())
     return;
 
-  CFX_Char* tc = m_pCurLine->GetChar(iCount - 1);
+  CFX_Char* tc = m_pCurLine->GetChar(m_pCurLine->m_LineChars.size() - 1);
   if (tc->m_dwStatus == CFX_BreakType::None)
     tc->m_dwStatus = CFX_BreakType::Piece;
 }
 
-FX_CHARTYPE CFX_Break::GetUnifiedCharType(FX_CHARTYPE chartype) const {
-  return chartype >= FX_CHARTYPE_ArabicAlef ? FX_CHARTYPE_Arabic : chartype;
+bool CFX_Break::IsGreaterThanLineWidth(int32_t width) const {
+  FX_SAFE_INT32 line_width = m_iLineWidth;
+  line_width += m_iTolerance;
+  return line_width.IsValid() && width > line_width.ValueOrDie();
 }
 
-void CFX_Break::FontChanged() {
-  m_iDefChar = 0;
-  if (!m_pFont || m_wDefChar == 0xFEFF)
-    return;
-
-  m_pFont->GetCharWidth(m_wDefChar, m_iDefChar);
-  m_iDefChar *= m_iFontSize;
+FX_CHARTYPE CFX_Break::GetUnifiedCharType(FX_CHARTYPE chartype) const {
+  return chartype >= FX_CHARTYPE::kArabicAlef ? FX_CHARTYPE::kArabic : chartype;
 }
 
 void CFX_Break::SetTabWidth(float fTabWidth) {
   // Note, the use of max here was only done in the TxtBreak code. Leaving this
   // in for the RTFBreak code for consistency. If we see issues with tab widths
   // we may need to fix this.
-  m_iTabWidth = std::max(FXSYS_round(fTabWidth * 20000.0f), kMinimumTabWidth);
-}
-
-void CFX_Break::SetDefaultChar(wchar_t wch) {
-  m_wDefChar = wch;
-  m_iDefChar = 0;
-  if (m_wDefChar == 0xFEFF || !m_pFont)
-    return;
-
-  m_pFont->GetCharWidth(m_wDefChar, m_iDefChar);
-  if (m_iDefChar < 0)
-    m_iDefChar = 0;
-  else
-    m_iDefChar *= m_iFontSize;
+  m_iTabWidth =
+      std::max(FXSYS_roundf(fTabWidth * kConversionFactor), kMinimumTabWidth);
 }
 
 void CFX_Break::SetParagraphBreakChar(wchar_t wch) {
@@ -144,19 +104,19 @@
 }
 
 void CFX_Break::SetLineBreakTolerance(float fTolerance) {
-  m_iTolerance = FXSYS_round(fTolerance * 20000.0f);
+  m_iTolerance = FXSYS_roundf(fTolerance * kConversionFactor);
 }
 
 void CFX_Break::SetCharSpace(float fCharSpace) {
-  m_iCharSpace = FXSYS_round(fCharSpace * 20000.0f);
+  m_iCharSpace = FXSYS_roundf(fCharSpace * kConversionFactor);
 }
 
 void CFX_Break::SetLineBoundary(float fLineStart, float fLineEnd) {
   if (fLineStart > fLineEnd)
     return;
 
-  m_iLineStart = FXSYS_round(fLineStart * 20000.0f);
-  m_iLineWidth = FXSYS_round(fLineEnd * 20000.0f);
+  m_iLineStart = FXSYS_roundf(fLineStart * kConversionFactor);
+  m_iLineWidth = FXSYS_roundf(fLineEnd * kConversionFactor);
   m_pCurLine->m_iStart = std::min(m_pCurLine->m_iStart, m_iLineWidth);
   m_pCurLine->m_iStart = std::max(m_pCurLine->m_iStart, m_iLineStart);
 }
@@ -172,7 +132,7 @@
   while (iStart > -1) {
     CFX_Char* pTC = &tca[iStart--];
     if (((bRichText && pTC->m_iCharWidth < 0) || bOmitChar) &&
-        pTC->GetCharType() == FX_CHARTYPE_Combination) {
+        pTC->GetCharType() == FX_CHARTYPE::kCombination) {
       continue;
     }
     if (--index < 0)
@@ -183,20 +143,20 @@
 
 int32_t CFX_Break::CountBreakPieces() const {
   return HasLine() ? pdfium::CollectionSize<int32_t>(
-                         m_Line[m_iReadyLineIndex].m_LinePieces)
+                         m_Lines[m_iReadyLineIndex].m_LinePieces)
                    : 0;
 }
 
 const CFX_BreakPiece* CFX_Break::GetBreakPieceUnstable(int32_t index) const {
   if (!HasLine())
     return nullptr;
-  if (!pdfium::IndexInBounds(m_Line[m_iReadyLineIndex].m_LinePieces, index))
+  if (!pdfium::IndexInBounds(m_Lines[m_iReadyLineIndex].m_LinePieces, index))
     return nullptr;
-  return &m_Line[m_iReadyLineIndex].m_LinePieces[index];
+  return &m_Lines[m_iReadyLineIndex].m_LinePieces[index];
 }
 
 void CFX_Break::ClearBreakPieces() {
   if (HasLine())
-    m_Line[m_iReadyLineIndex].Clear();
+    m_Lines[m_iReadyLineIndex].Clear();
   m_iReadyLineIndex = -1;
 }
diff --git a/xfa/fgas/layout/cfx_break.h b/xfa/fgas/layout/cfx_break.h
index 789220d..4f0dcb3 100644
--- a/xfa/fgas/layout/cfx_break.h
+++ b/xfa/fgas/layout/cfx_break.h
@@ -10,6 +10,7 @@
 #include <stdint.h>
 
 #include "core/fxcrt/retain_ptr.h"
+#include "core/fxcrt/unowned_ptr.h"
 #include "xfa/fgas/layout/cfx_breakline.h"
 
 class CFGAS_GEFont;
@@ -50,44 +51,45 @@
 
   void SetCharSpace(float fCharSpace);
   void SetParagraphBreakChar(wchar_t wch);
-  void SetDefaultChar(wchar_t wch);
 
   int32_t CountBreakPieces() const;
   const CFX_BreakPiece* GetBreakPieceUnstable(int32_t index) const;
   void ClearBreakPieces();
 
   CFX_Char* GetLastChar(int32_t index, bool bOmitChar, bool bRichText) const;
+  const CFX_BreakLine* GetCurrentLineForTesting() const {
+    return m_pCurLine.Get();
+  }
 
  protected:
+  static const int kMinimumTabWidth;
+  static const float kConversionFactor;
+
   explicit CFX_Break(uint32_t dwLayoutStyles);
 
   void SetBreakStatus();
   bool HasLine() const { return m_iReadyLineIndex >= 0; }
+  bool IsGreaterThanLineWidth(int32_t width) const;
   FX_CHARTYPE GetUnifiedCharType(FX_CHARTYPE dwType) const;
 
-  FX_CHARTYPE m_eCharType;
-  bool m_bSingleLine;
-  bool m_bCombText;
-  uint32_t m_dwIdentity;
-  uint32_t m_dwLayoutStyles;
-  int32_t m_iLineStart;
-  int32_t m_iLineWidth;
-  wchar_t m_wParagraphBreakChar;
-  int32_t m_iFontSize;
-  int32_t m_iTabWidth;
-  int32_t m_iHorizontalScale;
-  int32_t m_iVerticalScale;
-  int32_t m_iTolerance;
-  int32_t m_iCharSpace;
-  int32_t m_iDefChar;
-  wchar_t m_wDefChar;
+  FX_CHARTYPE m_eCharType = FX_CHARTYPE::kUnknown;
+  bool m_bSingleLine = false;
+  bool m_bCombText = false;
+  uint32_t m_dwIdentity = 0;
+  uint32_t m_dwLayoutStyles = 0;
+  int32_t m_iLineStart = 0;
+  int32_t m_iLineWidth = 2000000;
+  wchar_t m_wParagraphBreakChar = L'\n';
+  int32_t m_iFontSize = 240;
+  int32_t m_iTabWidth = 720000;
+  int32_t m_iHorizontalScale = 100;
+  int32_t m_iVerticalScale = 100;
+  int32_t m_iTolerance = 0;
+  int32_t m_iCharSpace = 0;
   RetainPtr<CFGAS_GEFont> m_pFont;
-  CFX_BreakLine m_Line[2];
-  CFX_BreakLine* m_pCurLine;
-  int8_t m_iReadyLineIndex;
-
- private:
-  void FontChanged();
+  UnownedPtr<CFX_BreakLine> m_pCurLine;
+  int8_t m_iReadyLineIndex = -1;
+  CFX_BreakLine m_Lines[2];
 };
 
 #endif  // XFA_FGAS_LAYOUT_CFX_BREAK_H_
diff --git a/xfa/fgas/layout/cfx_breakline.cpp b/xfa/fgas/layout/cfx_breakline.cpp
index 0788603..02203c9 100644
--- a/xfa/fgas/layout/cfx_breakline.cpp
+++ b/xfa/fgas/layout/cfx_breakline.cpp
@@ -8,33 +8,15 @@
 
 #include "third_party/base/stl_util.h"
 
-CFX_BreakLine::CFX_BreakLine() : m_iStart(0), m_iWidth(0), m_iArabicChars(0) {}
+CFX_BreakLine::CFX_BreakLine() = default;
 
-CFX_BreakLine::~CFX_BreakLine() {}
-
-int32_t CFX_BreakLine::CountChars() const {
-  return pdfium::CollectionSize<int32_t>(m_LineChars);
-}
+CFX_BreakLine::~CFX_BreakLine() = default;
 
 CFX_Char* CFX_BreakLine::GetChar(int32_t index) {
   ASSERT(pdfium::IndexInBounds(m_LineChars, index));
   return &m_LineChars[index];
 }
 
-const CFX_Char* CFX_BreakLine::GetChar(int32_t index) const {
-  ASSERT(pdfium::IndexInBounds(m_LineChars, index));
-  return &m_LineChars[index];
-}
-
-int32_t CFX_BreakLine::CountPieces() const {
-  return pdfium::CollectionSize<int32_t>(m_LinePieces);
-}
-
-const CFX_BreakPiece* CFX_BreakLine::GetPiece(int32_t index) const {
-  ASSERT(index >= 0 && index < CountPieces());
-  return &m_LinePieces[index];
-}
-
 int32_t CFX_BreakLine::GetLineEnd() const {
   return m_iStart + m_iWidth;
 }
@@ -45,3 +27,12 @@
   m_iWidth = 0;
   m_iArabicChars = 0;
 }
+
+void CFX_BreakLine::IncrementArabicCharCount() {
+  ++m_iArabicChars;
+}
+
+void CFX_BreakLine::DecrementArabicCharCount() {
+  ASSERT(m_iArabicChars > 0);
+  --m_iArabicChars;
+}
diff --git a/xfa/fgas/layout/cfx_breakline.h b/xfa/fgas/layout/cfx_breakline.h
index 0b83ee6..c432b35 100644
--- a/xfa/fgas/layout/cfx_breakline.h
+++ b/xfa/fgas/layout/cfx_breakline.h
@@ -9,30 +9,30 @@
 
 #include <vector>
 
-#include "core/fxcrt/cfx_char.h"
 #include "xfa/fgas/layout/cfx_breakpiece.h"
+#include "xfa/fgas/layout/cfx_char.h"
 
 class CFX_BreakLine {
  public:
   CFX_BreakLine();
   ~CFX_BreakLine();
 
-  int32_t CountChars() const;
   CFX_Char* GetChar(int32_t index);
-  const CFX_Char* GetChar(int32_t index) const;
-
-  int32_t CountPieces() const;
-  const CFX_BreakPiece* GetPiece(int32_t index) const;
-
   int32_t GetLineEnd() const;
 
   void Clear();
 
+  void IncrementArabicCharCount();
+  void DecrementArabicCharCount();
+  bool HasArabicChar() const { return m_iArabicChars > 0; }
+
   std::vector<CFX_Char> m_LineChars;
   std::vector<CFX_BreakPiece> m_LinePieces;
-  int32_t m_iStart;
-  int32_t m_iWidth;
-  int32_t m_iArabicChars;
+  int32_t m_iStart = 0;
+  int32_t m_iWidth = 0;
+
+ private:
+  int32_t m_iArabicChars = 0;
 };
 
 #endif  // XFA_FGAS_LAYOUT_CFX_BREAKLINE_H_
diff --git a/xfa/fgas/layout/cfx_breakpiece.cpp b/xfa/fgas/layout/cfx_breakpiece.cpp
index 364c117..b0cc754 100644
--- a/xfa/fgas/layout/cfx_breakpiece.cpp
+++ b/xfa/fgas/layout/cfx_breakpiece.cpp
@@ -6,6 +6,8 @@
 
 #include "xfa/fgas/layout/cfx_breakpiece.h"
 
+#include "xfa/fgas/layout/cfx_textuserdata.h"
+
 CFX_BreakPiece::CFX_BreakPiece()
     : m_dwStatus(CFX_BreakType::Piece),
       m_iStartPos(0),
@@ -30,7 +32,9 @@
 }
 
 CFX_Char* CFX_BreakPiece::GetChar(int32_t index) const {
-  ASSERT(index >= 0 && index < m_iChars && m_pChars);
+  ASSERT(index >= 0);
+  ASSERT(index < m_iChars);
+  ASSERT(m_pChars);
   return &(*m_pChars)[m_iStartChar + index];
 }
 
diff --git a/xfa/fgas/layout/cfx_breakpiece.h b/xfa/fgas/layout/cfx_breakpiece.h
index 5dbc0e7..8ea7032 100644
--- a/xfa/fgas/layout/cfx_breakpiece.h
+++ b/xfa/fgas/layout/cfx_breakpiece.h
@@ -9,11 +9,12 @@
 
 #include <vector>
 
-#include "core/fxcrt/cfx_char.h"
 #include "core/fxcrt/fx_string.h"
 #include "core/fxcrt/retain_ptr.h"
 #include "core/fxcrt/unowned_ptr.h"
-#include "xfa/fxfa/cxfa_textuserdata.h"
+#include "xfa/fgas/layout/cfx_char.h"
+
+class CFX_TextUserData;
 
 class CFX_BreakPiece {
  public:
@@ -41,7 +42,7 @@
   uint32_t m_dwIdentity;
   uint32_t m_dwCharStyles;
   UnownedPtr<std::vector<CFX_Char>> m_pChars;
-  RetainPtr<CXFA_TextUserData> m_pUserData;
+  RetainPtr<CFX_TextUserData> m_pUserData;
 };
 
 #endif  // XFA_FGAS_LAYOUT_CFX_BREAKPIECE_H_
diff --git a/xfa/fgas/layout/cfx_char.cpp b/xfa/fgas/layout/cfx_char.cpp
new file mode 100644
index 0000000..311aff4
--- /dev/null
+++ b/xfa/fgas/layout/cfx_char.cpp
@@ -0,0 +1,565 @@
+// 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
+
+#include "xfa/fgas/layout/cfx_char.h"
+
+#include <algorithm>
+
+#include "core/fxcrt/fx_extension.h"
+
+namespace {
+
+#ifndef NDEBUG
+constexpr int32_t kBidiMaxLevel = 61;
+#endif  // NDEBUG
+
+#undef PACK_NIBBLES
+#define PACK_NIBBLES(hi, lo) \
+  ((static_cast<uint32_t>(hi) << 4) + static_cast<uint32_t>(lo))
+
+enum FX_BIDIWEAKSTATE : uint8_t {
+  FX_BWSxa = 0,
+  FX_BWSxr,
+  FX_BWSxl,
+  FX_BWSao,
+  FX_BWSro,
+  FX_BWSlo,
+  FX_BWSrt,
+  FX_BWSlt,
+  FX_BWScn,
+  FX_BWSra,
+  FX_BWSre,
+  FX_BWSla,
+  FX_BWSle,
+  FX_BWSac,
+  FX_BWSrc,
+  FX_BWSrs,
+  FX_BWSlc,
+  FX_BWSls,
+  FX_BWSret,
+  FX_BWSlet
+};
+
+// NOTE: Range of FX_BIDICLASS prevents encoding all possible values in this
+// manner, but the ones used manage to fit. Except that I suspect that 0xF
+// was intended to be used as a sentinel, even though it also means kRLE.
+// TODO(tsepez): pick a better representation.
+enum FX_BIDIWEAKACTION : uint16_t {
+  FX_BWAIX = 0x100,
+  FX_BWAXX = 0x0F,
+  FX_BWAxxx = 0xFF,
+  FX_BWAxIx = 0x100 + FX_BWAxxx,
+  FX_BWAxxN = PACK_NIBBLES(0x0F, FX_BIDICLASS::kON),
+  FX_BWAxxE = PACK_NIBBLES(0x0F, FX_BIDICLASS::kEN),
+  FX_BWAxxA = PACK_NIBBLES(0x0F, FX_BIDICLASS::kAN),
+  FX_BWAxxR = PACK_NIBBLES(0x0F, FX_BIDICLASS::kR),
+  FX_BWAxxL = PACK_NIBBLES(0x0F, FX_BIDICLASS::kL),
+  FX_BWANxx = PACK_NIBBLES(FX_BIDICLASS::kON, 0x0F),
+  FX_BWAAxx = PACK_NIBBLES(FX_BIDICLASS::kAN, 0x0F),
+  FX_BWAExE = PACK_NIBBLES(FX_BIDICLASS::kEN, FX_BIDICLASS::kEN),
+  FX_BWANIx = 0x100 + PACK_NIBBLES(FX_BIDICLASS::kON, 0x0F),
+  FX_BWANxN = PACK_NIBBLES(FX_BIDICLASS::kON, FX_BIDICLASS::kON),
+  FX_BWANxR = PACK_NIBBLES(FX_BIDICLASS::kON, FX_BIDICLASS::kR),
+  FX_BWANxE = PACK_NIBBLES(FX_BIDICLASS::kON, FX_BIDICLASS::kEN),
+  FX_BWAAxA = PACK_NIBBLES(FX_BIDICLASS::kAN, FX_BIDICLASS::kAN),
+  FX_BWANxL = PACK_NIBBLES(FX_BIDICLASS::kON, FX_BIDICLASS::kL),
+  FX_BWALxL = PACK_NIBBLES(FX_BIDICLASS::kL, FX_BIDICLASS::kL),
+  FX_BWAxIL = 0x100 + PACK_NIBBLES(0x0F, FX_BIDICLASS::kL),
+  FX_BWAAxR = PACK_NIBBLES(FX_BIDICLASS::kAN, FX_BIDICLASS::kR),
+  FX_BWALxx = PACK_NIBBLES(FX_BIDICLASS::kL, 0x0F),
+};
+
+enum FX_BIDINEUTRALSTATE : uint8_t {
+  FX_BNSr = 0,
+  FX_BNSl,
+  FX_BNSrn,
+  FX_BNSln,
+  FX_BNSa,
+  FX_BNSna
+};
+
+enum FX_BIDINEUTRALACTION : uint16_t {
+  // For placeholders in table.
+  FX_BNAZero = 0,
+
+  // Other values.
+  FX_BNAnL = PACK_NIBBLES(0, FX_BIDICLASS::kL),
+  FX_BNAEn = PACK_NIBBLES(FX_BIDICLASS::kAN, 0),
+  FX_BNARn = PACK_NIBBLES(FX_BIDICLASS::kR, 0),
+  FX_BNALn = PACK_NIBBLES(FX_BIDICLASS::kL, 0),
+  FX_BNAIn = FX_BWAIX,
+  FX_BNALnL = PACK_NIBBLES(FX_BIDICLASS::kL, FX_BIDICLASS::kL),
+};
+#undef PACK_NIBBLES
+
+const FX_BIDICLASS kNTypes[] = {
+    FX_BIDICLASS::kN,   FX_BIDICLASS::kL,   FX_BIDICLASS::kR,
+    FX_BIDICLASS::kAN,  FX_BIDICLASS::kEN,  FX_BIDICLASS::kAL,
+    FX_BIDICLASS::kNSM, FX_BIDICLASS::kCS,  FX_BIDICLASS::kES,
+    FX_BIDICLASS::kET,  FX_BIDICLASS::kBN,  FX_BIDICLASS::kBN,
+    FX_BIDICLASS::kN,   FX_BIDICLASS::kB,   FX_BIDICLASS::kRLO,
+    FX_BIDICLASS::kRLE, FX_BIDICLASS::kLRO, FX_BIDICLASS::kLRE,
+    FX_BIDICLASS::kPDF, FX_BIDICLASS::kON,
+};
+
+const FX_BIDIWEAKSTATE kWeakStates[20][10] = {
+    {FX_BWSao, FX_BWSxl, FX_BWSxr, FX_BWScn, FX_BWScn, FX_BWSxa, FX_BWSxa,
+     FX_BWSao, FX_BWSao, FX_BWSao},
+    {FX_BWSro, FX_BWSxl, FX_BWSxr, FX_BWSra, FX_BWSre, FX_BWSxa, FX_BWSxr,
+     FX_BWSro, FX_BWSro, FX_BWSrt},
+    {FX_BWSlo, FX_BWSxl, FX_BWSxr, FX_BWSla, FX_BWSle, FX_BWSxa, FX_BWSxl,
+     FX_BWSlo, FX_BWSlo, FX_BWSlt},
+    {FX_BWSao, FX_BWSxl, FX_BWSxr, FX_BWScn, FX_BWScn, FX_BWSxa, FX_BWSao,
+     FX_BWSao, FX_BWSao, FX_BWSao},
+    {FX_BWSro, FX_BWSxl, FX_BWSxr, FX_BWSra, FX_BWSre, FX_BWSxa, FX_BWSro,
+     FX_BWSro, FX_BWSro, FX_BWSrt},
+    {FX_BWSlo, FX_BWSxl, FX_BWSxr, FX_BWSla, FX_BWSle, FX_BWSxa, FX_BWSlo,
+     FX_BWSlo, FX_BWSlo, FX_BWSlt},
+    {FX_BWSro, FX_BWSxl, FX_BWSxr, FX_BWSra, FX_BWSre, FX_BWSxa, FX_BWSrt,
+     FX_BWSro, FX_BWSro, FX_BWSrt},
+    {FX_BWSlo, FX_BWSxl, FX_BWSxr, FX_BWSla, FX_BWSle, FX_BWSxa, FX_BWSlt,
+     FX_BWSlo, FX_BWSlo, FX_BWSlt},
+    {FX_BWSao, FX_BWSxl, FX_BWSxr, FX_BWScn, FX_BWScn, FX_BWSxa, FX_BWScn,
+     FX_BWSac, FX_BWSao, FX_BWSao},
+    {FX_BWSro, FX_BWSxl, FX_BWSxr, FX_BWSra, FX_BWSre, FX_BWSxa, FX_BWSra,
+     FX_BWSrc, FX_BWSro, FX_BWSrt},
+    {FX_BWSro, FX_BWSxl, FX_BWSxr, FX_BWSra, FX_BWSre, FX_BWSxa, FX_BWSre,
+     FX_BWSrs, FX_BWSrs, FX_BWSret},
+    {FX_BWSlo, FX_BWSxl, FX_BWSxr, FX_BWSla, FX_BWSle, FX_BWSxa, FX_BWSla,
+     FX_BWSlc, FX_BWSlo, FX_BWSlt},
+    {FX_BWSlo, FX_BWSxl, FX_BWSxr, FX_BWSla, FX_BWSle, FX_BWSxa, FX_BWSle,
+     FX_BWSls, FX_BWSls, FX_BWSlet},
+    {FX_BWSao, FX_BWSxl, FX_BWSxr, FX_BWScn, FX_BWScn, FX_BWSxa, FX_BWSao,
+     FX_BWSao, FX_BWSao, FX_BWSao},
+    {FX_BWSro, FX_BWSxl, FX_BWSxr, FX_BWSra, FX_BWSre, FX_BWSxa, FX_BWSro,
+     FX_BWSro, FX_BWSro, FX_BWSrt},
+    {FX_BWSro, FX_BWSxl, FX_BWSxr, FX_BWSra, FX_BWSre, FX_BWSxa, FX_BWSro,
+     FX_BWSro, FX_BWSro, FX_BWSrt},
+    {FX_BWSlo, FX_BWSxl, FX_BWSxr, FX_BWSla, FX_BWSle, FX_BWSxa, FX_BWSlo,
+     FX_BWSlo, FX_BWSlo, FX_BWSlt},
+    {FX_BWSlo, FX_BWSxl, FX_BWSxr, FX_BWSla, FX_BWSle, FX_BWSxa, FX_BWSlo,
+     FX_BWSlo, FX_BWSlo, FX_BWSlt},
+    {FX_BWSro, FX_BWSxl, FX_BWSxr, FX_BWSra, FX_BWSre, FX_BWSxa, FX_BWSret,
+     FX_BWSro, FX_BWSro, FX_BWSret},
+    {FX_BWSlo, FX_BWSxl, FX_BWSxr, FX_BWSla, FX_BWSle, FX_BWSxa, FX_BWSlet,
+     FX_BWSlo, FX_BWSlo, FX_BWSlet},
+};
+
+const FX_BIDIWEAKACTION kWeakActions[20][10] = {
+    {FX_BWAxxx, FX_BWAxxx, FX_BWAxxx, FX_BWAxxx, FX_BWAxxA, FX_BWAxxR,
+     FX_BWAxxR, FX_BWAxxN, FX_BWAxxN, FX_BWAxxN},
+    {FX_BWAxxx, FX_BWAxxx, FX_BWAxxx, FX_BWAxxx, FX_BWAxxE, FX_BWAxxR,
+     FX_BWAxxR, FX_BWAxxN, FX_BWAxxN, FX_BWAxIx},
+    {FX_BWAxxx, FX_BWAxxx, FX_BWAxxx, FX_BWAxxx, FX_BWAxxL, FX_BWAxxR,
+     FX_BWAxxL, FX_BWAxxN, FX_BWAxxN, FX_BWAxIx},
+    {FX_BWAxxx, FX_BWAxxx, FX_BWAxxx, FX_BWAxxx, FX_BWAxxA, FX_BWAxxR,
+     FX_BWAxxN, FX_BWAxxN, FX_BWAxxN, FX_BWAxxN},
+    {FX_BWAxxx, FX_BWAxxx, FX_BWAxxx, FX_BWAxxx, FX_BWAxxE, FX_BWAxxR,
+     FX_BWAxxN, FX_BWAxxN, FX_BWAxxN, FX_BWAxIx},
+    {FX_BWAxxx, FX_BWAxxx, FX_BWAxxx, FX_BWAxxx, FX_BWAxxL, FX_BWAxxR,
+     FX_BWAxxN, FX_BWAxxN, FX_BWAxxN, FX_BWAxIx},
+    {FX_BWANxx, FX_BWANxx, FX_BWANxx, FX_BWANxx, FX_BWAExE, FX_BWANxR,
+     FX_BWAxIx, FX_BWANxN, FX_BWANxN, FX_BWAxIx},
+    {FX_BWANxx, FX_BWANxx, FX_BWANxx, FX_BWANxx, FX_BWALxL, FX_BWANxR,
+     FX_BWAxIx, FX_BWANxN, FX_BWANxN, FX_BWAxIx},
+    {FX_BWAxxx, FX_BWAxxx, FX_BWAxxx, FX_BWAxxx, FX_BWAxxA, FX_BWAxxR,
+     FX_BWAxxA, FX_BWAxIx, FX_BWAxxN, FX_BWAxxN},
+    {FX_BWAxxx, FX_BWAxxx, FX_BWAxxx, FX_BWAxxx, FX_BWAxxE, FX_BWAxxR,
+     FX_BWAxxA, FX_BWAxIx, FX_BWAxxN, FX_BWAxIx},
+    {FX_BWAxxx, FX_BWAxxx, FX_BWAxxx, FX_BWAxxx, FX_BWAxxE, FX_BWAxxR,
+     FX_BWAxxE, FX_BWAxIx, FX_BWAxIx, FX_BWAxxE},
+    {FX_BWAxxx, FX_BWAxxx, FX_BWAxxx, FX_BWAxxx, FX_BWAxxL, FX_BWAxxR,
+     FX_BWAxxA, FX_BWAxIx, FX_BWAxxN, FX_BWAxIx},
+    {FX_BWAxxx, FX_BWAxxx, FX_BWAxxx, FX_BWAxxx, FX_BWAxxL, FX_BWAxxR,
+     FX_BWAxxL, FX_BWAxIx, FX_BWAxIx, FX_BWAxxL},
+    {FX_BWANxx, FX_BWANxx, FX_BWANxx, FX_BWAAxx, FX_BWAAxA, FX_BWANxR,
+     FX_BWANxN, FX_BWANxN, FX_BWANxN, FX_BWANxN},
+    {FX_BWANxx, FX_BWANxx, FX_BWANxx, FX_BWAAxx, FX_BWANxE, FX_BWANxR,
+     FX_BWANxN, FX_BWANxN, FX_BWANxN, FX_BWANIx},
+    {FX_BWANxx, FX_BWANxx, FX_BWANxx, FX_BWANxx, FX_BWAExE, FX_BWANxR,
+     FX_BWANxN, FX_BWANxN, FX_BWANxN, FX_BWANIx},
+    {FX_BWANxx, FX_BWANxx, FX_BWANxx, FX_BWAAxx, FX_BWANxL, FX_BWANxR,
+     FX_BWANxN, FX_BWANxN, FX_BWANxN, FX_BWANIx},
+    {FX_BWANxx, FX_BWANxx, FX_BWANxx, FX_BWANxx, FX_BWALxL, FX_BWANxR,
+     FX_BWANxN, FX_BWANxN, FX_BWANxN, FX_BWANIx},
+    {FX_BWAxxx, FX_BWAxxx, FX_BWAxxx, FX_BWAxxx, FX_BWAxxE, FX_BWAxxR,
+     FX_BWAxxE, FX_BWAxxN, FX_BWAxxN, FX_BWAxxE},
+    {FX_BWAxxx, FX_BWAxxx, FX_BWAxxx, FX_BWAxxx, FX_BWAxxL, FX_BWAxxR,
+     FX_BWAxxL, FX_BWAxxN, FX_BWAxxN, FX_BWAxxL},
+};
+
+const FX_BIDINEUTRALSTATE kNeutralStates[6][5] = {
+    {FX_BNSrn, FX_BNSl, FX_BNSr, FX_BNSr, FX_BNSr},
+    {FX_BNSln, FX_BNSl, FX_BNSr, FX_BNSa, FX_BNSl},
+    {FX_BNSrn, FX_BNSl, FX_BNSr, FX_BNSr, FX_BNSr},
+    {FX_BNSln, FX_BNSl, FX_BNSr, FX_BNSa, FX_BNSl},
+    {FX_BNSna, FX_BNSl, FX_BNSr, FX_BNSa, FX_BNSl},
+    {FX_BNSna, FX_BNSl, FX_BNSr, FX_BNSa, FX_BNSl},
+};
+
+const FX_BIDINEUTRALACTION kNeutralActions[6][5] = {
+    {FX_BNAIn, FX_BNAZero, FX_BNAZero, FX_BNAZero, FX_BNAZero},
+    {FX_BNAIn, FX_BNAZero, FX_BNAZero, FX_BNAZero, FX_BNAnL},
+    {FX_BNAIn, FX_BNAEn, FX_BNARn, FX_BNARn, FX_BNARn},
+    {FX_BNAIn, FX_BNALn, FX_BNAEn, FX_BNAEn, FX_BNALnL},
+    {FX_BNAIn, FX_BNAZero, FX_BNAZero, FX_BNAZero, FX_BNAnL},
+    {FX_BNAIn, FX_BNAEn, FX_BNARn, FX_BNARn, FX_BNAEn},
+};
+
+const uint8_t kAddLevel[2][4] = {
+    {0, 1, 2, 2},
+    {1, 0, 1, 1},
+};
+
+FX_BIDICLASS Direction(int32_t val) {
+  return FX_IsOdd(val) ? FX_BIDICLASS::kR : FX_BIDICLASS::kL;
+}
+
+FX_BIDICLASS GetDeferredType(int32_t val) {
+  return static_cast<FX_BIDICLASS>((val >> 4) & 0x0F);
+}
+
+FX_BIDICLASS GetResolvedType(int32_t val) {
+  return static_cast<FX_BIDICLASS>(val & 0x0F);
+}
+
+FX_BIDICLASS GetDeferredNeutrals(int32_t iAction, int32_t iLevel) {
+  FX_BIDICLASS eClass = GetDeferredType(iAction);
+  return eClass == FX_BIDICLASS::kAN ? Direction(iLevel) : eClass;
+}
+
+FX_BIDICLASS GetResolvedNeutrals(int32_t iAction) {
+  return GetResolvedType(iAction);
+}
+
+FX_BIDIWEAKSTATE GetWeakState(FX_BIDIWEAKSTATE eState, FX_BIDICLASS eClass) {
+  ASSERT(static_cast<size_t>(eState) < FX_ArraySize(kWeakStates));
+  ASSERT(static_cast<size_t>(eClass) < FX_ArraySize(kWeakStates[0]));
+  return kWeakStates[static_cast<size_t>(eState)][static_cast<size_t>(eClass)];
+}
+
+FX_BIDIWEAKACTION GetWeakAction(FX_BIDIWEAKSTATE eState, FX_BIDICLASS eClass) {
+  ASSERT(static_cast<size_t>(eState) < FX_ArraySize(kWeakActions));
+  ASSERT(static_cast<size_t>(eClass) < FX_ArraySize(kWeakActions[0]));
+  return kWeakActions[static_cast<size_t>(eState)][static_cast<size_t>(eClass)];
+}
+
+FX_BIDINEUTRALSTATE GetNeutralState(FX_BIDINEUTRALSTATE eState,
+                                    FX_BIDICLASS eClass) {
+  ASSERT(static_cast<size_t>(eState) < FX_ArraySize(kNeutralStates));
+  ASSERT(static_cast<size_t>(eClass) < FX_ArraySize(kNeutralStates[0]));
+  return kNeutralStates[static_cast<size_t>(eState)]
+                       [static_cast<size_t>(eClass)];
+}
+
+FX_BIDINEUTRALACTION GetNeutralAction(FX_BIDINEUTRALSTATE eState,
+                                      FX_BIDICLASS eClass) {
+  ASSERT(static_cast<size_t>(eState) < FX_ArraySize(kNeutralActions));
+  ASSERT(static_cast<size_t>(eClass) < FX_ArraySize(kNeutralActions[0]));
+  return kNeutralActions[static_cast<size_t>(eState)]
+                        [static_cast<size_t>(eClass)];
+}
+
+void ReverseString(std::vector<CFX_Char>* chars, size_t iStart, size_t iCount) {
+  ASSERT(pdfium::IndexInBounds(*chars, iStart));
+  ASSERT(iStart + iCount <= chars->size());
+
+  std::reverse(chars->begin() + iStart, chars->begin() + iStart + iCount);
+}
+
+void SetDeferredRunClass(std::vector<CFX_Char>* chars,
+                         size_t iStart,
+                         size_t iCount,
+                         FX_BIDICLASS eValue) {
+  ASSERT(iStart <= chars->size());
+  ASSERT(iStart >= iCount);
+
+  size_t iLast = iStart - iCount;
+  for (size_t i = iStart; i > iLast; --i)
+    (*chars)[i - 1].m_iBidiClass = eValue;
+}
+
+void SetDeferredRunLevel(std::vector<CFX_Char>* chars,
+                         size_t iStart,
+                         size_t iCount,
+                         int32_t iValue) {
+  ASSERT(iStart <= chars->size());
+  ASSERT(iStart >= iCount);
+
+  size_t iLast = iStart - iCount;
+  for (size_t i = iStart; i > iLast; --i)
+    (*chars)[i - 1].m_iBidiLevel = static_cast<int16_t>(iValue);
+}
+
+void Classify(std::vector<CFX_Char>* chars, size_t iCount) {
+  for (size_t i = 0; i < iCount; ++i) {
+    CFX_Char& cur = (*chars)[i];
+    cur.m_iBidiClass = FX_GetBidiClass(cur.char_code());
+  }
+}
+
+void ClassifyWithTransform(std::vector<CFX_Char>* chars, size_t iCount) {
+  for (size_t i = 0; i < iCount; ++i) {
+    CFX_Char& cur = (*chars)[i];
+    cur.m_iBidiClass =
+        kNTypes[static_cast<size_t>(FX_GetBidiClass(cur.char_code()))];
+  }
+}
+
+void ResolveExplicit(std::vector<CFX_Char>* chars, size_t iCount) {
+  for (size_t i = 0; i < iCount; ++i)
+    (*chars)[i].m_iBidiLevel = 0;
+}
+
+void ResolveWeak(std::vector<CFX_Char>* chars, size_t iCount) {
+  if (iCount <= 1)
+    return;
+  --iCount;
+
+  int32_t iLevelCur = 0;
+  size_t iNum = 0;
+  FX_BIDIWEAKSTATE eState = FX_BWSxl;
+  FX_BIDICLASS eClsCur;
+  FX_BIDICLASS eClsRun;
+  FX_BIDICLASS eClsNew;
+  size_t i = 0;
+  for (; i <= iCount; ++i) {
+    CFX_Char* pTC = &(*chars)[i];
+    eClsCur = pTC->m_iBidiClass;
+    if (eClsCur == FX_BIDICLASS::kBN) {
+      pTC->m_iBidiLevel = (int16_t)iLevelCur;
+      if (i == iCount && iLevelCur != 0) {
+        eClsCur = Direction(iLevelCur);
+        pTC->m_iBidiClass = eClsCur;
+      } else if (i < iCount) {
+        CFX_Char* pTCNext = &(*chars)[i + 1];
+        int32_t iLevelNext, iLevelNew;
+        eClsNew = pTCNext->m_iBidiClass;
+        iLevelNext = pTCNext->m_iBidiLevel;
+        if (eClsNew != FX_BIDICLASS::kBN && iLevelCur != iLevelNext) {
+          iLevelNew = std::max(iLevelNext, iLevelCur);
+          pTC->m_iBidiLevel = static_cast<int16_t>(iLevelNew);
+          eClsCur = Direction(iLevelNew);
+          pTC->m_iBidiClass = eClsCur;
+          iLevelCur = iLevelNext;
+        } else {
+          if (iNum > 0)
+            ++iNum;
+          continue;
+        }
+      } else {
+        if (iNum > 0)
+          ++iNum;
+        continue;
+      }
+    }
+    if (eClsCur > FX_BIDICLASS::kBN)
+      continue;
+
+    FX_BIDIWEAKACTION eAction = GetWeakAction(eState, eClsCur);
+    eClsRun = GetDeferredType(eAction);
+    if (eClsRun != static_cast<FX_BIDICLASS>(0xF) && iNum > 0) {
+      SetDeferredRunClass(chars, i, iNum, eClsRun);
+      iNum = 0;
+    }
+    eClsNew = GetResolvedType(eAction);
+    if (eClsNew != static_cast<FX_BIDICLASS>(0xF))
+      pTC->m_iBidiClass = eClsNew;
+    if (FX_BWAIX & eAction)
+      ++iNum;
+
+    eState = GetWeakState(eState, eClsCur);
+  }
+  if (iNum == 0)
+    return;
+
+  eClsCur = Direction(0);
+  eClsRun = GetDeferredType(GetWeakAction(eState, eClsCur));
+  if (eClsRun != static_cast<FX_BIDICLASS>(0xF))
+    SetDeferredRunClass(chars, i, iNum, eClsRun);
+}
+
+void ResolveNeutrals(std::vector<CFX_Char>* chars, size_t iCount) {
+  if (iCount <= 1)
+    return;
+  --iCount;
+
+  CFX_Char* pTC;
+  int32_t iLevel = 0;
+  size_t i = 0;
+  size_t iNum = 0;
+  FX_BIDINEUTRALSTATE eState = FX_BNSl;
+  FX_BIDICLASS eClsCur;
+  FX_BIDICLASS eClsRun;
+  FX_BIDICLASS eClsNew;
+  for (; i <= iCount; ++i) {
+    pTC = &(*chars)[i];
+    eClsCur = pTC->m_iBidiClass;
+    if (eClsCur == FX_BIDICLASS::kBN) {
+      if (iNum)
+        ++iNum;
+      continue;
+    }
+    if (eClsCur >= FX_BIDICLASS::kAL)
+      continue;
+
+    FX_BIDINEUTRALACTION eAction = GetNeutralAction(eState, eClsCur);
+    eClsRun = GetDeferredNeutrals(eAction, iLevel);
+    if (eClsRun != FX_BIDICLASS::kN && iNum > 0) {
+      SetDeferredRunClass(chars, i, iNum, eClsRun);
+      iNum = 0;
+    }
+
+    eClsNew = GetResolvedNeutrals(eAction);
+    if (eClsNew != FX_BIDICLASS::kN)
+      pTC->m_iBidiClass = eClsNew;
+    if (FX_BNAIn & eAction)
+      ++iNum;
+
+    eState = GetNeutralState(eState, eClsCur);
+    iLevel = pTC->m_iBidiLevel;
+  }
+  if (iNum == 0)
+    return;
+
+  eClsCur = Direction(iLevel);
+  eClsRun = GetDeferredNeutrals(GetNeutralAction(eState, eClsCur), iLevel);
+  if (eClsRun != FX_BIDICLASS::kN)
+    SetDeferredRunClass(chars, i, iNum, eClsRun);
+}
+
+void ResolveImplicit(std::vector<CFX_Char>* chars, size_t iCount) {
+  for (size_t i = 0; i < iCount; ++i) {
+    FX_BIDICLASS eCls = (*chars)[i].m_iBidiClass;
+    if (eCls == FX_BIDICLASS::kBN || eCls <= FX_BIDICLASS::kON ||
+        eCls >= FX_BIDICLASS::kAL) {
+      continue;
+    }
+    (*chars)[i].m_iBidiLevel += kAddLevel[FX_IsOdd((*chars)[i].m_iBidiLevel)]
+                                         [static_cast<size_t>(eCls) - 1];
+  }
+}
+
+void ResolveWhitespace(std::vector<CFX_Char>* chars, size_t iCount) {
+  if (iCount <= 1)
+    return;
+  iCount--;
+
+  int32_t iLevel = 0;
+  size_t i = 0;
+  size_t iNum = 0;
+  for (; i <= iCount; ++i) {
+    switch (static_cast<FX_BIDICLASS>((*chars)[i].m_iBidiClass)) {
+      case FX_BIDICLASS::kWS:
+        ++iNum;
+        break;
+      case FX_BIDICLASS::kRLE:
+      case FX_BIDICLASS::kLRE:
+      case FX_BIDICLASS::kLRO:
+      case FX_BIDICLASS::kRLO:
+      case FX_BIDICLASS::kPDF:
+      case FX_BIDICLASS::kBN:
+        (*chars)[i].m_iBidiLevel = static_cast<int16_t>(iLevel);
+        ++iNum;
+        break;
+      case FX_BIDICLASS::kS:
+      case FX_BIDICLASS::kB:
+        if (iNum > 0)
+          SetDeferredRunLevel(chars, i, iNum, 0);
+
+        (*chars)[i].m_iBidiLevel = 0;
+        iNum = 0;
+        break;
+      default:
+        iNum = 0;
+        break;
+    }
+    iLevel = (*chars)[i].m_iBidiLevel;
+  }
+  if (iNum > 0)
+    SetDeferredRunLevel(chars, i, iNum, 0);
+}
+
+size_t ReorderLevel(std::vector<CFX_Char>* chars,
+                    size_t iCount,
+                    int32_t iBaseLevel,
+                    size_t iStart,
+                    bool bReverse) {
+  ASSERT(iBaseLevel >= 0);
+  ASSERT(iBaseLevel <= kBidiMaxLevel);
+  ASSERT(iStart < iCount);
+
+  if (iCount < 1)
+    return 0;
+
+  bReverse = bReverse || FX_IsOdd(iBaseLevel);
+  size_t i = iStart;
+  for (; i < iCount; ++i) {
+    int32_t iLevel = (*chars)[i].m_iBidiLevel;
+    if (iLevel == iBaseLevel)
+      continue;
+    if (iLevel < iBaseLevel)
+      break;
+
+    i += ReorderLevel(chars, iCount, iBaseLevel + 1, i, bReverse) - 1;
+  }
+
+  size_t iNum = i - iStart;
+  if (bReverse && iNum > 1)
+    ReverseString(chars, iStart, iNum);
+
+  return iNum;
+}
+
+void Reorder(std::vector<CFX_Char>* chars, size_t iCount) {
+  for (size_t i = 0; i < iCount;)
+    i += ReorderLevel(chars, iCount, 0, i, false);
+}
+
+void Position(std::vector<CFX_Char>* chars, size_t iCount) {
+  for (size_t i = 0; i < iCount; ++i) {
+    if ((*chars)[i].m_iBidiPos > iCount)
+      continue;
+
+    (*chars)[(*chars)[i].m_iBidiPos].m_iBidiOrder = i;
+  }
+}
+
+}  // namespace
+
+// static
+void CFX_Char::BidiLine(std::vector<CFX_Char>* chars, size_t iCount) {
+  ASSERT(iCount <= chars->size());
+  if (iCount < 2)
+    return;
+
+  ClassifyWithTransform(chars, iCount);
+  ResolveExplicit(chars, iCount);
+  ResolveWeak(chars, iCount);
+  ResolveNeutrals(chars, iCount);
+  ResolveImplicit(chars, iCount);
+  Classify(chars, iCount);
+  ResolveWhitespace(chars, iCount);
+  Reorder(chars, iCount);
+  Position(chars, iCount);
+}
+
+CFX_Char::CFX_Char(uint16_t wCharCode) : CFX_Char(wCharCode, 100, 100) {}
+
+CFX_Char::CFX_Char(uint16_t wCharCode,
+                   int32_t iHorizontalScale,
+                   int32_t iVerticalScale)
+    : m_wCharCode(wCharCode),
+      m_iHorizontalScale(iHorizontalScale),
+      m_iVerticalScale(iVerticalScale) {}
+
+CFX_Char::CFX_Char(const CFX_Char& other) = default;
+
+CFX_Char::~CFX_Char() = default;
+
+FX_CHARTYPE CFX_Char::GetCharType() const {
+  return FX_GetCharType(m_wCharCode);
+}
diff --git a/xfa/fgas/layout/cfx_char.h b/xfa/fgas/layout/cfx_char.h
new file mode 100644
index 0000000..c4bafcc
--- /dev/null
+++ b/xfa/fgas/layout/cfx_char.h
@@ -0,0 +1,56 @@
+// 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_FGAS_LAYOUT_CFX_CHAR_H_
+#define XFA_FGAS_LAYOUT_CFX_CHAR_H_
+
+#include <stdint.h>
+
+#include <vector>
+
+#include "core/fxcrt/fx_unicode.h"
+#include "core/fxcrt/retain_ptr.h"
+#include "xfa/fgas/layout/cfx_textuserdata.h"
+#include "xfa/fgas/layout/fx_linebreak.h"
+
+enum class CFX_BreakType : uint8_t { None = 0, Piece, Line, Paragraph, Page };
+
+class CFX_Char {
+ public:
+  static void BidiLine(std::vector<CFX_Char>* chars, size_t iCount);
+
+  explicit CFX_Char(uint16_t wCharCode);
+  CFX_Char(uint16_t wCharCode,
+           int32_t iHorizontalScale,
+           int32_t iVerticalScale);
+  CFX_Char(const CFX_Char& other);
+  ~CFX_Char();
+
+  FX_CHARTYPE GetCharType() const;
+
+  uint16_t char_code() const { return m_wCharCode; }
+  int16_t horizonal_scale() const { return m_iHorizontalScale; }
+  int16_t vertical_scale() const { return m_iVerticalScale; }
+
+  CFX_BreakType m_dwStatus = CFX_BreakType::None;
+  FX_BIDICLASS m_iBidiClass = FX_BIDICLASS::kON;
+  FX_LINEBREAKTYPE m_eLineBreakType = FX_LINEBREAKTYPE::kUNKNOWN;
+  uint32_t m_dwCharStyles = 0;
+  int32_t m_iCharWidth = 0;
+  uint16_t m_iBidiLevel = 0;
+  uint16_t m_iBidiPos = 0;
+  uint16_t m_iBidiOrder = 0;
+  int32_t m_iFontSize = 0;
+  uint32_t m_dwIdentity = 0;
+  RetainPtr<CFX_TextUserData> m_pUserData;
+
+ private:
+  uint16_t m_wCharCode;
+  int32_t m_iHorizontalScale;
+  int32_t m_iVerticalScale;
+};
+
+#endif  // XFA_FGAS_LAYOUT_CFX_CHAR_H_
diff --git a/xfa/fgas/layout/cfx_linebreak.cpp b/xfa/fgas/layout/cfx_linebreak.cpp
deleted file mode 100644
index 1435248..0000000
--- a/xfa/fgas/layout/cfx_linebreak.cpp
+++ /dev/null
@@ -1,268 +0,0 @@
-// Copyright 2014 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
-
-#include "xfa/fgas/layout/cfx_linebreak.h"
-
-#include "core/fxcrt/fx_unicode.h"
-
-const FX_LINEBREAKTYPE gs_FX_LineBreak_PairTable[64][32] = {
-    {FX_LBPB, FX_LBPB, FX_LBPB, FX_LBPB, FX_LBPB, FX_LBPB, FX_LBPB, FX_LBPB,
-     FX_LBPB, FX_LBPB, FX_LBPB, FX_LBPB, FX_LBPB, FX_LBPB, FX_LBPB, FX_LBPB,
-     FX_LBPB, FX_LBPB, FX_LBPB, FX_LBCP, FX_LBPB, FX_LBPB, FX_LBPB, FX_LBPB,
-     FX_LBPB, FX_LBPB, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN},
-    {FX_LBDB, FX_LBPB, FX_LBIB, FX_LBIB, FX_LBPB, FX_LBPB, FX_LBPB, FX_LBPB,
-     FX_LBIB, FX_LBIB, FX_LBDB, FX_LBDB, FX_LBDB, FX_LBDB, FX_LBIB, FX_LBIB,
-     FX_LBDB, FX_LBDB, FX_LBPB, FX_LBCB, FX_LBPB, FX_LBDB, FX_LBDB, FX_LBDB,
-     FX_LBDB, FX_LBDB, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN},
-    {FX_LBPB, FX_LBPB, FX_LBIB, FX_LBIB, FX_LBIB, FX_LBPB, FX_LBPB, FX_LBPB,
-     FX_LBIB, FX_LBIB, FX_LBIB, FX_LBIB, FX_LBIB, FX_LBIB, FX_LBIB, FX_LBIB,
-     FX_LBIB, FX_LBIB, FX_LBPB, FX_LBCB, FX_LBPB, FX_LBIB, FX_LBIB, FX_LBIB,
-     FX_LBIB, FX_LBIB, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN},
-    {FX_LBIB, FX_LBPB, FX_LBIB, FX_LBIB, FX_LBIB, FX_LBPB, FX_LBPB, FX_LBPB,
-     FX_LBIB, FX_LBIB, FX_LBIB, FX_LBIB, FX_LBIB, FX_LBIB, FX_LBIB, FX_LBIB,
-     FX_LBIB, FX_LBIB, FX_LBPB, FX_LBCB, FX_LBPB, FX_LBIB, FX_LBIB, FX_LBIB,
-     FX_LBIB, FX_LBIB, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN},
-    {FX_LBDB, FX_LBPB, FX_LBIB, FX_LBIB, FX_LBIB, FX_LBPB, FX_LBPB, FX_LBPB,
-     FX_LBDB, FX_LBDB, FX_LBDB, FX_LBDB, FX_LBDB, FX_LBDB, FX_LBIB, FX_LBIB,
-     FX_LBDB, FX_LBDB, FX_LBPB, FX_LBCB, FX_LBPB, FX_LBDB, FX_LBDB, FX_LBDB,
-     FX_LBDB, FX_LBDB, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN},
-    {FX_LBDB, FX_LBPB, FX_LBIB, FX_LBIB, FX_LBIB, FX_LBPB, FX_LBPB, FX_LBPB,
-     FX_LBDB, FX_LBDB, FX_LBDB, FX_LBDB, FX_LBDB, FX_LBDB, FX_LBIB, FX_LBIB,
-     FX_LBDB, FX_LBDB, FX_LBPB, FX_LBCB, FX_LBPB, FX_LBDB, FX_LBDB, FX_LBDB,
-     FX_LBDB, FX_LBDB, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN},
-    {FX_LBDB, FX_LBPB, FX_LBIB, FX_LBIB, FX_LBIB, FX_LBPB, FX_LBPB, FX_LBPB,
-     FX_LBDB, FX_LBDB, FX_LBIB, FX_LBDB, FX_LBDB, FX_LBDB, FX_LBIB, FX_LBIB,
-     FX_LBDB, FX_LBDB, FX_LBPB, FX_LBCB, FX_LBPB, FX_LBDB, FX_LBDB, FX_LBDB,
-     FX_LBDB, FX_LBDB, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN},
-    {FX_LBDB, FX_LBPB, FX_LBIB, FX_LBIB, FX_LBIB, FX_LBPB, FX_LBPB, FX_LBPB,
-     FX_LBDB, FX_LBDB, FX_LBIB, FX_LBIB, FX_LBDB, FX_LBDB, FX_LBIB, FX_LBIB,
-     FX_LBDB, FX_LBDB, FX_LBPB, FX_LBCB, FX_LBPB, FX_LBDB, FX_LBDB, FX_LBDB,
-     FX_LBDB, FX_LBDB, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN},
-    {FX_LBIB, FX_LBPB, FX_LBIB, FX_LBIB, FX_LBIB, FX_LBPB, FX_LBPB, FX_LBPB,
-     FX_LBDB, FX_LBDB, FX_LBIB, FX_LBIB, FX_LBIB, FX_LBDB, FX_LBIB, FX_LBIB,
-     FX_LBDB, FX_LBDB, FX_LBPB, FX_LBCB, FX_LBPB, FX_LBIB, FX_LBIB, FX_LBIB,
-     FX_LBIB, FX_LBIB, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN},
-    {FX_LBIB, FX_LBPB, FX_LBIB, FX_LBIB, FX_LBIB, FX_LBPB, FX_LBPB, FX_LBPB,
-     FX_LBDB, FX_LBDB, FX_LBIB, FX_LBIB, FX_LBDB, FX_LBDB, FX_LBIB, FX_LBIB,
-     FX_LBDB, FX_LBDB, FX_LBPB, FX_LBCB, FX_LBPB, FX_LBDB, FX_LBDB, FX_LBDB,
-     FX_LBDB, FX_LBDB, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN},
-    {FX_LBIB, FX_LBPB, FX_LBIB, FX_LBIB, FX_LBIB, FX_LBPB, FX_LBPB, FX_LBPB,
-     FX_LBIB, FX_LBIB, FX_LBIB, FX_LBIB, FX_LBDB, FX_LBIB, FX_LBIB, FX_LBIB,
-     FX_LBDB, FX_LBDB, FX_LBPB, FX_LBCB, FX_LBPB, FX_LBDB, FX_LBDB, FX_LBDB,
-     FX_LBDB, FX_LBDB, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN},
-    {FX_LBIB, FX_LBPB, FX_LBIB, FX_LBIB, FX_LBIB, FX_LBPB, FX_LBPB, FX_LBPB,
-     FX_LBDB, FX_LBDB, FX_LBIB, FX_LBIB, FX_LBDB, FX_LBIB, FX_LBIB, FX_LBIB,
-     FX_LBDB, FX_LBDB, FX_LBPB, FX_LBCB, FX_LBPB, FX_LBDB, FX_LBDB, FX_LBDB,
-     FX_LBDB, FX_LBDB, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN},
-    {FX_LBDB, FX_LBPB, FX_LBIB, FX_LBIB, FX_LBIB, FX_LBPB, FX_LBPB, FX_LBPB,
-     FX_LBDB, FX_LBIB, FX_LBDB, FX_LBDB, FX_LBDB, FX_LBIB, FX_LBIB, FX_LBIB,
-     FX_LBDB, FX_LBDB, FX_LBPB, FX_LBCB, FX_LBPB, FX_LBDB, FX_LBDB, FX_LBDB,
-     FX_LBDB, FX_LBDB, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN},
-    {FX_LBDB, FX_LBPB, FX_LBIB, FX_LBIB, FX_LBIB, FX_LBPB, FX_LBPB, FX_LBPB,
-     FX_LBDB, FX_LBDB, FX_LBDB, FX_LBDB, FX_LBDB, FX_LBIB, FX_LBIB, FX_LBIB,
-     FX_LBDB, FX_LBDB, FX_LBPB, FX_LBCB, FX_LBPB, FX_LBDB, FX_LBDB, FX_LBDB,
-     FX_LBDB, FX_LBDB, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN},
-    {FX_LBDB, FX_LBPB, FX_LBIB, FX_LBDB, FX_LBIB, FX_LBPB, FX_LBPB, FX_LBPB,
-     FX_LBDB, FX_LBDB, FX_LBIB, FX_LBDB, FX_LBDB, FX_LBDB, FX_LBIB, FX_LBIB,
-     FX_LBDB, FX_LBDB, FX_LBPB, FX_LBCB, FX_LBPB, FX_LBDB, FX_LBDB, FX_LBDB,
-     FX_LBDB, FX_LBDB, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN},
-    {FX_LBDB, FX_LBPB, FX_LBIB, FX_LBDB, FX_LBIB, FX_LBPB, FX_LBPB, FX_LBPB,
-     FX_LBDB, FX_LBDB, FX_LBDB, FX_LBDB, FX_LBDB, FX_LBDB, FX_LBIB, FX_LBIB,
-     FX_LBDB, FX_LBDB, FX_LBPB, FX_LBCB, FX_LBPB, FX_LBDB, FX_LBDB, FX_LBDB,
-     FX_LBDB, FX_LBDB, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN},
-    {FX_LBIB, FX_LBPB, FX_LBIB, FX_LBIB, FX_LBIB, FX_LBPB, FX_LBPB, FX_LBPB,
-     FX_LBIB, FX_LBIB, FX_LBIB, FX_LBIB, FX_LBIB, FX_LBIB, FX_LBIB, FX_LBIB,
-     FX_LBIB, FX_LBIB, FX_LBPB, FX_LBCB, FX_LBPB, FX_LBIB, FX_LBIB, FX_LBIB,
-     FX_LBIB, FX_LBIB, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN},
-    {FX_LBDB, FX_LBPB, FX_LBIB, FX_LBIB, FX_LBIB, FX_LBPB, FX_LBPB, FX_LBPB,
-     FX_LBDB, FX_LBDB, FX_LBDB, FX_LBDB, FX_LBDB, FX_LBDB, FX_LBIB, FX_LBIB,
-     FX_LBDB, FX_LBPB, FX_LBPB, FX_LBCB, FX_LBPB, FX_LBDB, FX_LBDB, FX_LBDB,
-     FX_LBDB, FX_LBDB, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN},
-    {FX_LBDB, FX_LBDB, FX_LBDB, FX_LBDB, FX_LBDB, FX_LBDB, FX_LBDB, FX_LBDB,
-     FX_LBDB, FX_LBDB, FX_LBDB, FX_LBDB, FX_LBDB, FX_LBDB, FX_LBDB, FX_LBDB,
-     FX_LBDB, FX_LBDB, FX_LBPB, FX_LBDB, FX_LBDB, FX_LBDB, FX_LBDB, FX_LBDB,
-     FX_LBDB, FX_LBDB, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN},
-    {FX_LBDB, FX_LBPB, FX_LBIB, FX_LBIB, FX_LBIB, FX_LBPB, FX_LBPB, FX_LBPB,
-     FX_LBDB, FX_LBDB, FX_LBIB, FX_LBIB, FX_LBDB, FX_LBIB, FX_LBIB, FX_LBIB,
-     FX_LBDB, FX_LBDB, FX_LBPB, FX_LBCB, FX_LBPB, FX_LBDB, FX_LBDB, FX_LBDB,
-     FX_LBDB, FX_LBDB, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN},
-    {FX_LBIB, FX_LBPB, FX_LBIB, FX_LBIB, FX_LBIB, FX_LBPB, FX_LBPB, FX_LBPB,
-     FX_LBIB, FX_LBIB, FX_LBIB, FX_LBIB, FX_LBIB, FX_LBIB, FX_LBIB, FX_LBIB,
-     FX_LBIB, FX_LBIB, FX_LBPB, FX_LBCB, FX_LBPB, FX_LBIB, FX_LBIB, FX_LBIB,
-     FX_LBIB, FX_LBIB, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN},
-    {FX_LBDB, FX_LBPB, FX_LBIB, FX_LBIB, FX_LBIB, FX_LBPB, FX_LBPB, FX_LBPB,
-     FX_LBDB, FX_LBIB, FX_LBDB, FX_LBDB, FX_LBDB, FX_LBIB, FX_LBIB, FX_LBIB,
-     FX_LBDB, FX_LBDB, FX_LBPB, FX_LBCB, FX_LBPB, FX_LBDB, FX_LBDB, FX_LBDB,
-     FX_LBIB, FX_LBIB, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN},
-    {FX_LBDB, FX_LBPB, FX_LBIB, FX_LBIB, FX_LBIB, FX_LBPB, FX_LBPB, FX_LBPB,
-     FX_LBDB, FX_LBIB, FX_LBDB, FX_LBDB, FX_LBDB, FX_LBIB, FX_LBIB, FX_LBIB,
-     FX_LBDB, FX_LBDB, FX_LBPB, FX_LBCB, FX_LBPB, FX_LBDB, FX_LBDB, FX_LBDB,
-     FX_LBDB, FX_LBIB, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN},
-    {FX_LBDB, FX_LBPB, FX_LBIB, FX_LBIB, FX_LBIB, FX_LBPB, FX_LBPB, FX_LBPB,
-     FX_LBDB, FX_LBIB, FX_LBDB, FX_LBDB, FX_LBDB, FX_LBIB, FX_LBIB, FX_LBIB,
-     FX_LBDB, FX_LBDB, FX_LBPB, FX_LBCB, FX_LBPB, FX_LBIB, FX_LBIB, FX_LBIB,
-     FX_LBIB, FX_LBDB, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN},
-    {FX_LBDB, FX_LBPB, FX_LBIB, FX_LBIB, FX_LBIB, FX_LBPB, FX_LBPB, FX_LBPB,
-     FX_LBDB, FX_LBIB, FX_LBDB, FX_LBDB, FX_LBDB, FX_LBIB, FX_LBIB, FX_LBIB,
-     FX_LBDB, FX_LBDB, FX_LBPB, FX_LBCB, FX_LBPB, FX_LBDB, FX_LBDB, FX_LBDB,
-     FX_LBIB, FX_LBIB, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN},
-    {FX_LBDB, FX_LBPB, FX_LBIB, FX_LBIB, FX_LBIB, FX_LBPB, FX_LBPB, FX_LBPB,
-     FX_LBDB, FX_LBIB, FX_LBDB, FX_LBDB, FX_LBDB, FX_LBIB, FX_LBIB, FX_LBIB,
-     FX_LBDB, FX_LBDB, FX_LBPB, FX_LBCB, FX_LBPB, FX_LBDB, FX_LBDB, FX_LBDB,
-     FX_LBDB, FX_LBIB, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN},
-    {FX_LBDB, FX_LBPB, FX_LBIB, FX_LBIB, FX_LBIB, FX_LBPB, FX_LBPB, FX_LBPB,
-     FX_LBDB, FX_LBIB, FX_LBDB, FX_LBDB, FX_LBDB, FX_LBIB, FX_LBIB, FX_LBIB,
-     FX_LBDB, FX_LBDB, FX_LBPB, FX_LBCB, FX_LBPB, FX_LBDB, FX_LBDB, FX_LBDB,
-     FX_LBDB, FX_LBDB, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN},
-    {FX_LBDB, FX_LBPB, FX_LBIB, FX_LBIB, FX_LBIB, FX_LBPB, FX_LBPB, FX_LBPB,
-     FX_LBDB, FX_LBIB, FX_LBDB, FX_LBDB, FX_LBDB, FX_LBIB, FX_LBIB, FX_LBIB,
-     FX_LBDB, FX_LBDB, FX_LBPB, FX_LBCB, FX_LBPB, FX_LBDB, FX_LBDB, FX_LBDB,
-     FX_LBDB, FX_LBDB, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN},
-    {FX_LBDB, FX_LBPB, FX_LBIB, FX_LBIB, FX_LBIB, FX_LBPB, FX_LBPB, FX_LBPB,
-     FX_LBDB, FX_LBIB, FX_LBDB, FX_LBDB, FX_LBDB, FX_LBIB, FX_LBIB, FX_LBIB,
-     FX_LBDB, FX_LBDB, FX_LBPB, FX_LBCB, FX_LBPB, FX_LBDB, FX_LBDB, FX_LBDB,
-     FX_LBDB, FX_LBDB, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN},
-    {FX_LBDB, FX_LBPB, FX_LBIB, FX_LBIB, FX_LBIB, FX_LBPB, FX_LBPB, FX_LBPB,
-     FX_LBDB, FX_LBIB, FX_LBDB, FX_LBDB, FX_LBDB, FX_LBIB, FX_LBIB, FX_LBIB,
-     FX_LBDB, FX_LBDB, FX_LBPB, FX_LBCB, FX_LBPB, FX_LBDB, FX_LBDB, FX_LBDB,
-     FX_LBDB, FX_LBDB, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN},
-    {FX_LBDB, FX_LBPB, FX_LBIB, FX_LBIB, FX_LBIB, FX_LBPB, FX_LBPB, FX_LBPB,
-     FX_LBDB, FX_LBIB, FX_LBDB, FX_LBDB, FX_LBDB, FX_LBIB, FX_LBIB, FX_LBIB,
-     FX_LBDB, FX_LBDB, FX_LBPB, FX_LBCB, FX_LBPB, FX_LBDB, FX_LBDB, FX_LBDB,
-     FX_LBDB, FX_LBDB, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN},
-    {FX_LBDB, FX_LBPB, FX_LBIB, FX_LBIB, FX_LBIB, FX_LBPB, FX_LBPB, FX_LBPB,
-     FX_LBDB, FX_LBIB, FX_LBDB, FX_LBDB, FX_LBDB, FX_LBIB, FX_LBIB, FX_LBIB,
-     FX_LBDB, FX_LBDB, FX_LBPB, FX_LBCB, FX_LBPB, FX_LBDB, FX_LBDB, FX_LBDB,
-     FX_LBDB, FX_LBDB, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN},
-    {FX_LBDB, FX_LBPB, FX_LBIB, FX_LBIB, FX_LBIB, FX_LBPB, FX_LBPB, FX_LBPB,
-     FX_LBDB, FX_LBIB, FX_LBDB, FX_LBDB, FX_LBDB, FX_LBIB, FX_LBIB, FX_LBIB,
-     FX_LBDB, FX_LBDB, FX_LBPB, FX_LBCB, FX_LBPB, FX_LBDB, FX_LBDB, FX_LBDB,
-     FX_LBDB, FX_LBDB, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN},
-    {FX_LBDB, FX_LBPB, FX_LBIB, FX_LBIB, FX_LBIB, FX_LBPB, FX_LBPB, FX_LBPB,
-     FX_LBDB, FX_LBIB, FX_LBDB, FX_LBDB, FX_LBDB, FX_LBIB, FX_LBIB, FX_LBIB,
-     FX_LBDB, FX_LBDB, FX_LBPB, FX_LBCB, FX_LBPB, FX_LBDB, FX_LBDB, FX_LBDB,
-     FX_LBDB, FX_LBDB, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN},
-    {FX_LBDB, FX_LBPB, FX_LBIB, FX_LBIB, FX_LBIB, FX_LBPB, FX_LBPB, FX_LBPB,
-     FX_LBDB, FX_LBIB, FX_LBDB, FX_LBDB, FX_LBDB, FX_LBIB, FX_LBIB, FX_LBIB,
-     FX_LBDB, FX_LBDB, FX_LBPB, FX_LBCB, FX_LBPB, FX_LBDB, FX_LBDB, FX_LBDB,
-     FX_LBDB, FX_LBDB, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN},
-    {FX_LBDB, FX_LBPB, FX_LBDB, FX_LBPB, FX_LBPB, FX_LBPB, FX_LBDB, FX_LBPB,
-     FX_LBDB, FX_LBIB, FX_LBDB, FX_LBDB, FX_LBDB, FX_LBPB, FX_LBPB, FX_LBIB,
-     FX_LBDB, FX_LBDB, FX_LBPB, FX_LBCB, FX_LBPB, FX_LBDB, FX_LBDB, FX_LBDB,
-     FX_LBPB, FX_LBDB, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN},
-    {FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN,
-     FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN,
-     FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN,
-     FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN},
-    {FX_LBDB, FX_LBPB, FX_LBIB, FX_LBDB, FX_LBIB, FX_LBPB, FX_LBPB, FX_LBPB,
-     FX_LBDB, FX_LBDB, FX_LBDB, FX_LBDB, FX_LBDB, FX_LBDB, FX_LBIB, FX_LBIB,
-     FX_LBDB, FX_LBDB, FX_LBPB, FX_LBCB, FX_LBPB, FX_LBDB, FX_LBDB, FX_LBDB,
-     FX_LBDB, FX_LBDB, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN},
-    {FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN,
-     FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN,
-     FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN,
-     FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN},
-    {FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN,
-     FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN,
-     FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN,
-     FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN},
-    {FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN,
-     FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN,
-     FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN,
-     FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN},
-    {FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN,
-     FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN,
-     FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN,
-     FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN},
-    {FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN,
-     FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN,
-     FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN,
-     FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN},
-    {FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN,
-     FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN,
-     FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN,
-     FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN},
-    {FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN,
-     FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN,
-     FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN,
-     FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN},
-    {FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN,
-     FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN,
-     FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN,
-     FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN},
-    {FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN,
-     FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN,
-     FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN,
-     FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN},
-    {FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN,
-     FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN,
-     FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN,
-     FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN},
-    {FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN,
-     FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN,
-     FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN,
-     FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN},
-    {FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN,
-     FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN,
-     FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN,
-     FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN},
-    {FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN,
-     FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN,
-     FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN,
-     FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN},
-    {FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN,
-     FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN,
-     FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN,
-     FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN},
-    {FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN,
-     FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN,
-     FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN,
-     FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN},
-    {FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN,
-     FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN,
-     FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN,
-     FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN},
-    {FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN,
-     FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN,
-     FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN,
-     FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN},
-    {FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN,
-     FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN,
-     FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN,
-     FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN},
-    {FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN,
-     FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN,
-     FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN,
-     FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN},
-    {FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN,
-     FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN,
-     FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN,
-     FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN},
-    {FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN,
-     FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN,
-     FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN,
-     FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN},
-    {FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN,
-     FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN,
-     FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN,
-     FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN},
-    {FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN,
-     FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN,
-     FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN,
-     FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN},
-    {FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN,
-     FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN,
-     FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN,
-     FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN},
-    {FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN,
-     FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN,
-     FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN,
-     FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN},
-    {FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN,
-     FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN,
-     FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN,
-     FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN},
-};
diff --git a/xfa/fgas/layout/cfx_linebreak.h b/xfa/fgas/layout/cfx_linebreak.h
deleted file mode 100644
index 8ba022e..0000000
--- a/xfa/fgas/layout/cfx_linebreak.h
+++ /dev/null
@@ -1,32 +0,0 @@
-// Copyright 2014 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_FGAS_LAYOUT_CFX_LINEBREAK_H_
-#define XFA_FGAS_LAYOUT_CFX_LINEBREAK_H_
-
-#include "core/fxcrt/fx_system.h"
-
-enum FX_LINEBREAKTYPE : uint8_t {
-  FX_LBT_UNKNOWN = 0x00,
-  FX_LBT_DIRECT_BRK = 0x1A,
-  FX_LBT_INDIRECT_BRK = 0x2B,
-  FX_LBT_COM_INDIRECT_BRK = 0x3C,
-  FX_LBT_COM_PROHIBITED_BRK = 0x4D,
-  FX_LBT_PROHIBITED_BRK = 0x5E,
-  FX_LBT_HANGUL_SPACE_BRK = 0x6F,
-};
-
-#define FX_LBUN FX_LBT_UNKNOWN
-#define FX_LBDB FX_LBT_DIRECT_BRK
-#define FX_LBIB FX_LBT_INDIRECT_BRK
-#define FX_LBCB FX_LBT_COM_INDIRECT_BRK
-#define FX_LBCP FX_LBT_COM_PROHIBITED_BRK
-#define FX_LBPB FX_LBT_PROHIBITED_BRK
-#define FX_LBHS FX_LBT_HANGUL_SPACE_BRK
-
-extern const FX_LINEBREAKTYPE gs_FX_LineBreak_PairTable[64][32];
-
-#endif  // XFA_FGAS_LAYOUT_CFX_LINEBREAK_H_
diff --git a/xfa/fgas/layout/cfx_linkuserdata.cpp b/xfa/fgas/layout/cfx_linkuserdata.cpp
new file mode 100644
index 0000000..d452480
--- /dev/null
+++ b/xfa/fgas/layout/cfx_linkuserdata.cpp
@@ -0,0 +1,12 @@
+// 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
+
+#include "xfa/fgas/layout/cfx_linkuserdata.h"
+
+CFX_LinkUserData::CFX_LinkUserData(const WideString& wsText)
+    : m_wsURLContent(wsText) {}
+
+CFX_LinkUserData::~CFX_LinkUserData() {}
diff --git a/xfa/fxfa/cxfa_linkuserdata.h b/xfa/fgas/layout/cfx_linkuserdata.h
similarity index 67%
rename from xfa/fxfa/cxfa_linkuserdata.h
rename to xfa/fgas/layout/cfx_linkuserdata.h
index 3d0f95e..83b43a2 100644
--- a/xfa/fxfa/cxfa_linkuserdata.h
+++ b/xfa/fgas/layout/cfx_linkuserdata.h
@@ -4,14 +4,14 @@
 
 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
 
-#ifndef XFA_FXFA_CXFA_LINKUSERDATA_H_
-#define XFA_FXFA_CXFA_LINKUSERDATA_H_
+#ifndef XFA_FGAS_LAYOUT_CFX_LINKUSERDATA_H_
+#define XFA_FGAS_LAYOUT_CFX_LINKUSERDATA_H_
 
 #include "core/fxcrt/fx_string.h"
 #include "core/fxcrt/fx_system.h"
 #include "core/fxcrt/retain_ptr.h"
 
-class CXFA_LinkUserData : public Retainable {
+class CFX_LinkUserData final : public Retainable {
  public:
   template <typename T, typename... Args>
   friend RetainPtr<T> pdfium::MakeRetain(Args&&... args);
@@ -19,10 +19,10 @@
   const wchar_t* GetLinkURL() const { return m_wsURLContent.c_str(); }
 
  private:
-  explicit CXFA_LinkUserData(wchar_t* pszText);
-  ~CXFA_LinkUserData() override;
+  explicit CFX_LinkUserData(const WideString& wsText);
+  ~CFX_LinkUserData() override;
 
   WideString m_wsURLContent;
 };
 
-#endif  // XFA_FXFA_CXFA_LINKUSERDATA_H_
+#endif  // XFA_FGAS_LAYOUT_CFX_LINKUSERDATA_H_
diff --git a/xfa/fgas/layout/cfx_rtfbreak.cpp b/xfa/fgas/layout/cfx_rtfbreak.cpp
index 3ef0ef2..78d723b 100644
--- a/xfa/fgas/layout/cfx_rtfbreak.cpp
+++ b/xfa/fgas/layout/cfx_rtfbreak.cpp
@@ -8,12 +8,17 @@
 
 #include <algorithm>
 
-#include "core/fxcrt/fx_arabic.h"
-#include "core/fxcrt/fx_bidi.h"
-#include "core/fxge/cfx_renderdevice.h"
+#include "build/build_config.h"
+#include "core/fxcrt/fx_safe_types.h"
+#include "core/fxge/text_char_pos.h"
+#include "third_party/base/numerics/safe_math.h"
 #include "third_party/base/stl_util.h"
 #include "xfa/fgas/font/cfgas_gefont.h"
-#include "xfa/fgas/layout/cfx_linebreak.h"
+#include "xfa/fgas/layout/cfx_char.h"
+#include "xfa/fgas/layout/cfx_textpiece.h"
+#include "xfa/fgas/layout/cfx_textuserdata.h"
+#include "xfa/fgas/layout/fx_arabic.h"
+#include "xfa/fgas/layout/fx_linebreak.h"
 
 CFX_RTFBreak::CFX_RTFBreak(uint32_t dwLayoutStyles)
     : CFX_Break(dwLayoutStyles),
@@ -26,15 +31,15 @@
 CFX_RTFBreak::~CFX_RTFBreak() {}
 
 void CFX_RTFBreak::SetLineStartPos(float fLinePos) {
-  int32_t iLinePos = FXSYS_round(fLinePos * 20000.0f);
+  int32_t iLinePos = FXSYS_roundf(fLinePos * kConversionFactor);
   iLinePos = std::min(iLinePos, m_iLineWidth);
   iLinePos = std::max(iLinePos, m_iLineStart);
   m_pCurLine->m_iStart = iLinePos;
 }
 
 void CFX_RTFBreak::AddPositionedTab(float fTabPos) {
-  int32_t iTabPos =
-      std::min(FXSYS_round(fTabPos * 20000.0f) + m_iLineStart, m_iLineWidth);
+  int32_t iTabPos = std::min(
+      FXSYS_roundf(fTabPos * kConversionFactor) + m_iLineStart, m_iLineWidth);
   auto it = std::lower_bound(m_PositionedTabs.begin(), m_PositionedTabs.end(),
                              iTabPos);
   if (it != m_PositionedTabs.end() && *it == iTabPos)
@@ -42,7 +47,7 @@
   m_PositionedTabs.insert(it, iTabPos);
 }
 
-void CFX_RTFBreak::SetUserData(const RetainPtr<CXFA_TextUserData>& pUserData) {
+void CFX_RTFBreak::SetUserData(const RetainPtr<CFX_TextUserData>& pUserData) {
   if (m_pUserData == pUserData)
     return;
 
@@ -50,10 +55,6 @@
   m_pUserData = pUserData;
 }
 
-int32_t CFX_RTFBreak::GetLastPositionedTab() const {
-  return m_PositionedTabs.empty() ? m_iLineStart : m_PositionedTabs.back();
-}
-
 bool CFX_RTFBreak::GetPositionedTab(int32_t* iTabPos) const {
   auto it = std::upper_bound(m_PositionedTabs.begin(), m_PositionedTabs.end(),
                              *iTabPos);
@@ -65,11 +66,10 @@
 }
 
 CFX_BreakType CFX_RTFBreak::AppendChar(wchar_t wch) {
-  ASSERT(m_pFont && m_pCurLine);
+  ASSERT(m_pCurLine);
 
-  uint32_t dwProps = FX_GetUnicodeProperties(wch);
-  FX_CHARTYPE chartype = GetCharTypeFromProp(dwProps);
-  m_pCurLine->m_LineChars.emplace_back(wch, dwProps, m_iHorizontalScale,
+  FX_CHARTYPE chartype = FX_GetCharType(wch);
+  m_pCurLine->m_LineChars.emplace_back(wch, m_iHorizontalScale,
                                        m_iVerticalScale);
   CFX_Char* pCurChar = &m_pCurLine->m_LineChars.back();
   pCurChar->m_iFontSize = m_iFontSize;
@@ -77,40 +77,40 @@
   pCurChar->m_pUserData = m_pUserData;
 
   CFX_BreakType dwRet1 = CFX_BreakType::None;
-  if (chartype != FX_CHARTYPE_Combination &&
+  if (chartype != FX_CHARTYPE::kCombination &&
       GetUnifiedCharType(m_eCharType) != GetUnifiedCharType(chartype) &&
-      m_eCharType != FX_CHARTYPE_Unknown &&
-      m_pCurLine->GetLineEnd() > m_iLineWidth + m_iTolerance &&
-      (m_eCharType != FX_CHARTYPE_Space || chartype != FX_CHARTYPE_Control)) {
+      m_eCharType != FX_CHARTYPE::kUnknown &&
+      IsGreaterThanLineWidth(m_pCurLine->GetLineEnd()) &&
+      (m_eCharType != FX_CHARTYPE::kSpace ||
+       chartype != FX_CHARTYPE::kControl)) {
     dwRet1 = EndBreak(CFX_BreakType::Line);
-    int32_t iCount = m_pCurLine->CountChars();
-    if (iCount > 0)
-      pCurChar = &m_pCurLine->m_LineChars[iCount - 1];
+    if (!m_pCurLine->m_LineChars.empty())
+      pCurChar = &m_pCurLine->m_LineChars.back();
   }
 
   CFX_BreakType dwRet2 = CFX_BreakType::None;
   switch (chartype) {
-    case FX_CHARTYPE_Tab:
+    case FX_CHARTYPE::kTab:
       AppendChar_Tab(pCurChar);
       break;
-    case FX_CHARTYPE_Control:
+    case FX_CHARTYPE::kControl:
       dwRet2 = AppendChar_Control(pCurChar);
       break;
-    case FX_CHARTYPE_Combination:
+    case FX_CHARTYPE::kCombination:
       AppendChar_Combination(pCurChar);
       break;
-    case FX_CHARTYPE_ArabicAlef:
-    case FX_CHARTYPE_ArabicSpecial:
-    case FX_CHARTYPE_ArabicDistortion:
-    case FX_CHARTYPE_ArabicNormal:
-    case FX_CHARTYPE_ArabicForm:
-    case FX_CHARTYPE_Arabic:
+    case FX_CHARTYPE::kArabicAlef:
+    case FX_CHARTYPE::kArabicSpecial:
+    case FX_CHARTYPE::kArabicDistortion:
+    case FX_CHARTYPE::kArabicNormal:
+    case FX_CHARTYPE::kArabicForm:
+    case FX_CHARTYPE::kArabic:
       dwRet2 = AppendChar_Arabic(pCurChar);
       break;
-    case FX_CHARTYPE_Unknown:
-    case FX_CHARTYPE_Space:
-    case FX_CHARTYPE_Numeric:
-    case FX_CHARTYPE_Normal:
+    case FX_CHARTYPE::kUnknown:
+    case FX_CHARTYPE::kSpace:
+    case FX_CHARTYPE::kNumeric:
+    case FX_CHARTYPE::kNormal:
     default:
       dwRet2 = AppendChar_Others(pCurChar);
       break;
@@ -121,21 +121,30 @@
 }
 
 void CFX_RTFBreak::AppendChar_Combination(CFX_Char* pCurChar) {
-  int32_t iCharWidth = 0;
-  if (!m_pFont->GetCharWidth(pCurChar->char_code(), iCharWidth))
-    iCharWidth = 0;
+  FX_SAFE_INT32 iCharWidth = 0;
+  int32_t iCharWidthOut;
+  if (m_pFont && m_pFont->GetCharWidth(pCurChar->char_code(), &iCharWidthOut))
+    iCharWidth = iCharWidthOut;
 
   iCharWidth *= m_iFontSize;
-  iCharWidth = iCharWidth * m_iHorizontalScale / 100;
+  iCharWidth *= m_iHorizontalScale;
+  iCharWidth /= 100;
   CFX_Char* pLastChar = GetLastChar(0, false, true);
-  if (pLastChar && pLastChar->GetCharType() > FX_CHARTYPE_Combination)
-    iCharWidth = -iCharWidth;
+  if (pLastChar && pLastChar->GetCharType() > FX_CHARTYPE::kCombination)
+    iCharWidth *= -1;
   else
-    m_eCharType = FX_CHARTYPE_Combination;
+    m_eCharType = FX_CHARTYPE::kCombination;
 
-  pCurChar->m_iCharWidth = iCharWidth;
-  if (iCharWidth > 0)
-    m_pCurLine->m_iWidth += iCharWidth;
+  int32_t iCharWidthValid = iCharWidth.ValueOrDefault(0);
+  pCurChar->m_iCharWidth = iCharWidthValid;
+  if (iCharWidthValid > 0) {
+    FX_SAFE_INT32 checked_width = m_pCurLine->m_iWidth;
+    checked_width += iCharWidthValid;
+    if (!checked_width.IsValid())
+      return;
+
+    m_pCurLine->m_iWidth = checked_width.ValueOrDie();
+  }
 }
 
 void CFX_RTFBreak::AppendChar_Tab(CFX_Char* pCurChar) {
@@ -144,10 +153,18 @@
 
   int32_t& iLineWidth = m_pCurLine->m_iWidth;
   int32_t iCharWidth = iLineWidth;
-  if (GetPositionedTab(&iCharWidth))
-    iCharWidth -= iLineWidth;
-  else
-    iCharWidth = m_iTabWidth * (iLineWidth / m_iTabWidth + 1) - iLineWidth;
+  FX_SAFE_INT32 iSafeCharWidth;
+  if (GetPositionedTab(&iCharWidth)) {
+    iSafeCharWidth = iCharWidth;
+  } else {
+    // Tab width is >= 160000, so this part does not need to be checked.
+    ASSERT(m_iTabWidth >= kMinimumTabWidth);
+    iSafeCharWidth = iLineWidth / m_iTabWidth + 1;
+    iSafeCharWidth *= m_iTabWidth;
+  }
+  iSafeCharWidth -= iLineWidth;
+
+  iCharWidth = iSafeCharWidth.ValueOrDefault(0);
 
   pCurChar->m_iCharWidth = iCharWidth;
   iLineWidth += iCharWidth;
@@ -178,46 +195,74 @@
 }
 
 CFX_BreakType CFX_RTFBreak::AppendChar_Arabic(CFX_Char* pCurChar) {
+  m_pCurLine->IncrementArabicCharCount();
+
   CFX_Char* pLastChar = nullptr;
-  int32_t iCharWidth = 0;
   wchar_t wForm;
   bool bAlef = false;
-  if (m_eCharType >= FX_CHARTYPE_ArabicAlef &&
-      m_eCharType <= FX_CHARTYPE_ArabicDistortion) {
+  if (m_eCharType >= FX_CHARTYPE::kArabicAlef &&
+      m_eCharType <= FX_CHARTYPE::kArabicDistortion) {
     pLastChar = GetLastChar(1, false, true);
     if (pLastChar) {
       m_pCurLine->m_iWidth -= pLastChar->m_iCharWidth;
       CFX_Char* pPrevChar = GetLastChar(2, false, true);
       wForm = pdfium::arabic::GetFormChar(pLastChar, pPrevChar, pCurChar);
       bAlef = (wForm == 0xFEFF &&
-               pLastChar->GetCharType() == FX_CHARTYPE_ArabicAlef);
-      if (!m_pFont->GetCharWidth(wForm, iCharWidth) &&
-          !m_pFont->GetCharWidth(pLastChar->char_code(), iCharWidth)) {
-        iCharWidth = m_iDefChar;
+               pLastChar->GetCharType() == FX_CHARTYPE::kArabicAlef);
+      FX_SAFE_INT32 iCharWidth;
+      int32_t iCharWidthOut;
+      if (m_pFont &&
+          (m_pFont->GetCharWidth(wForm, &iCharWidthOut) ||
+           m_pFont->GetCharWidth(pLastChar->char_code(), &iCharWidthOut))) {
+        iCharWidth = iCharWidthOut;
+      } else {
+        iCharWidth = 0;
       }
 
       iCharWidth *= m_iFontSize;
-      iCharWidth = iCharWidth * m_iHorizontalScale / 100;
-      pLastChar->m_iCharWidth = iCharWidth;
-      m_pCurLine->m_iWidth += iCharWidth;
+      iCharWidth *= m_iHorizontalScale;
+      iCharWidth /= 100;
+
+      int iCharWidthValid = iCharWidth.ValueOrDefault(0);
+      pLastChar->m_iCharWidth = iCharWidthValid;
+
+      FX_SAFE_INT32 checked_width = m_pCurLine->m_iWidth;
+      checked_width += iCharWidthValid;
+      if (!checked_width.IsValid())
+        return CFX_BreakType::None;
+
+      m_pCurLine->m_iWidth = checked_width.ValueOrDie();
       iCharWidth = 0;
     }
   }
 
   wForm = pdfium::arabic::GetFormChar(pCurChar, bAlef ? nullptr : pLastChar,
                                       nullptr);
-  if (!m_pFont->GetCharWidth(wForm, iCharWidth) &&
-      !m_pFont->GetCharWidth(pCurChar->char_code(), iCharWidth)) {
-    iCharWidth = m_iDefChar;
+  FX_SAFE_INT32 iCharWidth;
+  int32_t iCharWidthOut;
+  if (m_pFont &&
+      (m_pFont->GetCharWidth(wForm, &iCharWidthOut) ||
+       m_pFont->GetCharWidth(pCurChar->char_code(), &iCharWidthOut))) {
+    iCharWidth = iCharWidthOut;
+  } else {
+    iCharWidth = 0;
   }
 
   iCharWidth *= m_iFontSize;
-  iCharWidth = iCharWidth * m_iHorizontalScale / 100;
-  pCurChar->m_iCharWidth = iCharWidth;
-  m_pCurLine->m_iWidth += iCharWidth;
-  m_pCurLine->m_iArabicChars++;
+  iCharWidth *= m_iHorizontalScale;
+  iCharWidth /= 100;
 
-  if (m_pCurLine->GetLineEnd() > m_iLineWidth + m_iTolerance)
+  int iCharWidthValid = iCharWidth.ValueOrDefault(0);
+  pCurChar->m_iCharWidth = iCharWidthValid;
+
+  FX_SAFE_INT32 checked_width = m_pCurLine->m_iWidth;
+  checked_width += iCharWidthValid;
+  if (!checked_width.IsValid())
+    return CFX_BreakType::None;
+
+  m_pCurLine->m_iWidth = checked_width.ValueOrDie();
+
+  if (IsGreaterThanLineWidth(m_pCurLine->GetLineEnd()))
     return EndBreak(CFX_BreakType::Line);
   return CFX_BreakType::None;
 }
@@ -225,18 +270,29 @@
 CFX_BreakType CFX_RTFBreak::AppendChar_Others(CFX_Char* pCurChar) {
   FX_CHARTYPE chartype = pCurChar->GetCharType();
   wchar_t wForm = pCurChar->char_code();
-  int32_t iCharWidth = 0;
-  if (!m_pFont->GetCharWidth(wForm, iCharWidth))
-    iCharWidth = m_iDefChar;
+  FX_SAFE_INT32 iCharWidth;
+  int32_t iCharWidthOut;
+  if (m_pFont && m_pFont->GetCharWidth(wForm, &iCharWidthOut))
+    iCharWidth = iCharWidthOut;
+  else
+    iCharWidth = 0;
 
   iCharWidth *= m_iFontSize;
-  iCharWidth *= m_iHorizontalScale / 100;
+  iCharWidth *= m_iHorizontalScale;
+  iCharWidth /= 100;
   iCharWidth += m_iCharSpace;
 
-  pCurChar->m_iCharWidth = iCharWidth;
-  m_pCurLine->m_iWidth += iCharWidth;
-  if (chartype != FX_CHARTYPE_Space &&
-      m_pCurLine->GetLineEnd() > m_iLineWidth + m_iTolerance) {
+  int iCharWidthValid = iCharWidth.ValueOrDefault(0);
+  pCurChar->m_iCharWidth = iCharWidthValid;
+
+  FX_SAFE_INT32 checked_width = m_pCurLine->m_iWidth;
+  checked_width += iCharWidthValid;
+  if (!checked_width.IsValid())
+    return CFX_BreakType::None;
+
+  m_pCurLine->m_iWidth = checked_width.ValueOrDie();
+  if (chartype != FX_CHARTYPE::kSpace &&
+      IsGreaterThanLineWidth(m_pCurLine->GetLineEnd())) {
     return EndBreak(CFX_BreakType::Line);
   }
   return CFX_BreakType::None;
@@ -253,25 +309,24 @@
   }
 
   if (HasLine()) {
-    if (!m_Line[m_iReadyLineIndex].m_LinePieces.empty()) {
-      if (dwStatus != CFX_BreakType::Piece)
-        m_Line[m_iReadyLineIndex].m_LinePieces.back().m_dwStatus = dwStatus;
-      return m_Line[m_iReadyLineIndex].m_LinePieces.back().m_dwStatus;
-    }
-    return CFX_BreakType::None;
+    if (m_Lines[m_iReadyLineIndex].m_LinePieces.empty())
+      return CFX_BreakType::None;
+
+    if (dwStatus != CFX_BreakType::Piece)
+      m_Lines[m_iReadyLineIndex].m_LinePieces.back().m_dwStatus = dwStatus;
+    return m_Lines[m_iReadyLineIndex].m_LinePieces.back().m_dwStatus;
   }
 
-  int32_t iCount = m_pCurLine->CountChars();
-  if (iCount < 1)
+  if (m_pCurLine->m_LineChars.empty())
     return CFX_BreakType::None;
 
-  CFX_Char* tc = m_pCurLine->GetChar(iCount - 1);
+  CFX_Char* tc = m_pCurLine->GetChar(m_pCurLine->m_LineChars.size() - 1);
   tc->m_dwStatus = dwStatus;
   if (dwStatus == CFX_BreakType::Piece)
     return dwStatus;
 
-  m_iReadyLineIndex = m_pCurLine == &m_Line[0] ? 0 : 1;
-  CFX_BreakLine* pNextLine = &m_Line[1 - m_iReadyLineIndex];
+  m_iReadyLineIndex = m_pCurLine == &m_Lines[0] ? 0 : 1;
+  CFX_BreakLine* pNextLine = &m_Lines[1 - m_iReadyLineIndex];
   bool bAllChars = m_iAlignment == CFX_RTFLineAlignment::Justified ||
                    m_iAlignment == CFX_RTFLineAlignment::Distributed;
 
@@ -285,7 +340,7 @@
   m_pCurLine->m_iStart = m_iLineStart;
 
   CFX_Char* pTC = GetLastChar(0, false, true);
-  m_eCharType = pTC ? pTC->GetCharType() : FX_CHARTYPE_Unknown;
+  m_eCharType = pTC ? pTC->GetCharType() : FX_CHARTYPE::kUnknown;
   return dwStatus;
 }
 
@@ -293,15 +348,16 @@
                                       bool bAllChars,
                                       CFX_BreakType dwStatus) {
   bool bDone = false;
-  if (m_pCurLine->GetLineEnd() > m_iLineWidth + m_iTolerance) {
-    const CFX_Char* tc = m_pCurLine->GetChar(m_pCurLine->CountChars() - 1);
+  if (IsGreaterThanLineWidth(m_pCurLine->GetLineEnd())) {
+    const CFX_Char* tc =
+        m_pCurLine->GetChar(m_pCurLine->m_LineChars.size() - 1);
     switch (tc->GetCharType()) {
-      case FX_CHARTYPE_Tab:
-      case FX_CHARTYPE_Control:
-      case FX_CHARTYPE_Space:
+      case FX_CHARTYPE::kTab:
+      case FX_CHARTYPE::kControl:
+      case FX_CHARTYPE::kSpace:
         break;
       default:
-        SplitTextLine(m_pCurLine, pNextLine, !m_bPagination && bAllChars);
+        SplitTextLine(m_pCurLine.Get(), pNextLine, !m_bPagination && bAllChars);
         bDone = true;
         break;
     }
@@ -310,7 +366,7 @@
   if (!m_bPagination) {
     if (bAllChars && !bDone) {
       int32_t endPos = m_pCurLine->GetLineEnd();
-      GetBreakPos(m_pCurLine->m_LineChars, endPos, bAllChars, true);
+      GetBreakPos(m_pCurLine->m_LineChars, bAllChars, true, &endPos);
     }
     return false;
   }
@@ -320,7 +376,7 @@
   tp.m_pChars = &m_pCurLine->m_LineChars;
   bool bNew = true;
   uint32_t dwIdentity = static_cast<uint32_t>(-1);
-  int32_t iLast = m_pCurLine->CountChars() - 1;
+  int32_t iLast = pdfium::CollectionSize<int32_t>(m_pCurLine->m_LineChars) - 1;
   int32_t j = 0;
   for (int32_t i = 0; i <= iLast;) {
     const CFX_Char* pTC = pCurChars + i;
@@ -334,7 +390,7 @@
       tp.m_iVerticalScale = pTC->vertical_scale();
       dwIdentity = pTC->m_dwIdentity;
       tp.m_dwIdentity = dwIdentity;
-      tp.m_pUserData = pTC->m_pUserData.As<CXFA_TextUserData>();
+      tp.m_pUserData = pTC->m_pUserData;
       j = i;
       bNew = false;
     }
@@ -362,22 +418,19 @@
                                      CFX_BreakType dwStatus) {
   CFX_Char* pTC;
   std::vector<CFX_Char>& chars = m_pCurLine->m_LineChars;
-  int32_t iCount = m_pCurLine->CountChars();
-  if (!m_bPagination && m_pCurLine->m_iArabicChars > 0) {
-    ASSERT(iCount >= 0);
-
+  if (!m_bPagination && m_pCurLine->HasArabicChar()) {
     size_t iBidiNum = 0;
-    for (size_t i = 0; i < static_cast<size_t>(iCount); ++i) {
+    for (size_t i = 0; i < m_pCurLine->m_LineChars.size(); ++i) {
       pTC = &chars[i];
       pTC->m_iBidiPos = static_cast<int32_t>(i);
-      if (pTC->GetCharType() != FX_CHARTYPE_Control)
+      if (pTC->GetCharType() != FX_CHARTYPE::kControl)
         iBidiNum = i;
       if (i == 0)
         pTC->m_iBidiLevel = 1;
     }
-    FX_BidiLine(&chars, iBidiNum + 1);
+    CFX_Char::BidiLine(&chars, iBidiNum + 1);
   } else {
-    for (int32_t i = 0; i < iCount; ++i) {
+    for (size_t i = 0; i < m_pCurLine->m_LineChars.size(); ++i) {
       pTC = &chars[i];
       pTC->m_iBidiLevel = 0;
       pTC->m_iBidiPos = 0;
@@ -396,6 +449,7 @@
   uint32_t dwIdentity = static_cast<uint32_t>(-1);
   int32_t i = 0;
   int32_t j = 0;
+  int32_t iCount = pdfium::CollectionSize<int32_t>(m_pCurLine->m_LineChars);
   while (i < iCount) {
     pTC = &chars[i];
     if (iBidiLevel < 0) {
@@ -409,7 +463,7 @@
       tp.m_iVerticalScale = pTC->vertical_scale();
       dwIdentity = pTC->m_dwIdentity;
       tp.m_dwIdentity = dwIdentity;
-      tp.m_pUserData = pTC->m_pUserData.As<CXFA_TextUserData>();
+      tp.m_pUserData = pTC->m_pUserData;
       tp.m_dwStatus = CFX_BreakType::Piece;
       ++i;
     } else if (iBidiLevel != pTC->m_iBidiLevel ||
@@ -465,13 +519,13 @@
     int32_t j = bArabic ? 0 : ttp.m_iChars - 1;
     while (j > -1 && j < ttp.m_iChars) {
       const CFX_Char* tc = ttp.GetChar(j);
-      if (tc->m_nBreakType == FX_LBT_DIRECT_BRK)
+      if (tc->m_eLineBreakType == FX_LINEBREAKTYPE::kDIRECT_BRK)
         ++iGapChars;
 
       if (!bFind || !bAllChars) {
-        uint32_t dwCharType = tc->GetCharType();
-        if (dwCharType == FX_CHARTYPE_Space ||
-            dwCharType == FX_CHARTYPE_Control) {
+        FX_CHARTYPE dwCharType = tc->GetCharType();
+        if (dwCharType == FX_CHARTYPE::kSpace ||
+            dwCharType == FX_CHARTYPE::kControl) {
           if (!bFind) {
             int32_t iCharWidth = tc->m_iCharWidth;
             if (bAllChars && iCharWidth > 0)
@@ -503,9 +557,10 @@
 
       for (int32_t j = 0; j < ttp.m_iChars; ++j) {
         CFX_Char* tc = ttp.GetChar(j);
-        if (tc->m_nBreakType != FX_LBT_DIRECT_BRK || tc->m_iCharWidth < 0)
+        if (tc->m_eLineBreakType != FX_LINEBREAKTYPE::kDIRECT_BRK ||
+            tc->m_iCharWidth < 0) {
           continue;
-
+        }
         int32_t k = iOffset / iGapChars;
         tc->m_iCharWidth += k;
         ttp.m_iWidth += k;
@@ -528,9 +583,9 @@
 }
 
 int32_t CFX_RTFBreak::GetBreakPos(std::vector<CFX_Char>& tca,
-                                  int32_t& iEndPos,
                                   bool bAllChars,
-                                  bool bOnlyBrk) {
+                                  bool bOnlyBrk,
+                                  int32_t* pEndPos) {
   int32_t iLength = pdfium::CollectionSize<int32_t>(tca) - 1;
   if (iLength < 1)
     return iLength;
@@ -541,84 +596,82 @@
   int32_t iIndirectPos = -1;
   int32_t iLast = -1;
   int32_t iLastPos = -1;
-  if (iEndPos <= m_iLineWidth) {
+  if (*pEndPos <= m_iLineWidth) {
     if (!bAllChars)
       return iLength;
 
     iBreak = iLength;
-    iBreakPos = iEndPos;
+    iBreakPos = *pEndPos;
   }
 
   CFX_Char* pCharArray = tca.data();
   CFX_Char* pCur = pCharArray + iLength;
   --iLength;
   if (bAllChars)
-    pCur->m_nBreakType = FX_LBT_UNKNOWN;
+    pCur->m_eLineBreakType = FX_LINEBREAKTYPE::kUNKNOWN;
 
-  uint32_t nCodeProp = pCur->char_props();
-  uint32_t nNext = nCodeProp & 0x003F;
+  FX_BREAKPROPERTY nNext = FX_GetBreakProperty(pCur->char_code());
   int32_t iCharWidth = pCur->m_iCharWidth;
   if (iCharWidth > 0)
-    iEndPos -= iCharWidth;
+    *pEndPos -= iCharWidth;
 
   while (iLength >= 0) {
     pCur = pCharArray + iLength;
-    nCodeProp = pCur->char_props();
-    uint32_t nCur = nCodeProp & 0x003F;
+    FX_BREAKPROPERTY nCur = FX_GetBreakProperty(pCur->char_code());
     bool bNeedBreak = false;
     FX_LINEBREAKTYPE eType;
-    if (nCur == kBreakPropertyTB) {
+    if (nCur == FX_BREAKPROPERTY::kTB) {
       bNeedBreak = true;
-      eType = nNext == kBreakPropertyTB
-                  ? FX_LBT_PROHIBITED_BRK
-                  : gs_FX_LineBreak_PairTable[nCur][nNext];
+      eType = nNext == FX_BREAKPROPERTY::kTB
+                  ? FX_LINEBREAKTYPE::kPROHIBITED_BRK
+                  : GetLineBreakTypeFromPair(nCur, nNext);
     } else {
-      if (nCur == kBreakPropertySpace)
+      if (nCur == FX_BREAKPROPERTY::kSP)
         bNeedBreak = true;
 
-      eType = nNext == kBreakPropertySpace
-                  ? FX_LBT_PROHIBITED_BRK
-                  : gs_FX_LineBreak_PairTable[nCur][nNext];
+      eType = nNext == FX_BREAKPROPERTY::kSP
+                  ? FX_LINEBREAKTYPE::kPROHIBITED_BRK
+                  : GetLineBreakTypeFromPair(nCur, nNext);
     }
     if (bAllChars)
-      pCur->m_nBreakType = eType;
+      pCur->m_eLineBreakType = eType;
 
     if (!bOnlyBrk) {
       iCharWidth = pCur->m_iCharWidth;
-      if (iEndPos <= m_iLineWidth || bNeedBreak) {
-        if (eType == FX_LBT_DIRECT_BRK && iBreak < 0) {
+      if (*pEndPos <= m_iLineWidth || bNeedBreak) {
+        if (eType == FX_LINEBREAKTYPE::kDIRECT_BRK && iBreak < 0) {
           iBreak = iLength;
-          iBreakPos = iEndPos;
+          iBreakPos = *pEndPos;
           if (!bAllChars)
             return iLength;
-        } else if (eType == FX_LBT_INDIRECT_BRK && iIndirect < 0) {
+        } else if (eType == FX_LINEBREAKTYPE::kINDIRECT_BRK && iIndirect < 0) {
           iIndirect = iLength;
-          iIndirectPos = iEndPos;
+          iIndirectPos = *pEndPos;
         }
         if (iLast < 0) {
           iLast = iLength;
-          iLastPos = iEndPos;
+          iLastPos = *pEndPos;
         }
       }
       if (iCharWidth > 0)
-        iEndPos -= iCharWidth;
+        *pEndPos -= iCharWidth;
     }
-    nNext = nCodeProp & 0x003F;
+    nNext = nCur;
     --iLength;
   }
   if (bOnlyBrk)
     return 0;
 
   if (iBreak > -1) {
-    iEndPos = iBreakPos;
+    *pEndPos = iBreakPos;
     return iBreak;
   }
   if (iIndirect > -1) {
-    iEndPos = iIndirectPos;
+    *pEndPos = iIndirectPos;
     return iIndirect;
   }
   if (iLast > -1) {
-    iEndPos = iLastPos;
+    *pEndPos = iLastPos;
     return iLast;
   }
   return 0;
@@ -627,21 +680,22 @@
 void CFX_RTFBreak::SplitTextLine(CFX_BreakLine* pCurLine,
                                  CFX_BreakLine* pNextLine,
                                  bool bAllChars) {
-  ASSERT(pCurLine && pNextLine);
-  int32_t iCount = pCurLine->CountChars();
-  if (iCount < 2)
+  ASSERT(pCurLine);
+  ASSERT(pNextLine);
+
+  if (pCurLine->m_LineChars.size() < 2)
     return;
 
   int32_t iEndPos = pCurLine->GetLineEnd();
   std::vector<CFX_Char>& curChars = pCurLine->m_LineChars;
-  int32_t iCharPos = GetBreakPos(curChars, iEndPos, bAllChars, false);
+  int32_t iCharPos = GetBreakPos(curChars, bAllChars, false, &iEndPos);
   if (iCharPos < 0)
     iCharPos = 0;
 
   ++iCharPos;
-  if (iCharPos >= iCount) {
+  if (iCharPos >= pdfium::CollectionSize<int32_t>(pCurLine->m_LineChars)) {
     pNextLine->Clear();
-    curChars[iCharPos - 1].m_nBreakType = FX_LBT_UNKNOWN;
+    curChars[iCharPos - 1].m_eLineBreakType = FX_LINEBREAKTYPE::kUNKNOWN;
     return;
   }
 
@@ -651,30 +705,30 @@
   pNextLine->m_iStart = pCurLine->m_iStart;
   pNextLine->m_iWidth = pCurLine->GetLineEnd() - iEndPos;
   pCurLine->m_iWidth = iEndPos;
-  curChars[iCharPos - 1].m_nBreakType = FX_LBT_UNKNOWN;
+  curChars[iCharPos - 1].m_eLineBreakType = FX_LINEBREAKTYPE::kUNKNOWN;
 
   for (size_t i = 0; i < pNextLine->m_LineChars.size(); ++i) {
-    if (pNextLine->m_LineChars[i].GetCharType() >= FX_CHARTYPE_ArabicAlef) {
-      pCurLine->m_iArabicChars--;
-      pNextLine->m_iArabicChars++;
+    if (pNextLine->m_LineChars[i].GetCharType() >= FX_CHARTYPE::kArabicAlef) {
+      pCurLine->DecrementArabicCharCount();
+      pNextLine->IncrementArabicCharCount();
     }
     pNextLine->m_LineChars[i].m_dwStatus = CFX_BreakType::None;
   }
 }
 
-int32_t CFX_RTFBreak::GetDisplayPos(const FX_RTFTEXTOBJ* pText,
-                                    FXTEXT_CHARPOS* pCharPos,
-                                    bool bCharCode) const {
-  if (!pText || pText->iLength < 1)
+size_t CFX_RTFBreak::GetDisplayPos(const CFX_TextPiece* pPiece,
+                                   std::vector<TextCharPos>* pCharPos) const {
+  ASSERT(pPiece->iChars > 0);
+  ASSERT(pPiece->pFont);
+
+  RetainPtr<CFGAS_GEFont> pFont = pPiece->pFont;
+  CFX_RectF rtText(pPiece->rtPiece);
+  bool bRTLPiece = FX_IsOdd(pPiece->iBidiLevel);
+  float fFontSize = pPiece->fFontSize;
+  int32_t iFontSize = FXSYS_roundf(fFontSize * 20.0f);
+  if (iFontSize == 0)
     return 0;
 
-  ASSERT(pText->pFont && pText->pRect);
-
-  RetainPtr<CFGAS_GEFont> pFont = pText->pFont;
-  CFX_RectF rtText(*pText->pRect);
-  bool bRTLPiece = FX_IsOdd(pText->iBidiLevel);
-  float fFontSize = pText->fFontSize;
-  int32_t iFontSize = FXSYS_round(fFontSize * 20.0f);
   int32_t iAscent = pFont->GetAscent();
   int32_t iDescent = pFont->GetDescent();
   int32_t iMaxHeight = iAscent - iDescent;
@@ -684,106 +738,86 @@
   wchar_t wPrev = 0xFEFF;
   wchar_t wNext;
   float fX = rtText.left;
-  int32_t iHorScale = pText->iHorizontalScale;
-  int32_t iVerScale = pText->iVerticalScale;
+  int32_t iHorScale = pPiece->iHorScale;
+  int32_t iVerScale = pPiece->iVerScale;
   if (bRTLPiece)
     fX = rtText.right();
 
   float fY = rtText.top + fAscent;
-  int32_t iCount = 0;
-  for (int32_t i = 0; i < pText->iLength; ++i) {
-    wchar_t wch = pText->pStr[i];
-    int32_t iWidth = pText->pWidths[i];
-    uint32_t dwProps = FX_GetUnicodeProperties(wch);
-    uint32_t dwCharType = (dwProps & FX_CHARTYPEBITSMASK);
+  size_t szCount = 0;
+  for (int32_t i = 0; i < pPiece->iChars; ++i) {
+    TextCharPos& current_char_pos = (*pCharPos)[szCount];
+    wchar_t wch = pPiece->szText[i];
+    int32_t iWidth = pPiece->Widths[i];
+    FX_CHARTYPE dwCharType = FX_GetCharType(wch);
     if (iWidth == 0) {
-      if (dwCharType == FX_CHARTYPE_ArabicAlef)
+      if (dwCharType == FX_CHARTYPE::kArabicAlef)
         wPrev = 0xFEFF;
       continue;
     }
 
-    int32_t iCharWidth = abs(iWidth);
-    bool bEmptyChar =
-        (dwCharType >= FX_CHARTYPE_Tab && dwCharType <= FX_CHARTYPE_Control);
+    uint32_t iCharWidth = abs(iWidth);
+    const bool bEmptyChar = (dwCharType >= FX_CHARTYPE::kTab &&
+                             dwCharType <= FX_CHARTYPE::kControl);
     if (!bEmptyChar)
-      ++iCount;
+      ++szCount;
 
-    if (pCharPos) {
-      iCharWidth /= iFontSize;
-      wchar_t wForm = wch;
-      if (dwCharType >= FX_CHARTYPE_ArabicAlef) {
-        if (i + 1 < pText->iLength) {
-          wNext = pText->pStr[i + 1];
-          if (pText->pWidths[i + 1] < 0 && i + 2 < pText->iLength)
-            wNext = pText->pStr[i + 2];
-        } else {
-          wNext = 0xFEFF;
-        }
-        wForm = pdfium::arabic::GetFormChar(wch, wPrev, wNext);
-      } else if (bRTLPiece) {
-        wForm = FX_GetMirrorChar(wch, dwProps);
+    iCharWidth /= iFontSize;
+    wchar_t wForm = wch;
+    if (dwCharType >= FX_CHARTYPE::kArabicAlef) {
+      if (i + 1 < pPiece->iChars) {
+        wNext = pPiece->szText[i + 1];
+        if (pPiece->Widths[i + 1] < 0 && i + 2 < pPiece->iChars)
+          wNext = pPiece->szText[i + 2];
+      } else {
+        wNext = 0xFEFF;
       }
-      dwProps = FX_GetUnicodeProperties(wForm);
+      wForm = pdfium::arabic::GetFormChar(wch, wPrev, wNext);
+    } else if (bRTLPiece) {
+      wForm = FX_GetMirrorChar(wch);
+    }
 
-      if (!bEmptyChar) {
-        if (bCharCode) {
-          pCharPos->m_GlyphIndex = wch;
-        } else {
-          pCharPos->m_GlyphIndex = pFont->GetGlyphIndex(wForm);
-          if (pCharPos->m_GlyphIndex == 0xFFFF)
-            pCharPos->m_GlyphIndex = pFont->GetGlyphIndex(wch);
-        }
-#if _FX_PLATFORM_ == _FX_PLATFORM_APPLE_
-        pCharPos->m_ExtGID = pCharPos->m_GlyphIndex;
+    if (!bEmptyChar) {
+      current_char_pos.m_GlyphIndex = pFont->GetGlyphIndex(wForm);
+      if (current_char_pos.m_GlyphIndex == 0xFFFF)
+        current_char_pos.m_GlyphIndex = pFont->GetGlyphIndex(wch);
+#if defined(OS_MACOSX)
+      current_char_pos.m_ExtGID = current_char_pos.m_GlyphIndex;
 #endif
-        pCharPos->m_FontCharWidth = iCharWidth;
-      }
+      current_char_pos.m_FontCharWidth = iCharWidth;
+    }
 
-      float fCharWidth = fFontSize * iCharWidth / 1000.0f;
-      if (bRTLPiece && dwCharType != FX_CHARTYPE_Combination)
-        fX -= fCharWidth;
+    float fCharWidth = fFontSize * iCharWidth / 1000.0f;
+    if (bRTLPiece && dwCharType != FX_CHARTYPE::kCombination)
+      fX -= fCharWidth;
 
-      if (!bEmptyChar)
-        pCharPos->m_Origin = CFX_PointF(fX, fY);
-      if (!bRTLPiece && dwCharType != FX_CHARTYPE_Combination)
-        fX += fCharWidth;
+    if (!bEmptyChar)
+      current_char_pos.m_Origin = CFX_PointF(fX, fY);
+    if (!bRTLPiece && dwCharType != FX_CHARTYPE::kCombination)
+      fX += fCharWidth;
 
-      if (!bEmptyChar) {
-        pCharPos->m_bGlyphAdjust = true;
-        pCharPos->m_AdjustMatrix[0] = -1;
-        pCharPos->m_AdjustMatrix[1] = 0;
-        pCharPos->m_AdjustMatrix[2] = 0;
-        pCharPos->m_AdjustMatrix[3] = 1;
-        pCharPos->m_Origin.y += fAscent * iVerScale / 100.0f;
-        pCharPos->m_Origin.y -= fAscent;
+    if (!bEmptyChar) {
+      current_char_pos.m_bGlyphAdjust = true;
+      current_char_pos.m_AdjustMatrix[0] = -1;
+      current_char_pos.m_AdjustMatrix[1] = 0;
+      current_char_pos.m_AdjustMatrix[2] = 0;
+      current_char_pos.m_AdjustMatrix[3] = 1;
+      current_char_pos.m_Origin.y += fAscent * iVerScale / 100.0f;
+      current_char_pos.m_Origin.y -= fAscent;
 
-        if (iHorScale != 100 || iVerScale != 100) {
-          pCharPos->m_AdjustMatrix[0] =
-              pCharPos->m_AdjustMatrix[0] * iHorScale / 100.0f;
-          pCharPos->m_AdjustMatrix[1] =
-              pCharPos->m_AdjustMatrix[1] * iHorScale / 100.0f;
-          pCharPos->m_AdjustMatrix[2] =
-              pCharPos->m_AdjustMatrix[2] * iVerScale / 100.0f;
-          pCharPos->m_AdjustMatrix[3] =
-              pCharPos->m_AdjustMatrix[3] * iVerScale / 100.0f;
-        }
-        ++pCharPos;
+      if (iHorScale != 100 || iVerScale != 100) {
+        current_char_pos.m_AdjustMatrix[0] =
+            current_char_pos.m_AdjustMatrix[0] * iHorScale / 100.0f;
+        current_char_pos.m_AdjustMatrix[1] =
+            current_char_pos.m_AdjustMatrix[1] * iHorScale / 100.0f;
+        current_char_pos.m_AdjustMatrix[2] =
+            current_char_pos.m_AdjustMatrix[2] * iVerScale / 100.0f;
+        current_char_pos.m_AdjustMatrix[3] =
+            current_char_pos.m_AdjustMatrix[3] * iVerScale / 100.0f;
       }
     }
     if (iWidth > 0)
       wPrev = wch;
   }
-  return iCount;
+  return szCount;
 }
-
-FX_RTFTEXTOBJ::FX_RTFTEXTOBJ()
-    : pFont(nullptr),
-      pRect(nullptr),
-      wLineBreakChar(L'\n'),
-      fFontSize(12.0f),
-      iLength(0),
-      iBidiLevel(0),
-      iHorizontalScale(100),
-      iVerticalScale(100) {}
-
-FX_RTFTEXTOBJ::~FX_RTFTEXTOBJ() {}
diff --git a/xfa/fgas/layout/cfx_rtfbreak.h b/xfa/fgas/layout/cfx_rtfbreak.h
index 67052d2..2a722b0 100644
--- a/xfa/fgas/layout/cfx_rtfbreak.h
+++ b/xfa/fgas/layout/cfx_rtfbreak.h
@@ -14,10 +14,11 @@
 #include "core/fxcrt/fx_unicode.h"
 #include "core/fxcrt/retain_ptr.h"
 #include "xfa/fgas/layout/cfx_break.h"
-#include "xfa/fxfa/cxfa_textuserdata.h"
 
 class CFGAS_GEFont;
-class FXTEXT_CHARPOS;
+class CFX_TextUserData;
+class CFX_TextPiece;
+class TextCharPos;
 
 enum class CFX_RTFLineAlignment {
   Left = 0,
@@ -27,23 +28,7 @@
   Distributed
 };
 
-struct FX_RTFTEXTOBJ {
-  FX_RTFTEXTOBJ();
-  ~FX_RTFTEXTOBJ();
-
-  WideString pStr;
-  std::vector<int32_t> pWidths;
-  RetainPtr<CFGAS_GEFont> pFont;
-  const CFX_RectF* pRect;
-  wchar_t wLineBreakChar;
-  float fFontSize;
-  int32_t iLength;
-  int32_t iBidiLevel;
-  int32_t iHorizontalScale;
-  int32_t iVerticalScale;
-};
-
-class CFX_RTFBreak : public CFX_Break {
+class CFX_RTFBreak final : public CFX_Break {
  public:
   explicit CFX_RTFBreak(uint32_t dwLayoutStyles);
   ~CFX_RTFBreak() override;
@@ -51,33 +36,29 @@
   void SetLineStartPos(float fLinePos);
 
   void SetAlignment(CFX_RTFLineAlignment align) { m_iAlignment = align; }
-  void SetUserData(const RetainPtr<CXFA_TextUserData>& pUserData);
+  void SetUserData(const RetainPtr<CFX_TextUserData>& pUserData);
 
   void AddPositionedTab(float fTabPos);
 
   CFX_BreakType EndBreak(CFX_BreakType dwStatus);
 
-  int32_t GetDisplayPos(const FX_RTFTEXTOBJ* pText,
-                        FXTEXT_CHARPOS* pCharPos,
-                        bool bCharCode) const;
+  size_t GetDisplayPos(const CFX_TextPiece* pPiece,
+                       std::vector<TextCharPos>* pCharPos) const;
 
   CFX_BreakType AppendChar(wchar_t wch);
 
-  CFX_BreakLine* GetCurrentLineForTesting() const { return m_pCurLine; }
-
  private:
   void AppendChar_Combination(CFX_Char* pCurChar);
   void AppendChar_Tab(CFX_Char* pCurChar);
   CFX_BreakType AppendChar_Control(CFX_Char* pCurChar);
   CFX_BreakType AppendChar_Arabic(CFX_Char* pCurChar);
   CFX_BreakType AppendChar_Others(CFX_Char* pCurChar);
-  int32_t GetLastPositionedTab() const;
   bool GetPositionedTab(int32_t* iTabPos) const;
 
   int32_t GetBreakPos(std::vector<CFX_Char>& tca,
-                      int32_t& iEndPos,
                       bool bAllChars,
-                      bool bOnlyBrk);
+                      bool bOnlyBrk,
+                      int32_t* pEndPos);
   void SplitTextLine(CFX_BreakLine* pCurLine,
                      CFX_BreakLine* pNextLine,
                      bool bAllChars);
@@ -92,7 +73,7 @@
   bool m_bPagination;
   std::vector<int32_t> m_PositionedTabs;
   CFX_RTFLineAlignment m_iAlignment;
-  RetainPtr<CXFA_TextUserData> m_pUserData;
+  RetainPtr<CFX_TextUserData> m_pUserData;
 };
 
 #endif  // XFA_FGAS_LAYOUT_CFX_RTFBREAK_H_
diff --git a/xfa/fgas/layout/cfx_rtfbreak_unittest.cpp b/xfa/fgas/layout/cfx_rtfbreak_unittest.cpp
index 5f24631..0775d7b 100644
--- a/xfa/fgas/layout/cfx_rtfbreak_unittest.cpp
+++ b/xfa/fgas/layout/cfx_rtfbreak_unittest.cpp
@@ -7,26 +7,29 @@
 #include "xfa/fgas/layout/cfx_rtfbreak.h"
 
 #include <memory>
+#include <utility>
 
+#include "core/fxge/cfx_font.h"
 #include "core/fxge/cfx_gemodule.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "testing/test_support.h"
+#include "testing/xfa_unit_test_support.h"
 #include "third_party/base/ptr_util.h"
 #include "xfa/fgas/font/cfgas_fontmgr.h"
 #include "xfa/fgas/font/cfgas_gefont.h"
+#include "xfa/fgas/layout/cfx_char.h"
 
 class CFX_RTFBreakTest : public testing::Test {
  public:
   void SetUp() override {
     font_ =
         CFGAS_GEFont::LoadFont(L"Arial Black", 0, 0, GetGlobalFontManager());
-    ASSERT(font_.Get() != nullptr);
+    ASSERT_TRUE(font_.Get());
   }
 
-  std::unique_ptr<CFX_RTFBreak> CreateBreak(int32_t args) {
-    auto b = pdfium::MakeUnique<CFX_RTFBreak>(args);
-    b->SetFont(font_);
-    return b;
+  std::unique_ptr<CFX_RTFBreak> CreateBreak(uint32_t layout_styles) {
+    auto rtf_break = pdfium::MakeUnique<CFX_RTFBreak>(layout_styles);
+    rtf_break->SetFont(font_);
+    return rtf_break;
   }
 
  private:
@@ -37,38 +40,54 @@
 // and must be consumed before you get any more characters ....
 
 TEST_F(CFX_RTFBreakTest, AddChars) {
-  auto b = CreateBreak(FX_LAYOUTSTYLE_ExpandTab);
+  auto rtf_break = CreateBreak(FX_LAYOUTSTYLE_ExpandTab);
 
   WideString str(L"Input String.");
-  for (const auto& c : str)
-    EXPECT_EQ(CFX_BreakType::None, b->AppendChar(c));
+  for (wchar_t ch : str)
+    EXPECT_EQ(CFX_BreakType::None, rtf_break->AppendChar(ch));
 
-  EXPECT_EQ(CFX_BreakType::Paragraph, b->AppendChar(L'\n'));
-  ASSERT_EQ(1, b->CountBreakPieces());
-  EXPECT_EQ(str + L"\n", b->GetBreakPieceUnstable(0)->GetString());
+  EXPECT_EQ(CFX_BreakType::Paragraph, rtf_break->AppendChar(L'\n'));
+  ASSERT_EQ(1, rtf_break->CountBreakPieces());
+  EXPECT_EQ(str + L"\n", rtf_break->GetBreakPieceUnstable(0)->GetString());
 
-  b->ClearBreakPieces();
-  b->Reset();
-  EXPECT_EQ(0, b->GetCurrentLineForTesting()->GetLineEnd());
+  rtf_break->ClearBreakPieces();
+  rtf_break->Reset();
+  EXPECT_EQ(0, rtf_break->GetCurrentLineForTesting()->GetLineEnd());
 
   str = L"Second str.";
-  for (const auto& c : str)
-    EXPECT_EQ(CFX_BreakType::None, b->AppendChar(c));
+  for (wchar_t ch : str)
+    EXPECT_EQ(CFX_BreakType::None, rtf_break->AppendChar(ch));
 
   // Force the end of the break at the end of the string.
-  b->EndBreak(CFX_BreakType::Paragraph);
-  ASSERT_EQ(1, b->CountBreakPieces());
-  EXPECT_EQ(str, b->GetBreakPieceUnstable(0)->GetString());
+  rtf_break->EndBreak(CFX_BreakType::Paragraph);
+  ASSERT_EQ(1, rtf_break->CountBreakPieces());
+  EXPECT_EQ(str, rtf_break->GetBreakPieceUnstable(0)->GetString());
 }
 
 TEST_F(CFX_RTFBreakTest, ControlCharacters) {
-  auto b = CreateBreak(FX_LAYOUTSTYLE_ExpandTab);
-  EXPECT_EQ(CFX_BreakType::Line, b->AppendChar(L'\v'));
-  EXPECT_EQ(CFX_BreakType::Page, b->AppendChar(L'\f'));
-  // 0x2029 is the Paragraph Separator unicode character.
-  EXPECT_EQ(CFX_BreakType::Paragraph, b->AppendChar(0x2029));
-  EXPECT_EQ(CFX_BreakType::Paragraph, b->AppendChar(L'\n'));
+  auto rtf_break = CreateBreak(FX_LAYOUTSTYLE_ExpandTab);
+  EXPECT_EQ(CFX_BreakType::Line, rtf_break->AppendChar(L'\v'));
+  EXPECT_EQ(CFX_BreakType::Page, rtf_break->AppendChar(L'\f'));
+  const wchar_t kUnicodeParagraphSeparator = 0x2029;
+  EXPECT_EQ(CFX_BreakType::Paragraph,
+            rtf_break->AppendChar(kUnicodeParagraphSeparator));
+  EXPECT_EQ(CFX_BreakType::Paragraph, rtf_break->AppendChar(L'\n'));
 
-  ASSERT_EQ(1, b->CountBreakPieces());
-  EXPECT_EQ(L"\v", b->GetBreakPieceUnstable(0)->GetString());
+  ASSERT_EQ(1, rtf_break->CountBreakPieces());
+  EXPECT_EQ(L"\v", rtf_break->GetBreakPieceUnstable(0)->GetString());
+}
+
+TEST_F(CFX_RTFBreakTest, BidiLine) {
+  auto rtf_break = CreateBreak(FX_LAYOUTSTYLE_ExpandTab);
+  rtf_break->SetLineBreakTolerance(1);
+  rtf_break->SetFontSize(12);
+
+  WideString input = WideString::FromUTF8(ByteStringView("\xa\x0\xa\xa", 4));
+  for (wchar_t ch : input)
+    rtf_break->AppendChar(ch);
+
+  std::vector<CFX_Char> chars =
+      rtf_break->GetCurrentLineForTesting()->m_LineChars;
+  CFX_Char::BidiLine(&chars, chars.size());
+  EXPECT_EQ(3u, chars.size());
 }
diff --git a/xfa/fgas/layout/cfx_textpiece.cpp b/xfa/fgas/layout/cfx_textpiece.cpp
new file mode 100644
index 0000000..06f6cd6
--- /dev/null
+++ b/xfa/fgas/layout/cfx_textpiece.cpp
@@ -0,0 +1,13 @@
+// Copyright 2019 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
+
+#include "xfa/fgas/layout/cfx_textpiece.h"
+
+#include "xfa/fgas/font/cfgas_gefont.h"
+
+CFX_TextPiece::CFX_TextPiece() = default;
+
+CFX_TextPiece::~CFX_TextPiece() = default;
diff --git a/xfa/fgas/layout/cfx_textpiece.h b/xfa/fgas/layout/cfx_textpiece.h
new file mode 100644
index 0000000..409d200
--- /dev/null
+++ b/xfa/fgas/layout/cfx_textpiece.h
@@ -0,0 +1,34 @@
+// Copyright 2019 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_FGAS_LAYOUT_CFX_TEXTPIECE_H_
+#define XFA_FGAS_LAYOUT_CFX_TEXTPIECE_H_
+
+#include <vector>
+
+#include "core/fxcrt/fx_coordinates.h"
+#include "core/fxcrt/fx_string.h"
+#include "core/fxcrt/retain_ptr.h"
+
+class CFGAS_GEFont;
+
+class CFX_TextPiece {
+ public:
+  CFX_TextPiece();
+  ~CFX_TextPiece();
+
+  WideString szText;
+  std::vector<int32_t> Widths;
+  int32_t iChars;
+  int32_t iHorScale;
+  int32_t iVerScale;
+  int32_t iBidiLevel;
+  float fFontSize;
+  CFX_RectF rtPiece;
+  RetainPtr<CFGAS_GEFont> pFont;
+};
+
+#endif  // XFA_FGAS_LAYOUT_CFX_TEXTPIECE_H_
diff --git a/xfa/fxfa/cxfa_textuserdata.cpp b/xfa/fgas/layout/cfx_textuserdata.cpp
similarity index 68%
rename from xfa/fxfa/cxfa_textuserdata.cpp
rename to xfa/fgas/layout/cfx_textuserdata.cpp
index 6c46978..f5151bd 100644
--- a/xfa/fxfa/cxfa_textuserdata.cpp
+++ b/xfa/fgas/layout/cfx_textuserdata.cpp
@@ -4,20 +4,20 @@
 
 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
 
-#include "xfa/fxfa/cxfa_textuserdata.h"
+#include "xfa/fgas/layout/cfx_textuserdata.h"
 
 #include "core/fxcrt/css/cfx_css.h"
 #include "core/fxcrt/css/cfx_csscomputedstyle.h"
 #include "core/fxcrt/css/cfx_cssstyleselector.h"
-#include "xfa/fxfa/cxfa_linkuserdata.h"
+#include "xfa/fgas/layout/cfx_linkuserdata.h"
 
-CXFA_TextUserData::CXFA_TextUserData(
+CFX_TextUserData::CFX_TextUserData(
     const RetainPtr<CFX_CSSComputedStyle>& pStyle)
     : m_pStyle(pStyle) {}
 
-CXFA_TextUserData::CXFA_TextUserData(
+CFX_TextUserData::CFX_TextUserData(
     const RetainPtr<CFX_CSSComputedStyle>& pStyle,
-    const RetainPtr<CXFA_LinkUserData>& pLinkData)
+    const RetainPtr<CFX_LinkUserData>& pLinkData)
     : m_pStyle(pStyle), m_pLinkData(pLinkData) {}
 
-CXFA_TextUserData::~CXFA_TextUserData() {}
+CFX_TextUserData::~CFX_TextUserData() {}
diff --git a/xfa/fgas/layout/cfx_textuserdata.h b/xfa/fgas/layout/cfx_textuserdata.h
new file mode 100644
index 0000000..d5aaed9
--- /dev/null
+++ b/xfa/fgas/layout/cfx_textuserdata.h
@@ -0,0 +1,30 @@
+// 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_FGAS_LAYOUT_CFX_TEXTUSERDATA_H_
+#define XFA_FGAS_LAYOUT_CFX_TEXTUSERDATA_H_
+
+#include "core/fxcrt/retain_ptr.h"
+
+class CFX_CSSComputedStyle;
+class CFX_LinkUserData;
+
+class CFX_TextUserData final : public Retainable {
+ public:
+  template <typename T, typename... Args>
+  friend RetainPtr<T> pdfium::MakeRetain(Args&&... args);
+
+  RetainPtr<CFX_CSSComputedStyle> m_pStyle;
+  RetainPtr<CFX_LinkUserData> m_pLinkData;
+
+ private:
+  explicit CFX_TextUserData(const RetainPtr<CFX_CSSComputedStyle>& pStyle);
+  CFX_TextUserData(const RetainPtr<CFX_CSSComputedStyle>& pStyle,
+                   const RetainPtr<CFX_LinkUserData>& pLinkData);
+  ~CFX_TextUserData() override;
+};
+
+#endif  // XFA_FGAS_LAYOUT_CFX_TEXTUSERDATA_H_
diff --git a/xfa/fgas/layout/cfx_txtbreak.cpp b/xfa/fgas/layout/cfx_txtbreak.cpp
index b028c9b..4b87728 100644
--- a/xfa/fgas/layout/cfx_txtbreak.cpp
+++ b/xfa/fgas/layout/cfx_txtbreak.cpp
@@ -8,19 +8,20 @@
 
 #include <algorithm>
 
-#include "core/fxcrt/fx_arabic.h"
-#include "core/fxcrt/fx_bidi.h"
-#include "core/fxcrt/fx_memory.h"
-#include "third_party/base/ptr_util.h"
-#include "xfa/fde/cfde_texteditengine.h"
+#include "build/build_config.h"
+#include "core/fxcrt/fx_safe_types.h"
+#include "core/fxge/text_char_pos.h"
+#include "third_party/base/stl_util.h"
 #include "xfa/fgas/font/cfgas_gefont.h"
-#include "xfa/fgas/layout/cfx_linebreak.h"
+#include "xfa/fgas/layout/cfx_char.h"
+#include "xfa/fgas/layout/fx_arabic.h"
+#include "xfa/fgas/layout/fx_linebreak.h"
 
 namespace {
 
-bool IsCtrlCode(wchar_t ch) {
-  uint32_t dwRet = (FX_GetUnicodeProperties(ch) & FX_CHARTYPEBITSMASK);
-  return dwRet == FX_CHARTYPE_Tab || dwRet == FX_CHARTYPE_Control;
+bool IsCtrlCode(wchar_t wch) {
+  FX_CHARTYPE dwRet = FX_GetCharType(wch);
+  return dwRet == FX_CHARTYPE::kTab || dwRet == FX_CHARTYPE::kControl;
 }
 
 }  // namespace
@@ -33,24 +34,24 @@
 CFX_TxtBreak::~CFX_TxtBreak() {}
 
 void CFX_TxtBreak::SetLineWidth(float fLineWidth) {
-  m_iLineWidth = FXSYS_round(fLineWidth * 20000.0f);
+  m_iLineWidth = FXSYS_roundf(fLineWidth * kConversionFactor);
   ASSERT(m_iLineWidth >= 20000);
 }
 
 void CFX_TxtBreak::SetAlignment(int32_t iAlignment) {
-  ASSERT(iAlignment >= CFX_TxtLineAlignment_Left &&
-         iAlignment <= CFX_TxtLineAlignment_Justified);
+  ASSERT(iAlignment >= CFX_TxtLineAlignment_Left);
+  ASSERT(iAlignment <= CFX_TxtLineAlignment_Justified);
   m_iAlignment = iAlignment;
 }
 
 void CFX_TxtBreak::SetCombWidth(float fCombWidth) {
-  m_iCombWidth = FXSYS_round(fCombWidth * 20000.0f);
+  m_iCombWidth = FXSYS_roundf(fCombWidth * kConversionFactor);
 }
 
 void CFX_TxtBreak::AppendChar_Combination(CFX_Char* pCurChar) {
   wchar_t wch = pCurChar->char_code();
   wchar_t wForm;
-  int32_t iCharWidth = 0;
+  FX_SAFE_INT32 iCharWidth = 0;
   pCurChar->m_iCharWidth = -1;
   if (m_bCombText) {
     iCharWidth = m_iCombWidth;
@@ -78,21 +79,27 @@
         pCurChar->m_dwCharStyles |= FX_TXTCHARSTYLE_ArabicShadda;
       }
     }
-    if (!m_pFont->GetCharWidth(wForm, iCharWidth))
+    int32_t iCharWidthOut;
+    if (m_pFont && m_pFont->GetCharWidth(wForm, &iCharWidthOut))
+      iCharWidth = iCharWidthOut;
+    else
       iCharWidth = 0;
 
     iCharWidth *= m_iFontSize;
-    iCharWidth = iCharWidth * m_iHorizontalScale / 100;
+    iCharWidth *= m_iHorizontalScale;
+    iCharWidth /= 100;
   }
-  pCurChar->m_iCharWidth = -iCharWidth;
+
+  iCharWidth *= -1;
+  pCurChar->m_iCharWidth = iCharWidth.ValueOrDefault(0);
 }
 
 void CFX_TxtBreak::AppendChar_Tab(CFX_Char* pCurChar) {
-  m_eCharType = FX_CHARTYPE_Tab;
+  m_eCharType = FX_CHARTYPE::kTab;
 }
 
 CFX_BreakType CFX_TxtBreak::AppendChar_Control(CFX_Char* pCurChar) {
-  m_eCharType = FX_CHARTYPE_Control;
+  m_eCharType = FX_CHARTYPE::kControl;
   CFX_BreakType dwRet = CFX_BreakType::None;
   if (!m_bSingleLine) {
     wchar_t wch = pCurChar->char_code();
@@ -122,52 +129,65 @@
   FX_CHARTYPE chartype = pCurChar->GetCharType();
   int32_t& iLineWidth = m_pCurLine->m_iWidth;
   wchar_t wForm;
-  int32_t iCharWidth = 0;
   CFX_Char* pLastChar = nullptr;
   bool bAlef = false;
-  if (!m_bCombText && m_eCharType >= FX_CHARTYPE_ArabicAlef &&
-      m_eCharType <= FX_CHARTYPE_ArabicDistortion) {
+  if (!m_bCombText && m_eCharType >= FX_CHARTYPE::kArabicAlef &&
+      m_eCharType <= FX_CHARTYPE::kArabicDistortion) {
+    FX_SAFE_INT32 iCharWidth = 0;
     pLastChar = GetLastChar(1, true, false);
     if (pLastChar) {
+      if (pLastChar->m_iCharWidth > 0)
+        iLineWidth -= pLastChar->m_iCharWidth;
       iCharWidth = pLastChar->m_iCharWidth;
-      if (iCharWidth > 0)
-        iLineWidth -= iCharWidth;
 
       CFX_Char* pPrevChar = GetLastChar(2, true, false);
       wForm = pdfium::arabic::GetFormChar(pLastChar, pPrevChar, pCurChar);
       bAlef = (wForm == 0xFEFF &&
-               pLastChar->GetCharType() == FX_CHARTYPE_ArabicAlef);
-      m_pFont->GetCharWidth(wForm, iCharWidth);
-
+               pLastChar->GetCharType() == FX_CHARTYPE::kArabicAlef);
+      if (m_pFont) {
+        int32_t iCharWidthOut = 0;
+        m_pFont->GetCharWidth(wForm, &iCharWidthOut);
+        iCharWidth = iCharWidthOut;
+      }
       if (wForm == 0xFEFF)
-        iCharWidth = m_iDefChar;
+        iCharWidth = 0;
 
       iCharWidth *= m_iFontSize;
-      iCharWidth = iCharWidth * m_iHorizontalScale / 100;
-      pLastChar->m_iCharWidth = iCharWidth;
-      iLineWidth += iCharWidth;
-      iCharWidth = 0;
+      iCharWidth *= m_iHorizontalScale;
+      iCharWidth /= 100;
+
+      int32_t iCharWidthValid = iCharWidth.ValueOrDefault(0);
+      pLastChar->m_iCharWidth = iCharWidthValid;
+      iLineWidth += iCharWidthValid;
     }
   }
 
   m_eCharType = chartype;
   wForm = pdfium::arabic::GetFormChar(pCurChar, bAlef ? nullptr : pLastChar,
                                       nullptr);
+  FX_SAFE_INT32 iCharWidth = 0;
   if (m_bCombText) {
     iCharWidth = m_iCombWidth;
   } else {
-    m_pFont->GetCharWidth(wForm, iCharWidth);
-
+    if (m_pFont) {
+      int32_t iCharWidthOut = 0;
+      m_pFont->GetCharWidth(wForm, &iCharWidthOut);
+      iCharWidth = iCharWidthOut;
+    }
     if (wForm == 0xFEFF)
-      iCharWidth = m_iDefChar;
+      iCharWidth = 0;
 
     iCharWidth *= m_iFontSize;
-    iCharWidth = iCharWidth * m_iHorizontalScale / 100;
+    iCharWidth *= m_iHorizontalScale;
+    iCharWidth /= 100;
   }
-  pCurChar->m_iCharWidth = iCharWidth;
-  iLineWidth += iCharWidth;
-  m_pCurLine->m_iArabicChars++;
-  if (!m_bSingleLine && iLineWidth > m_iLineWidth + m_iTolerance)
+
+  int32_t iCharWidthValid = iCharWidth.ValueOrDefault(0);
+  pCurChar->m_iCharWidth = iCharWidthValid;
+  iLineWidth += iCharWidthValid;
+
+  m_pCurLine->IncrementArabicCharCount();
+  if (!m_bSingleLine && IsGreaterThanLineWidth(iLineWidth))
     return EndBreak(CFX_BreakType::Line);
   return CFX_BreakType::None;
 }
@@ -175,7 +195,7 @@
 CFX_BreakType CFX_TxtBreak::AppendChar_Others(CFX_Char* pCurChar) {
   FX_CHARTYPE chartype = pCurChar->GetCharType();
   int32_t& iLineWidth = m_pCurLine->m_iWidth;
-  int32_t iCharWidth = 0;
+  FX_SAFE_INT32 iCharWidth = 0;
   m_eCharType = chartype;
   wchar_t wch = pCurChar->char_code();
   wchar_t wForm = wch;
@@ -183,18 +203,24 @@
   if (m_bCombText) {
     iCharWidth = m_iCombWidth;
   } else {
-    if (!m_pFont->GetCharWidth(wForm, iCharWidth))
-      iCharWidth = m_iDefChar;
+    int32_t iCharWidthOut;
+    if (m_pFont && m_pFont->GetCharWidth(wForm, &iCharWidthOut))
+      iCharWidth = iCharWidthOut;
+    else
+      iCharWidth = 0;
 
     iCharWidth *= m_iFontSize;
-    iCharWidth = iCharWidth * m_iHorizontalScale / 100;
+    iCharWidth *= m_iHorizontalScale;
+    iCharWidth /= 100;
   }
 
   iCharWidth += m_iCharSpace;
-  pCurChar->m_iCharWidth = iCharWidth;
-  iLineWidth += iCharWidth;
-  if (!m_bSingleLine && chartype != FX_CHARTYPE_Space &&
-      iLineWidth > m_iLineWidth + m_iTolerance) {
+
+  int32_t iCharWidthValid = iCharWidth.ValueOrDefault(0);
+  pCurChar->m_iCharWidth = iCharWidthValid;
+  iLineWidth += iCharWidthValid;
+  if (!m_bSingleLine && chartype != FX_CHARTYPE::kSpace &&
+      IsGreaterThanLineWidth(iLineWidth)) {
     return EndBreak(CFX_BreakType::Line);
   }
 
@@ -202,23 +228,22 @@
 }
 
 CFX_BreakType CFX_TxtBreak::AppendChar(wchar_t wch) {
-  uint32_t dwProps = FX_GetUnicodeProperties(wch);
-  FX_CHARTYPE chartype = GetCharTypeFromProp(dwProps);
-  m_pCurLine->m_LineChars.emplace_back(wch, dwProps, m_iHorizontalScale,
+  FX_CHARTYPE chartype = FX_GetCharType(wch);
+  m_pCurLine->m_LineChars.emplace_back(wch, m_iHorizontalScale,
                                        m_iVerticalScale);
   CFX_Char* pCurChar = &m_pCurLine->m_LineChars.back();
   pCurChar->m_dwCharStyles = m_iAlignment | (1 << 8);
 
   CFX_BreakType dwRet1 = CFX_BreakType::None;
-  if (chartype != FX_CHARTYPE_Combination &&
+  if (chartype != FX_CHARTYPE::kCombination &&
       GetUnifiedCharType(m_eCharType) != GetUnifiedCharType(chartype) &&
-      m_eCharType != FX_CHARTYPE_Unknown &&
-      m_pCurLine->m_iWidth > m_iLineWidth + m_iTolerance && !m_bSingleLine &&
-      (m_eCharType != FX_CHARTYPE_Space || chartype != FX_CHARTYPE_Control)) {
+      m_eCharType != FX_CHARTYPE::kUnknown && !m_bSingleLine &&
+      IsGreaterThanLineWidth(m_pCurLine->m_iWidth) &&
+      (m_eCharType != FX_CHARTYPE::kSpace ||
+       chartype != FX_CHARTYPE::kControl)) {
     dwRet1 = EndBreak(CFX_BreakType::Line);
-    int32_t iCount = m_pCurLine->CountChars();
-    if (iCount > 0)
-      pCurChar = &m_pCurLine->m_LineChars[iCount - 1];
+    if (!m_pCurLine->m_LineChars.empty())
+      pCurChar = &m_pCurLine->m_LineChars.back();
   }
 
   CFX_BreakType dwRet2 = CFX_BreakType::None;
@@ -227,29 +252,30 @@
     // don't get matched as control characters so we go into AppendChar_other
     // and never detect the new paragraph ...
     dwRet2 = CFX_BreakType::Paragraph;
+    EndBreak(dwRet2);
   } else {
     switch (chartype) {
-      case FX_CHARTYPE_Tab:
+      case FX_CHARTYPE::kTab:
         AppendChar_Tab(pCurChar);
         break;
-      case FX_CHARTYPE_Control:
+      case FX_CHARTYPE::kControl:
         dwRet2 = AppendChar_Control(pCurChar);
         break;
-      case FX_CHARTYPE_Combination:
+      case FX_CHARTYPE::kCombination:
         AppendChar_Combination(pCurChar);
         break;
-      case FX_CHARTYPE_ArabicAlef:
-      case FX_CHARTYPE_ArabicSpecial:
-      case FX_CHARTYPE_ArabicDistortion:
-      case FX_CHARTYPE_ArabicNormal:
-      case FX_CHARTYPE_ArabicForm:
-      case FX_CHARTYPE_Arabic:
+      case FX_CHARTYPE::kArabicAlef:
+      case FX_CHARTYPE::kArabicSpecial:
+      case FX_CHARTYPE::kArabicDistortion:
+      case FX_CHARTYPE::kArabicNormal:
+      case FX_CHARTYPE::kArabicForm:
+      case FX_CHARTYPE::kArabic:
         dwRet2 = AppendChar_Arabic(pCurChar);
         break;
-      case FX_CHARTYPE_Unknown:
-      case FX_CHARTYPE_Space:
-      case FX_CHARTYPE_Numeric:
-      case FX_CHARTYPE_Normal:
+      case FX_CHARTYPE::kUnknown:
+      case FX_CHARTYPE::kSpace:
+      case FX_CHARTYPE::kNumeric:
+      case FX_CHARTYPE::kNormal:
       default:
         dwRet2 = AppendChar_Others(pCurChar);
         break;
@@ -260,28 +286,26 @@
 
 bool CFX_TxtBreak::EndBreak_SplitLine(CFX_BreakLine* pNextLine,
                                       bool bAllChars) {
-  int32_t iCount = m_pCurLine->CountChars();
   bool bDone = false;
   CFX_Char* pTC;
-  if (!m_bSingleLine && m_pCurLine->m_iWidth > m_iLineWidth + m_iTolerance) {
-    pTC = m_pCurLine->GetChar(iCount - 1);
+  if (!m_bSingleLine && IsGreaterThanLineWidth(m_pCurLine->m_iWidth)) {
+    pTC = m_pCurLine->GetChar(m_pCurLine->m_LineChars.size() - 1);
     switch (pTC->GetCharType()) {
-      case FX_CHARTYPE_Tab:
-      case FX_CHARTYPE_Control:
-      case FX_CHARTYPE_Space:
+      case FX_CHARTYPE::kTab:
+      case FX_CHARTYPE::kControl:
+      case FX_CHARTYPE::kSpace:
         break;
       default:
-        SplitTextLine(m_pCurLine, pNextLine, bAllChars);
+        SplitTextLine(m_pCurLine.Get(), pNextLine, bAllChars);
         bDone = true;
         break;
     }
   }
 
-  iCount = m_pCurLine->CountChars();
   CFX_BreakPiece tp;
   if (bAllChars && !bDone) {
     int32_t iEndPos = m_pCurLine->m_iWidth;
-    GetBreakPos(m_pCurLine->m_LineChars, iEndPos, bAllChars, true);
+    GetBreakPos(&m_pCurLine->m_LineChars, bAllChars, true, &iEndPos);
   }
   return false;
 }
@@ -292,96 +316,12 @@
   FX_TPO tpo;
   CFX_Char* pTC;
   std::vector<CFX_Char>& chars = m_pCurLine->m_LineChars;
-  int32_t iCount = m_pCurLine->CountChars();
-  bool bDone = m_pCurLine->m_iArabicChars > 0;
-  if (bDone) {
-    ASSERT(iCount >= 0);
-
-    size_t iBidiNum = 0;
-    for (size_t i = 0; i < static_cast<size_t>(iCount); ++i) {
-      pTC = &chars[i];
-      pTC->m_iBidiPos = static_cast<int32_t>(i);
-      if (pTC->GetCharType() != FX_CHARTYPE_Control)
-        iBidiNum = i;
-      if (i == 0)
-        pTC->m_iBidiLevel = 1;
-    }
-    FX_BidiLine(&chars, iBidiNum + 1);
-  }
-
-  if (bDone) {
-    tp.m_dwStatus = CFX_BreakType::Piece;
-    tp.m_iStartPos = m_pCurLine->m_iStart;
-    tp.m_pChars = &m_pCurLine->m_LineChars;
-    int32_t iBidiLevel = -1;
-    int32_t iCharWidth;
-    int32_t i = 0;
-    int32_t j = -1;
-    while (i < iCount) {
-      pTC = &chars[i];
-      if (iBidiLevel < 0) {
-        iBidiLevel = pTC->m_iBidiLevel;
-        tp.m_iWidth = 0;
-        tp.m_iBidiLevel = iBidiLevel;
-        tp.m_iBidiPos = pTC->m_iBidiOrder;
-        tp.m_dwCharStyles = pTC->m_dwCharStyles;
-        tp.m_iHorizontalScale = pTC->horizonal_scale();
-        tp.m_iVerticalScale = pTC->vertical_scale();
-        tp.m_dwStatus = CFX_BreakType::Piece;
-      }
-      if (iBidiLevel != pTC->m_iBidiLevel ||
-          pTC->m_dwStatus != CFX_BreakType::None) {
-        if (iBidiLevel == pTC->m_iBidiLevel) {
-          tp.m_dwStatus = pTC->m_dwStatus;
-          iCharWidth = pTC->m_iCharWidth;
-          if (iCharWidth > 0)
-            tp.m_iWidth += iCharWidth;
-
-          i++;
-        }
-        tp.m_iChars = i - tp.m_iStartChar;
-        m_pCurLine->m_LinePieces.push_back(tp);
-        tp.m_iStartPos += tp.m_iWidth;
-        tp.m_iStartChar = i;
-        tpo.index = ++j;
-        tpo.pos = tp.m_iBidiPos;
-        tpos->push_back(tpo);
-        iBidiLevel = -1;
-      } else {
-        iCharWidth = pTC->m_iCharWidth;
-        if (iCharWidth > 0)
-          tp.m_iWidth += iCharWidth;
-
-        i++;
-      }
-    }
-    if (i > tp.m_iStartChar) {
-      tp.m_dwStatus = dwStatus;
-      tp.m_iChars = i - tp.m_iStartChar;
-      m_pCurLine->m_LinePieces.push_back(tp);
-      tpo.index = ++j;
-      tpo.pos = tp.m_iBidiPos;
-      tpos->push_back(tpo);
-    }
-    if (j > -1) {
-      if (j > 0) {
-        std::sort(tpos->begin(), tpos->end());
-        int32_t iStartPos = 0;
-        for (i = 0; i <= j; i++) {
-          tpo = (*tpos)[i];
-          CFX_BreakPiece& ttp = m_pCurLine->m_LinePieces[tpo.index];
-          ttp.m_iStartPos = iStartPos;
-          iStartPos += ttp.m_iWidth;
-        }
-      }
-      m_pCurLine->m_LinePieces[j].m_dwStatus = dwStatus;
-    }
-  } else {
+  if (!m_pCurLine->HasArabicChar()) {
     tp.m_dwStatus = dwStatus;
     tp.m_iStartPos = m_pCurLine->m_iStart;
     tp.m_iWidth = m_pCurLine->m_iWidth;
     tp.m_iStartChar = 0;
-    tp.m_iChars = iCount;
+    tp.m_iChars = m_pCurLine->m_LineChars.size();
     tp.m_pChars = &m_pCurLine->m_LineChars;
     pTC = &chars[0];
     tp.m_dwCharStyles = pTC->m_dwCharStyles;
@@ -389,6 +329,86 @@
     tp.m_iVerticalScale = pTC->vertical_scale();
     m_pCurLine->m_LinePieces.push_back(tp);
     tpos->push_back({0, 0});
+    return;
+  }
+
+  size_t iBidiNum = 0;
+  for (size_t i = 0; i < m_pCurLine->m_LineChars.size(); ++i) {
+    pTC = &chars[i];
+    pTC->m_iBidiPos = static_cast<int32_t>(i);
+    if (pTC->GetCharType() != FX_CHARTYPE::kControl)
+      iBidiNum = i;
+    if (i == 0)
+      pTC->m_iBidiLevel = 1;
+  }
+  CFX_Char::BidiLine(&chars, iBidiNum + 1);
+
+  tp.m_dwStatus = CFX_BreakType::Piece;
+  tp.m_iStartPos = m_pCurLine->m_iStart;
+  tp.m_pChars = &m_pCurLine->m_LineChars;
+  int32_t iBidiLevel = -1;
+  int32_t iCharWidth;
+  int32_t i = 0;
+  int32_t j = -1;
+  int32_t iCount = pdfium::CollectionSize<int32_t>(m_pCurLine->m_LineChars);
+  while (i < iCount) {
+    pTC = &chars[i];
+    if (iBidiLevel < 0) {
+      iBidiLevel = pTC->m_iBidiLevel;
+      tp.m_iWidth = 0;
+      tp.m_iBidiLevel = iBidiLevel;
+      tp.m_iBidiPos = pTC->m_iBidiOrder;
+      tp.m_dwCharStyles = pTC->m_dwCharStyles;
+      tp.m_iHorizontalScale = pTC->horizonal_scale();
+      tp.m_iVerticalScale = pTC->vertical_scale();
+      tp.m_dwStatus = CFX_BreakType::Piece;
+    }
+    if (iBidiLevel != pTC->m_iBidiLevel ||
+        pTC->m_dwStatus != CFX_BreakType::None) {
+      if (iBidiLevel == pTC->m_iBidiLevel) {
+        tp.m_dwStatus = pTC->m_dwStatus;
+        iCharWidth = pTC->m_iCharWidth;
+        if (iCharWidth > 0)
+          tp.m_iWidth += iCharWidth;
+
+        i++;
+      }
+      tp.m_iChars = i - tp.m_iStartChar;
+      m_pCurLine->m_LinePieces.push_back(tp);
+      tp.m_iStartPos += tp.m_iWidth;
+      tp.m_iStartChar = i;
+      tpo.index = ++j;
+      tpo.pos = tp.m_iBidiPos;
+      tpos->push_back(tpo);
+      iBidiLevel = -1;
+    } else {
+      iCharWidth = pTC->m_iCharWidth;
+      if (iCharWidth > 0)
+        tp.m_iWidth += iCharWidth;
+
+      i++;
+    }
+  }
+  if (i > tp.m_iStartChar) {
+    tp.m_dwStatus = dwStatus;
+    tp.m_iChars = i - tp.m_iStartChar;
+    m_pCurLine->m_LinePieces.push_back(tp);
+    tpo.index = ++j;
+    tpo.pos = tp.m_iBidiPos;
+    tpos->push_back(tpo);
+  }
+  if (j > -1) {
+    if (j > 0) {
+      std::sort(tpos->begin(), tpos->end());
+      int32_t iStartPos = 0;
+      for (i = 0; i <= j; i++) {
+        tpo = (*tpos)[i];
+        CFX_BreakPiece& ttp = m_pCurLine->m_LinePieces[tpo.index];
+        ttp.m_iStartPos = iStartPos;
+        iStartPos += ttp.m_iWidth;
+      }
+    }
+    m_pCurLine->m_LinePieces[j].m_dwStatus = dwStatus;
   }
 }
 
@@ -407,11 +427,12 @@
     int32_t j = bArabic ? 0 : ttp.m_iChars - 1;
     while (j > -1 && j < ttp.m_iChars) {
       const CFX_Char* pTC = ttp.GetChar(j);
-      if (pTC->m_nBreakType == FX_LBT_DIRECT_BRK)
+      if (pTC->m_eLineBreakType == FX_LINEBREAKTYPE::kDIRECT_BRK)
         iGapChars++;
       if (!bFind || !bAllChars) {
         FX_CHARTYPE chartype = pTC->GetCharType();
-        if (chartype == FX_CHARTYPE_Space || chartype == FX_CHARTYPE_Control) {
+        if (chartype == FX_CHARTYPE::kSpace ||
+            chartype == FX_CHARTYPE::kControl) {
           if (!bFind && bAllChars && pTC->m_iCharWidth > 0)
             iNetWidth -= pTC->m_iCharWidth;
         } else {
@@ -437,18 +458,16 @@
       else
         ttp.m_iStartPos = iStart;
 
-      for (int32_t j = 0; j < ttp.m_iChars; j++) {
+      for (int32_t j = 0; j < ttp.m_iChars && iGapChars > 0; j++, iGapChars--) {
         CFX_Char* pTC = ttp.GetChar(j);
-        if (pTC->m_nBreakType != FX_LBT_DIRECT_BRK || pTC->m_iCharWidth < 0)
+        if (pTC->m_eLineBreakType != FX_LINEBREAKTYPE::kDIRECT_BRK ||
+            pTC->m_iCharWidth < 0) {
           continue;
-
+        }
         int32_t k = iOffset / iGapChars;
         pTC->m_iCharWidth += k;
         ttp.m_iWidth += k;
         iOffset -= k;
-        iGapChars--;
-        if (iGapChars < 1)
-          break;
       }
       iStart += ttp.m_iWidth;
     }
@@ -475,24 +494,23 @@
   }
 
   if (HasLine()) {
-    if (!m_Line[m_iReadyLineIndex].m_LinePieces.empty()) {
-      if (dwStatus != CFX_BreakType::Piece)
-        m_Line[m_iReadyLineIndex].m_LinePieces.back().m_dwStatus = dwStatus;
-      return m_Line[m_iReadyLineIndex].m_LinePieces.back().m_dwStatus;
-    }
-    return CFX_BreakType::None;
+    if (m_Lines[m_iReadyLineIndex].m_LinePieces.empty())
+      return CFX_BreakType::None;
+
+    if (dwStatus != CFX_BreakType::Piece)
+      m_Lines[m_iReadyLineIndex].m_LinePieces.back().m_dwStatus = dwStatus;
+    return m_Lines[m_iReadyLineIndex].m_LinePieces.back().m_dwStatus;
   }
 
-  int32_t iCount = m_pCurLine->CountChars();
-  if (iCount < 1)
+  if (m_pCurLine->m_LineChars.empty())
     return CFX_BreakType::None;
 
-  m_pCurLine->GetChar(iCount - 1)->m_dwStatus = dwStatus;
+  m_pCurLine->m_LineChars.back().m_dwStatus = dwStatus;
   if (dwStatus == CFX_BreakType::Piece)
     return dwStatus;
 
-  m_iReadyLineIndex = m_pCurLine == &m_Line[0] ? 0 : 1;
-  CFX_BreakLine* pNextLine = &m_Line[1 - m_iReadyLineIndex];
+  m_iReadyLineIndex = m_pCurLine == &m_Lines[0] ? 0 : 1;
+  CFX_BreakLine* pNextLine = &m_Lines[1 - m_iReadyLineIndex];
   bool bAllChars = m_iAlignment > CFX_TxtLineAlignment_Right;
   if (!EndBreak_SplitLine(pNextLine, bAllChars)) {
     std::deque<FX_TPO> tpos;
@@ -503,16 +521,17 @@
 
   m_pCurLine = pNextLine;
   CFX_Char* pTC = GetLastChar(0, false, false);
-  m_eCharType = pTC ? pTC->GetCharType() : FX_CHARTYPE_Unknown;
+  m_eCharType = pTC ? pTC->GetCharType() : FX_CHARTYPE::kUnknown;
 
   return dwStatus;
 }
 
-int32_t CFX_TxtBreak::GetBreakPos(std::vector<CFX_Char>& ca,
-                                  int32_t& iEndPos,
+int32_t CFX_TxtBreak::GetBreakPos(std::vector<CFX_Char>* pChars,
                                   bool bAllChars,
-                                  bool bOnlyBrk) {
-  int32_t iLength = pdfium::CollectionSize<int32_t>(ca) - 1;
+                                  bool bOnlyBrk,
+                                  int32_t* pEndPos) {
+  std::vector<CFX_Char>& chars = *pChars;
+  int32_t iLength = pdfium::CollectionSize<int32_t>(chars) - 1;
   if (iLength < 1)
     return iLength;
 
@@ -522,74 +541,71 @@
   int32_t iIndirectPos = -1;
   int32_t iLast = -1;
   int32_t iLastPos = -1;
-  if (m_bSingleLine || iEndPos <= m_iLineWidth) {
+  if (m_bSingleLine || *pEndPos <= m_iLineWidth) {
     if (!bAllChars)
       return iLength;
 
     iBreak = iLength;
-    iBreakPos = iEndPos;
+    iBreakPos = *pEndPos;
   }
 
   FX_LINEBREAKTYPE eType;
-  uint32_t nCodeProp;
-  uint32_t nCur;
-  uint32_t nNext;
-  CFX_Char* pCur = &ca[iLength--];
+  FX_BREAKPROPERTY nCur;
+  FX_BREAKPROPERTY nNext;
+  CFX_Char* pCur = &chars[iLength--];
   if (bAllChars)
-    pCur->m_nBreakType = FX_LBT_UNKNOWN;
+    pCur->m_eLineBreakType = FX_LINEBREAKTYPE::kUNKNOWN;
 
-  nCodeProp = pCur->char_props();
-  nNext = nCodeProp & 0x003F;
+  nNext = FX_GetBreakProperty(pCur->char_code());
   int32_t iCharWidth = pCur->m_iCharWidth;
   if (iCharWidth > 0)
-    iEndPos -= iCharWidth;
+    *pEndPos -= iCharWidth;
 
   while (iLength >= 0) {
-    pCur = &ca[iLength];
-    nCodeProp = pCur->char_props();
-    nCur = nCodeProp & 0x003F;
-    if (nNext == kBreakPropertySpace)
-      eType = FX_LBT_PROHIBITED_BRK;
+    pCur = &chars[iLength];
+    nCur = FX_GetBreakProperty(pCur->char_code());
+    if (nNext == FX_BREAKPROPERTY::kSP)
+      eType = FX_LINEBREAKTYPE::kPROHIBITED_BRK;
     else
-      eType = gs_FX_LineBreak_PairTable[nCur][nNext];
+      eType = GetLineBreakTypeFromPair(nCur, nNext);
     if (bAllChars)
-      pCur->m_nBreakType = static_cast<uint8_t>(eType);
+      pCur->m_eLineBreakType = eType;
     if (!bOnlyBrk) {
-      if (m_bSingleLine || iEndPos <= m_iLineWidth ||
-          nCur == kBreakPropertySpace) {
-        if (eType == FX_LBT_DIRECT_BRK && iBreak < 0) {
+      if (m_bSingleLine || *pEndPos <= m_iLineWidth ||
+          nCur == FX_BREAKPROPERTY::kSP) {
+        if (eType == FX_LINEBREAKTYPE::kDIRECT_BRK && iBreak < 0) {
           iBreak = iLength;
-          iBreakPos = iEndPos;
+          iBreakPos = *pEndPos;
           if (!bAllChars)
             return iLength;
-        } else if (eType == FX_LBT_INDIRECT_BRK && iIndirect < 0) {
+        } else if (eType == FX_LINEBREAKTYPE::kINDIRECT_BRK && iIndirect < 0) {
           iIndirect = iLength;
-          iIndirectPos = iEndPos;
+          iIndirectPos = *pEndPos;
         }
         if (iLast < 0) {
           iLast = iLength;
-          iLastPos = iEndPos;
+          iLastPos = *pEndPos;
         }
       }
       iCharWidth = pCur->m_iCharWidth;
       if (iCharWidth > 0)
-        iEndPos -= iCharWidth;
+        *pEndPos -= iCharWidth;
     }
-    nNext = nCodeProp & 0x003F;
+    nNext = nCur;
     iLength--;
   }
   if (bOnlyBrk)
     return 0;
   if (iBreak > -1) {
-    iEndPos = iBreakPos;
+    *pEndPos = iBreakPos;
     return iBreak;
   }
   if (iIndirect > -1) {
-    iEndPos = iIndirectPos;
+    *pEndPos = iIndirectPos;
     return iIndirect;
   }
   if (iLast > -1) {
-    iEndPos = iLastPos;
+    *pEndPos = iLastPos;
     return iLast;
   }
   return 0;
@@ -598,22 +614,23 @@
 void CFX_TxtBreak::SplitTextLine(CFX_BreakLine* pCurLine,
                                  CFX_BreakLine* pNextLine,
                                  bool bAllChars) {
-  ASSERT(pCurLine && pNextLine);
-  int32_t iCount = pCurLine->CountChars();
-  if (iCount < 2)
+  ASSERT(pCurLine);
+  ASSERT(pNextLine);
+
+  if (pCurLine->m_LineChars.size() < 2)
     return;
 
   int32_t iEndPos = pCurLine->m_iWidth;
   std::vector<CFX_Char>& curChars = pCurLine->m_LineChars;
-  int32_t iCharPos = GetBreakPos(curChars, iEndPos, bAllChars, false);
+  int32_t iCharPos = GetBreakPos(&curChars, bAllChars, false, &iEndPos);
   if (iCharPos < 0)
     iCharPos = 0;
 
   iCharPos++;
-  if (iCharPos >= iCount) {
+  if (iCharPos >= pdfium::CollectionSize<int32_t>(pCurLine->m_LineChars)) {
     pNextLine->Clear();
     CFX_Char* pTC = &curChars[iCharPos - 1];
-    pTC->m_nBreakType = FX_LBT_UNKNOWN;
+    pTC->m_eLineBreakType = FX_LINEBREAKTYPE::kUNKNOWN;
     return;
   }
 
@@ -622,13 +639,12 @@
   curChars.erase(curChars.begin() + iCharPos, curChars.end());
   pCurLine->m_iWidth = iEndPos;
   CFX_Char* pTC = &curChars[iCharPos - 1];
-  pTC->m_nBreakType = FX_LBT_UNKNOWN;
-  iCount = pdfium::CollectionSize<int>(pNextLine->m_LineChars);
+  pTC->m_eLineBreakType = FX_LINEBREAKTYPE::kUNKNOWN;
   int32_t iWidth = 0;
-  for (int32_t i = 0; i < iCount; i++) {
-    if (pNextLine->m_LineChars[i].GetCharType() >= FX_CHARTYPE_ArabicAlef) {
-      pCurLine->m_iArabicChars--;
-      pNextLine->m_iArabicChars++;
+  for (size_t i = 0; i < pNextLine->m_LineChars.size(); ++i) {
+    if (pNextLine->m_LineChars[i].GetCharType() >= FX_CHARTYPE::kArabicAlef) {
+      pCurLine->DecrementArabicCharCount();
+      pNextLine->IncrementArabicCharCount();
     }
     iWidth += std::max(0, pNextLine->m_LineChars[i].m_iCharWidth);
     pNextLine->m_LineChars[i].m_dwStatus = CFX_BreakType::None;
@@ -642,12 +658,12 @@
   int32_t iWidth;
 };
 
-int32_t CFX_TxtBreak::GetDisplayPos(const FX_TXTRUN* pTxtRun,
-                                    FXTEXT_CHARPOS* pCharPos) const {
+size_t CFX_TxtBreak::GetDisplayPos(const Run* pTxtRun,
+                                   TextCharPos* pCharPos) const {
   if (!pTxtRun || pTxtRun->iLength < 1)
     return 0;
 
-  CFDE_TextEditEngine* pEngine = pTxtRun->pEdtEngine;
+  Engine* pEngine = pTxtRun->pEdtEngine;
   const wchar_t* pStr = pTxtRun->wsStr.c_str();
   int32_t* pWidths = pTxtRun->pWidths;
   int32_t iLength = pTxtRun->iLength - 1;
@@ -656,12 +672,12 @@
   CFX_RectF rtText(*pTxtRun->pRect);
   bool bRTLPiece = (pTxtRun->dwCharStyles & FX_TXTCHARSTYLE_OddBidiLevel) != 0;
   float fFontSize = pTxtRun->fFontSize;
-  int32_t iFontSize = FXSYS_round(fFontSize * 20.0f);
+  int32_t iFontSize = FXSYS_roundf(fFontSize * 20.0f);
   int32_t iAscent = pFont->GetAscent();
   int32_t iDescent = pFont->GetDescent();
   int32_t iMaxHeight = iAscent - iDescent;
   float fFontHeight = fFontSize;
-  float fAscent = fFontHeight * (float)iAscent / (float)iMaxHeight;
+  float fAscent = fFontHeight * iAscent / iMaxHeight;
   float fX = rtText.left;
   float fY;
   float fCharWidth;
@@ -677,7 +693,7 @@
   fYBase = rtText.top + (rtText.height - fFontSize) / 2.0f;
   fY = fYBase + fAscent;
 
-  int32_t iCount = 0;
+  size_t szCount = 0;
   int32_t iNext = 0;
   wchar_t wPrev = 0xFEFF;
   wchar_t wNext = 0xFEFF;
@@ -686,32 +702,32 @@
   bool bShadda = false;
   bool bLam = false;
   for (int32_t i = 0; i <= iLength; i++) {
+    int32_t iAbsolute = i + pTxtRun->iStart;
     int32_t iWidth;
     wchar_t wch;
     if (pEngine) {
-      wch = pEngine->GetChar(i);
-      iWidth = pEngine->GetWidthOfChar(i);
+      wch = pEngine->GetChar(iAbsolute);
+      iWidth = pEngine->GetWidthOfChar(iAbsolute);
     } else {
       wch = *pStr++;
       iWidth = *pWidths++;
     }
 
-    uint32_t dwProps = FX_GetUnicodeProperties(wch);
-    FX_CHARTYPE chartype = GetCharTypeFromProp(dwProps);
-    if (chartype == FX_CHARTYPE_ArabicAlef && iWidth == 0) {
+    FX_CHARTYPE chartype = FX_GetCharType(wch);
+    if (chartype == FX_CHARTYPE::kArabicAlef && iWidth == 0) {
       wPrev = 0xFEFF;
       wLast = wch;
       continue;
     }
 
-    if (chartype >= FX_CHARTYPE_ArabicAlef) {
+    if (chartype >= FX_CHARTYPE::kArabicAlef) {
       if (i < iLength) {
         if (pEngine) {
           iNext = i + 1;
           while (iNext <= iLength) {
-            wNext = pEngine->GetChar(iNext);
-            dwProps = FX_GetUnicodeProperties(wNext);
-            if ((dwProps & FX_CHARTYPEBITSMASK) != FX_CHARTYPE_Combination)
+            int32_t iNextAbsolute = iNext + pTxtRun->iStart;
+            wNext = pEngine->GetChar(iNextAbsolute);
+            if (FX_GetCharType(wNext) != FX_CHARTYPE::kCombination)
               break;
 
             iNext++;
@@ -726,8 +742,7 @@
               break;
 
             wNext = pStr[j];
-            dwProps = FX_GetUnicodeProperties(wNext);
-          } while ((dwProps & FX_CHARTYPEBITSMASK) == FX_CHARTYPE_Combination);
+          } while (FX_GetCharType(wNext) == FX_CHARTYPE::kCombination);
           if (i + j >= iLength)
             wNext = 0xFEFF;
         }
@@ -737,7 +752,7 @@
 
       wForm = pdfium::arabic::GetFormChar(wch, wPrev, wNext);
       bLam = (wPrev == 0x0644 && wch == 0x0644 && wNext == 0x0647);
-    } else if (chartype == FX_CHARTYPE_Combination) {
+    } else if (chartype == FX_CHARTYPE::kCombination) {
       wForm = wch;
       if (wch >= 0x064C && wch <= 0x0651) {
         if (bShadda) {
@@ -747,8 +762,10 @@
           wNext = 0xFEFF;
           if (pEngine) {
             iNext = i + 1;
-            if (iNext <= iLength)
-              wNext = pEngine->GetChar(iNext);
+            if (iNext <= iLength) {
+              int32_t iNextAbsolute = iNext + pTxtRun->iStart;
+              wNext = pEngine->GetChar(iNextAbsolute);
+            }
           } else {
             if (i < iLength)
               wNext = *pStr;
@@ -768,30 +785,29 @@
       } else {
         bShadda = false;
       }
-    } else if (chartype == FX_CHARTYPE_Numeric) {
+    } else if (chartype == FX_CHARTYPE::kNumeric) {
       wForm = wch;
     } else if (wch == L'.') {
       wForm = wch;
     } else if (wch == L',') {
       wForm = wch;
     } else if (bRTLPiece) {
-      wForm = FX_GetMirrorChar(wch, dwProps);
+      wForm = FX_GetMirrorChar(wch);
     } else {
       wForm = wch;
     }
-    if (chartype != FX_CHARTYPE_Combination)
+    if (chartype != FX_CHARTYPE::kCombination)
       bShadda = false;
-    if (chartype < FX_CHARTYPE_ArabicAlef)
+    if (chartype < FX_CHARTYPE::kArabicAlef)
       bLam = false;
 
-    dwProps = FX_GetUnicodeProperties(wForm);
     bool bEmptyChar =
-        (chartype >= FX_CHARTYPE_Tab && chartype <= FX_CHARTYPE_Control);
+        (chartype >= FX_CHARTYPE::kTab && chartype <= FX_CHARTYPE::kControl);
     if (wForm == 0xFEFF)
       bEmptyChar = true;
 
     int32_t iForms = bLam ? 3 : 1;
-    iCount += (bEmptyChar && bSkipSpace) ? 0 : iForms;
+    szCount += (bEmptyChar && bSkipSpace) ? 0 : iForms;
     if (!pCharPos) {
       if (iWidth > 0)
         wPrev = wch;
@@ -810,11 +826,11 @@
     if (bLam) {
       formChars[1].wForm = 0x0651;
       iCharWidth = 0;
-      pFont->GetCharWidth(0x0651, iCharWidth);
+      pFont->GetCharWidth(0x0651, &iCharWidth);
       formChars[1].iWidth = iCharWidth;
       formChars[2].wForm = 0x0670;
       iCharWidth = 0;
-      pFont->GetCharWidth(0x0670, iCharWidth);
+      pFont->GetCharWidth(0x0670, &iCharWidth);
       formChars[2].iWidth = iCharWidth;
     }
 
@@ -822,20 +838,22 @@
       wForm = (wchar_t)formChars[j].wForm;
       iCharWidth = formChars[j].iWidth;
       if (j > 0) {
-        chartype = FX_CHARTYPE_Combination;
+        chartype = FX_CHARTYPE::kCombination;
         wch = wForm;
         wLast = (wchar_t)formChars[j - 1].wForm;
       }
       if (!bEmptyChar || (bEmptyChar && !bSkipSpace)) {
         pCharPos->m_GlyphIndex = pFont->GetGlyphIndex(wForm);
-#if _FX_PLATFORM_ == _FX_PLATFORM_APPLE_
+#if defined(OS_MACOSX)
         pCharPos->m_ExtGID = pCharPos->m_GlyphIndex;
 #endif
+        // TODO(npm): change widths in this method to unsigned to avoid implicit
+        // cast in the following line.
         pCharPos->m_FontCharWidth = iCharWidth;
       }
 
       fCharWidth = fFontSize * iCharWidth / 1000.0f;
-      if (bRTLPiece && chartype != FX_CHARTYPE_Combination)
+      if (bRTLPiece && chartype != FX_CHARTYPE::kCombination)
         fX -= fCharWidth;
 
       if (!bEmptyChar || (bEmptyChar && !bSkipSpace)) {
@@ -843,30 +861,27 @@
 
         if ((dwStyles & FX_LAYOUTSTYLE_CombText) != 0) {
           int32_t iFormWidth = iCharWidth;
-          pFont->GetCharWidth(wForm, iFormWidth);
+          pFont->GetCharWidth(wForm, &iFormWidth);
           float fOffset = fFontSize * (iCharWidth - iFormWidth) / 2000.0f;
           pCharPos->m_Origin.x += fOffset;
         }
 
-        if (chartype == FX_CHARTYPE_Combination) {
-          CFX_Rect rtBBox;
+        if (chartype == FX_CHARTYPE::kCombination) {
+          FX_RECT rtBBox;
           if (pFont->GetCharBBox(wForm, &rtBBox)) {
             pCharPos->m_Origin.y =
-                fYBase + fFontSize -
-                fFontSize * (float)rtBBox.height / (float)iMaxHeight;
+                fYBase + fFontSize - fFontSize * rtBBox.Height() / iMaxHeight;
           }
           if (wForm == wch && wLast != 0xFEFF) {
-            uint32_t dwLastProps = FX_GetUnicodeProperties(wLast);
-            if ((dwLastProps & FX_CHARTYPEBITSMASK) ==
-                FX_CHARTYPE_Combination) {
-              CFX_Rect rtBox;
+            if (FX_GetCharType(wLast) == FX_CHARTYPE::kCombination) {
+              FX_RECT rtBox;
               if (pFont->GetCharBBox(wLast, &rtBox))
-                pCharPos->m_Origin.y -= fFontSize * rtBox.height / iMaxHeight;
+                pCharPos->m_Origin.y -= fFontSize * rtBox.Height() / iMaxHeight;
             }
           }
         }
       }
-      if (!bRTLPiece && chartype != FX_CHARTYPE_Combination)
+      if (!bRTLPiece && chartype != FX_CHARTYPE::kCombination)
         fX += fCharWidth;
 
       if (!bEmptyChar || (bEmptyChar && !bSkipSpace)) {
@@ -893,32 +908,31 @@
       wPrev = static_cast<wchar_t>(formChars[0].wch);
     wLast = wch;
   }
-  return iCount;
+  return szCount;
 }
 
-std::vector<CFX_RectF> CFX_TxtBreak::GetCharRects(const FX_TXTRUN* pTxtRun,
+std::vector<CFX_RectF> CFX_TxtBreak::GetCharRects(const Run* pTxtRun,
                                                   bool bCharBBox) const {
   if (!pTxtRun || pTxtRun->iLength < 1)
     return std::vector<CFX_RectF>();
 
-  CFDE_TextEditEngine* pEngine = pTxtRun->pEdtEngine;
+  Engine* pEngine = pTxtRun->pEdtEngine;
   const wchar_t* pStr = pTxtRun->wsStr.c_str();
   int32_t* pWidths = pTxtRun->pWidths;
   int32_t iLength = pTxtRun->iLength;
   CFX_RectF rect(*pTxtRun->pRect);
   float fFontSize = pTxtRun->fFontSize;
-  int32_t iFontSize = FXSYS_round(fFontSize * 20.0f);
   float fScale = fFontSize / 1000.0f;
   RetainPtr<CFGAS_GEFont> pFont = pTxtRun->pFont;
   if (!pFont)
     bCharBBox = false;
 
-  CFX_Rect bbox;
+  FX_RECT bbox;
   if (bCharBBox)
     bCharBBox = pFont->GetBBox(&bbox);
 
   float fLeft = std::max(0.0f, bbox.left * fScale);
-  float fHeight = fabs(bbox.height * fScale);
+  float fHeight = fabs(bbox.Height() * fScale);
   bool bRTLPiece = !!(pTxtRun->dwCharStyles & FX_TXTCHARSTYLE_OddBidiLevel);
   bool bSingleLine = !!(pTxtRun->dwStyles & FX_LAYOUTSTYLE_SingleLine);
   bool bCombText = !!(pTxtRun->dwStyles & FX_LAYOUTSTYLE_CombText);
@@ -929,23 +943,22 @@
 
   std::vector<CFX_RectF> rtArray(iLength);
   for (int32_t i = 0; i < iLength; i++) {
+    int32_t iAbsolute = i + pTxtRun->iStart;
     if (pEngine) {
-      wch = pEngine->GetChar(i);
-      iCharSize = pEngine->GetWidthOfChar(i);
+      wch = pEngine->GetChar(iAbsolute);
+      iCharSize = pEngine->GetWidthOfChar(iAbsolute);
     } else {
       wch = *pStr++;
       iCharSize = *pWidths++;
     }
-    fCharSize = static_cast<float>(iCharSize) / 20000.0f;
+    fCharSize = static_cast<float>(iCharSize) / kConversionFactor;
     bool bRet = (!bSingleLine && IsCtrlCode(wch));
     if (!(wch == L'\v' || wch == L'\f' || wch == 0x2028 || wch == 0x2029 ||
           wch == L'\n')) {
       bRet = false;
     }
-    if (bRet) {
-      iCharSize = iFontSize * 500;
+    if (bRet)
       fCharSize = fFontSize / 2.0f;
-    }
     rect.left = fStart;
     if (bRTLPiece) {
       rect.left -= fCharSize;
@@ -957,7 +970,7 @@
 
     if (bCharBBox && !bRet) {
       int32_t iCharWidth = 1000;
-      pFont->GetCharWidth(wch, iCharWidth);
+      pFont->GetCharWidth(wch, &iCharWidth);
       float fRTLeft = 0, fCharWidth = 0;
       if (iCharWidth > 0) {
         fCharWidth = iCharWidth * fScale;
@@ -979,20 +992,10 @@
   return rtArray;
 }
 
-FX_TXTRUN::FX_TXTRUN()
-    : pEdtEngine(nullptr),
-      pIdentity(nullptr),
-      pWidths(nullptr),
-      iLength(0),
-      pFont(nullptr),
-      fFontSize(12),
-      dwStyles(0),
-      iHorizontalScale(100),
-      iVerticalScale(100),
-      dwCharStyles(0),
-      pRect(nullptr),
-      bSkipSpace(true) {}
+CFX_TxtBreak::Engine::~Engine() = default;
 
-FX_TXTRUN::~FX_TXTRUN() {}
+CFX_TxtBreak::Run::Run() = default;
 
-FX_TXTRUN::FX_TXTRUN(const FX_TXTRUN& other) = default;
+CFX_TxtBreak::Run::~Run() = default;
+
+CFX_TxtBreak::Run::Run(const CFX_TxtBreak::Run& other) = default;
diff --git a/xfa/fgas/layout/cfx_txtbreak.h b/xfa/fgas/layout/cfx_txtbreak.h
index e6f8da0..7f3d4ac 100644
--- a/xfa/fgas/layout/cfx_txtbreak.h
+++ b/xfa/fgas/layout/cfx_txtbreak.h
@@ -8,17 +8,14 @@
 #define XFA_FGAS_LAYOUT_CFX_TXTBREAK_H_
 
 #include <deque>
-#include <memory>
 #include <vector>
 
-#include "core/fxcrt/cfx_char.h"
-#include "core/fxge/cfx_renderdevice.h"
-#include "third_party/base/stl_util.h"
+#include "core/fxcrt/fx_coordinates.h"
 #include "xfa/fgas/layout/cfx_break.h"
+#include "xfa/fgas/layout/cfx_char.h"
 
-class CFDE_TextEditEngine;
 class CFGAS_GEFont;
-struct FDE_TEXTEDITPIECE;
+class TextCharPos;
 
 #define FX_TXTCHARSTYLE_ArabicShadda 0x0020
 #define FX_TXTCHARSTYLE_OddBidiLevel 0x0040
@@ -34,28 +31,36 @@
   return type == CFX_BreakType::None || type == CFX_BreakType::Piece;
 }
 
-struct FX_TXTRUN {
-  FX_TXTRUN();
-  FX_TXTRUN(const FX_TXTRUN& other);
-  ~FX_TXTRUN();
-
-  CFDE_TextEditEngine* pEdtEngine;
-  const FDE_TEXTEDITPIECE* pIdentity;
-  WideString wsStr;
-  int32_t* pWidths;
-  int32_t iLength;
-  RetainPtr<CFGAS_GEFont> pFont;
-  float fFontSize;
-  uint32_t dwStyles;
-  int32_t iHorizontalScale;
-  int32_t iVerticalScale;
-  uint32_t dwCharStyles;
-  const CFX_RectF* pRect;
-  bool bSkipSpace;
-};
-
-class CFX_TxtBreak : public CFX_Break {
+class CFX_TxtBreak final : public CFX_Break {
  public:
+  class Engine {
+   public:
+    virtual ~Engine();
+    virtual wchar_t GetChar(size_t idx) const = 0;
+    // Non-const so we can force a layout if needed.
+    virtual size_t GetWidthOfChar(size_t idx) = 0;
+  };
+
+  struct Run {
+    Run();
+    Run(const Run& other);
+    ~Run();
+
+    CFX_TxtBreak::Engine* pEdtEngine = nullptr;
+    WideString wsStr;
+    int32_t* pWidths = nullptr;
+    int32_t iStart = 0;
+    int32_t iLength = 0;
+    RetainPtr<CFGAS_GEFont> pFont;
+    float fFontSize = 12.0f;
+    uint32_t dwStyles = 0;
+    int32_t iHorizontalScale = 100;
+    int32_t iVerticalScale = 100;
+    uint32_t dwCharStyles = 0;
+    const CFX_RectF* pRect = nullptr;
+    bool bSkipSpace = true;
+  };
+
   CFX_TxtBreak();
   ~CFX_TxtBreak() override;
 
@@ -64,10 +69,8 @@
   void SetCombWidth(float fCombWidth);
   CFX_BreakType EndBreak(CFX_BreakType dwStatus);
 
-  int32_t GetDisplayPos(const FX_TXTRUN* pTxtRun,
-                        FXTEXT_CHARPOS* pCharPos) const;
-  std::vector<CFX_RectF> GetCharRects(const FX_TXTRUN* pTxtRun,
-                                      bool bCharBBox = false) const;
+  size_t GetDisplayPos(const Run* pTxtRun, TextCharPos* pCharPos) const;
+  std::vector<CFX_RectF> GetCharRects(const Run* pTxtRun, bool bCharBBox) const;
   CFX_BreakType AppendChar(wchar_t wch);
 
  private:
@@ -83,13 +86,13 @@
   void EndBreak_Alignment(const std::deque<FX_TPO>& tpos,
                           bool bAllChars,
                           CFX_BreakType dwStatus);
-  int32_t GetBreakPos(std::vector<CFX_Char>& ca,
-                      int32_t& iEndPos,
-                      bool bAllChars = false,
-                      bool bOnlyBrk = false);
+  int32_t GetBreakPos(std::vector<CFX_Char>* pChars,
+                      bool bAllChars,
+                      bool bOnlyBrk,
+                      int32_t* pEndPos);
   void SplitTextLine(CFX_BreakLine* pCurLine,
                      CFX_BreakLine* pNextLine,
-                     bool bAllChars = false);
+                     bool bAllChars);
 
   int32_t m_iAlignment;
   int32_t m_iCombWidth;
diff --git a/xfa/fgas/layout/cfx_txtbreak_unittest.cpp b/xfa/fgas/layout/cfx_txtbreak_unittest.cpp
new file mode 100644
index 0000000..a3ae207
--- /dev/null
+++ b/xfa/fgas/layout/cfx_txtbreak_unittest.cpp
@@ -0,0 +1,49 @@
+// Copyright 2018 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/fgas/layout/cfx_txtbreak.h"
+
+#include <memory>
+#include <utility>
+
+#include "core/fxge/cfx_font.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/xfa_unit_test_support.h"
+#include "third_party/base/ptr_util.h"
+#include "xfa/fgas/font/cfgas_fontmgr.h"
+#include "xfa/fgas/font/cfgas_gefont.h"
+#include "xfa/fgas/layout/cfx_char.h"
+
+class CFX_TxtBreakTest : public testing::Test {
+ public:
+  void SetUp() override {
+    font_ =
+        CFGAS_GEFont::LoadFont(L"Arial Black", 0, 0, GetGlobalFontManager());
+    ASSERT_TRUE(font_.Get());
+  }
+
+  std::unique_ptr<CFX_TxtBreak> CreateBreak() {
+    auto txt_break = pdfium::MakeUnique<CFX_TxtBreak>();
+    txt_break->SetFont(font_);
+    return txt_break;
+  }
+
+ private:
+  RetainPtr<CFGAS_GEFont> font_;
+};
+
+TEST_F(CFX_TxtBreakTest, BidiLine) {
+  auto txt_break = CreateBreak();
+  txt_break->SetLineBreakTolerance(1);
+  txt_break->SetFontSize(12);
+
+  WideString input = WideString::FromUTF8(ByteStringView("\xa\x0\xa\xa", 4));
+  for (wchar_t ch : input)
+    txt_break->AppendChar(ch);
+
+  std::vector<CFX_Char> chars =
+      txt_break->GetCurrentLineForTesting()->m_LineChars;
+  CFX_Char::BidiLine(&chars, chars.size());
+  EXPECT_EQ(3u, chars.size());
+}
diff --git a/xfa/fgas/layout/fx_arabic.cpp b/xfa/fgas/layout/fx_arabic.cpp
new file mode 100644
index 0000000..886bb0d
--- /dev/null
+++ b/xfa/fgas/layout/fx_arabic.cpp
@@ -0,0 +1,231 @@
+// Copyright 2014 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
+
+#include "xfa/fgas/layout/fx_arabic.h"
+
+#include <algorithm>
+#include <vector>
+
+#include "core/fxcrt/fx_memory.h"
+#include "core/fxcrt/fx_unicode.h"
+
+namespace {
+
+struct FX_ARBFORMTABLE {
+  uint16_t wIsolated;
+  uint16_t wFinal;
+  uint16_t wInitial;
+  uint16_t wMedial;
+};
+
+struct FX_ARAALEF {
+  uint16_t wAlef;
+  uint16_t wIsolated;
+};
+
+struct FX_ARASHADDA {
+  uint16_t wShadda;
+  uint16_t wIsolated;
+};
+
+const FX_ARBFORMTABLE g_FX_ArabicFormTables[] = {
+    {0xFE81, 0xFE82, 0xFE81, 0xFE82}, {0xFE83, 0xFE84, 0xFE83, 0xFE84},
+    {0xFE85, 0xFE86, 0xFE85, 0xFE86}, {0xFE87, 0xFE88, 0xFE87, 0xFE88},
+    {0xFE89, 0xFE8A, 0xFE8B, 0xFE8C}, {0xFE8D, 0xFE8E, 0xFE8D, 0xFE8E},
+    {0xFE8F, 0xFE90, 0xFE91, 0xFE92}, {0xFE93, 0xFE94, 0xFE93, 0xFE94},
+    {0xFE95, 0xFE96, 0xFE97, 0xFE98}, {0xFE99, 0xFE9A, 0xFE9B, 0xFE9C},
+    {0xFE9D, 0xFE9E, 0xFE9F, 0xFEA0}, {0xFEA1, 0xFEA2, 0xFEA3, 0xFEA4},
+    {0xFEA5, 0xFEA6, 0xFEA7, 0xFEA8}, {0xFEA9, 0xFEAA, 0xFEA9, 0xFEAA},
+    {0xFEAB, 0xFEAC, 0xFEAB, 0xFEAC}, {0xFEAD, 0xFEAE, 0xFEAD, 0xFEAE},
+    {0xFEAF, 0xFEB0, 0xFEAF, 0xFEB0}, {0xFEB1, 0xFEB2, 0xFEB3, 0xFEB4},
+    {0xFEB5, 0xFEB6, 0xFEB7, 0xFEB8}, {0xFEB9, 0xFEBA, 0xFEBB, 0xFEBC},
+    {0xFEBD, 0xFEBE, 0xFEBF, 0xFEC0}, {0xFEC1, 0xFEC2, 0xFEC3, 0xFEC4},
+    {0xFEC5, 0xFEC6, 0xFEC7, 0xFEC8}, {0xFEC9, 0xFECA, 0xFECB, 0xFECC},
+    {0xFECD, 0xFECE, 0xFECF, 0xFED0}, {0x063B, 0x063B, 0x063B, 0x063B},
+    {0x063C, 0x063C, 0x063C, 0x063C}, {0x063D, 0x063D, 0x063D, 0x063D},
+    {0x063E, 0x063E, 0x063E, 0x063E}, {0x063F, 0x063F, 0x063F, 0x063F},
+    {0x0640, 0x0640, 0x0640, 0x0640}, {0xFED1, 0xFED2, 0xFED3, 0xFED4},
+    {0xFED5, 0xFED6, 0xFED7, 0xFED8}, {0xFED9, 0xFEDA, 0xFEDB, 0xFEDC},
+    {0xFEDD, 0xFEDE, 0xFEDF, 0xFEE0}, {0xFEE1, 0xFEE2, 0xFEE3, 0xFEE4},
+    {0xFEE5, 0xFEE6, 0xFEE7, 0xFEE8}, {0xFEE9, 0xFEEA, 0xFEEB, 0xFEEC},
+    {0xFEED, 0xFEEE, 0xFEED, 0xFEEE}, {0xFEEF, 0xFEF0, 0xFBFE, 0xFBFF},
+    {0xFEF1, 0xFEF2, 0xFEF3, 0xFEF4}, {0x064B, 0x064B, 0x064B, 0x064B},
+    {0x064C, 0x064C, 0x064C, 0x064C}, {0x064D, 0x064D, 0x064D, 0x064D},
+    {0x064E, 0x064E, 0x064E, 0x064E}, {0x064F, 0x064F, 0x064F, 0x064F},
+    {0x0650, 0x0650, 0x0650, 0x0650}, {0x0651, 0x0651, 0x0651, 0x0651},
+    {0x0652, 0x0652, 0x0652, 0x0652}, {0x0653, 0x0653, 0x0653, 0x0653},
+    {0x0654, 0x0654, 0x0654, 0x0654}, {0x0655, 0x0655, 0x0655, 0x0655},
+    {0x0656, 0x0656, 0x0656, 0x0656}, {0x0657, 0x0657, 0x0657, 0x0657},
+    {0x0658, 0x0658, 0x0658, 0x0658}, {0x0659, 0x0659, 0x0659, 0x0659},
+    {0x065A, 0x065A, 0x065A, 0x065A}, {0x065B, 0x065B, 0x065B, 0x065B},
+    {0x065C, 0x065C, 0x065C, 0x065C}, {0x065D, 0x065D, 0x065D, 0x065D},
+    {0x065E, 0x065E, 0x065E, 0x065E}, {0x065F, 0x065F, 0x065F, 0x065F},
+    {0x0660, 0x0660, 0x0660, 0x0660}, {0x0661, 0x0661, 0x0661, 0x0661},
+    {0x0662, 0x0662, 0x0662, 0x0662}, {0x0663, 0x0663, 0x0663, 0x0663},
+    {0x0664, 0x0664, 0x0664, 0x0664}, {0x0665, 0x0665, 0x0665, 0x0665},
+    {0x0666, 0x0666, 0x0666, 0x0666}, {0x0667, 0x0667, 0x0667, 0x0667},
+    {0x0668, 0x0668, 0x0668, 0x0668}, {0x0669, 0x0669, 0x0669, 0x0669},
+    {0x066A, 0x066A, 0x066A, 0x066A}, {0x066B, 0x066B, 0x066B, 0x066B},
+    {0x066C, 0x066C, 0x066C, 0x066C}, {0x066D, 0x066D, 0x066D, 0x066D},
+    {0x066E, 0x066E, 0x066E, 0x066E}, {0x066F, 0x066F, 0x066F, 0x066F},
+    {0x0670, 0x0670, 0x0670, 0x0670}, {0xFB50, 0xFB51, 0xFB50, 0xFB51},
+    {0x0672, 0x0672, 0x0672, 0x0672}, {0x0673, 0x0673, 0x0673, 0x0673},
+    {0x0674, 0x0674, 0x0674, 0x0674}, {0x0675, 0x0675, 0x0675, 0x0675},
+    {0x0676, 0x0676, 0x0676, 0x0676}, {0x0677, 0x0677, 0x0677, 0x0677},
+    {0x0678, 0x0678, 0x0678, 0x0678}, {0xFB66, 0xFB67, 0xFB68, 0xFB69},
+    {0xFB5E, 0xFB5F, 0xFB60, 0xFB61}, {0xFB52, 0xFB53, 0xFB54, 0xFB55},
+    {0x067C, 0x067C, 0x067C, 0x067C}, {0x067D, 0x067D, 0x067D, 0x067D},
+    {0xFB56, 0xFB57, 0xFB58, 0xFB59}, {0xFB62, 0xFB63, 0xFB64, 0xFB65},
+    {0xFB5A, 0xFB5B, 0xFB5C, 0xFB5D}, {0x0681, 0x0681, 0x0681, 0x0681},
+    {0x0682, 0x0682, 0x0682, 0x0682}, {0xFB76, 0xFB77, 0xFB78, 0xFB79},
+    {0xFB72, 0xFB73, 0xFB74, 0xFB75}, {0x0685, 0x0685, 0x0685, 0x0685},
+    {0xFB7A, 0xFB7B, 0xFB7C, 0xFB7D}, {0xFB7E, 0xFB7F, 0xFB80, 0xFB81},
+    {0xFB88, 0xFB89, 0xFB88, 0xFB89}, {0x0689, 0x0689, 0x0689, 0x0689},
+    {0x068A, 0x068A, 0x068A, 0x068A}, {0x068B, 0x068B, 0x068B, 0x068B},
+    {0xFB84, 0xFB85, 0xFB84, 0xFB85}, {0xFB82, 0xFB83, 0xFB82, 0xFB83},
+    {0xFB86, 0xFB87, 0xFB86, 0xFB87}, {0x068F, 0x068F, 0x068F, 0x068F},
+    {0x0690, 0x0690, 0x0690, 0x0690}, {0xFB8C, 0xFB8D, 0xFB8C, 0xFB8D},
+    {0x0692, 0x0692, 0x0692, 0x0692}, {0x0693, 0x0693, 0x0693, 0x0693},
+    {0x0694, 0x0694, 0x0694, 0x0694}, {0x0695, 0x0695, 0x0695, 0x0695},
+    {0x0696, 0x0696, 0x0696, 0x0696}, {0x0697, 0x0697, 0x0697, 0x0697},
+    {0xFB8A, 0xFB8B, 0xFB8A, 0xFB8B}, {0x0699, 0x0699, 0x0699, 0x0699},
+    {0x069A, 0x069A, 0x069A, 0x069A}, {0x069B, 0x069B, 0x069B, 0x069B},
+    {0x069C, 0x069C, 0x069C, 0x069C}, {0x069D, 0x069D, 0x069D, 0x069D},
+    {0x069E, 0x069E, 0x069E, 0x069E}, {0x069F, 0x069F, 0x069F, 0x069F},
+    {0x06A0, 0x06A0, 0x06A0, 0x06A0}, {0x06A1, 0x06A1, 0x06A1, 0x06A1},
+    {0x06A2, 0x06A2, 0x06A2, 0x06A2}, {0x06A3, 0x06A3, 0x06A3, 0x06A3},
+    {0xFB6A, 0xFB6B, 0xFB6C, 0xFB6D}, {0x06A5, 0x06A5, 0x06A5, 0x06A5},
+    {0xFB6E, 0xFB6F, 0xFB70, 0xFB71}, {0x06A7, 0x06A7, 0x06A7, 0x06A7},
+    {0x06A8, 0x06A8, 0x06A8, 0x06A8}, {0xFB8E, 0xFB8F, 0xFB90, 0xFB91},
+    {0x06AA, 0x06AA, 0x06AA, 0x06AA}, {0x06AB, 0x06AB, 0x06AB, 0x06AB},
+    {0x06AC, 0x06AC, 0x06AC, 0x06AC}, {0xFBD3, 0xFBD4, 0xFBD5, 0xFBD6},
+    {0x06AE, 0x06AE, 0x06AE, 0x06AE}, {0xFB92, 0xFB93, 0xFB94, 0xFB95},
+    {0x06B0, 0x06B0, 0x06B0, 0x06B0}, {0xFB9A, 0xFB9B, 0xFB9C, 0xFB9D},
+    {0x06B2, 0x06B2, 0x06B2, 0x06B2}, {0xFB96, 0xFB97, 0xFB98, 0xFB99},
+    {0x06B4, 0x06B4, 0x06B4, 0x06B4}, {0x06B5, 0x06B5, 0x06B5, 0x06B5},
+    {0x06B6, 0x06B6, 0x06B6, 0x06B6}, {0x06B7, 0x06B7, 0x06B7, 0x06B7},
+    {0x06B8, 0x06B8, 0x06B8, 0x06B8}, {0x06B9, 0x06B9, 0x06B9, 0x06B9},
+    {0xFB9E, 0xFB9F, 0xFBE8, 0xFBE9}, {0xFBA0, 0xFBA1, 0xFBA2, 0xFBA3},
+    {0x06BC, 0x06BC, 0x06BC, 0x06BC}, {0x06BD, 0x06BD, 0x06BD, 0x06BD},
+    {0xFBAA, 0xFBAB, 0xFBAC, 0xFBAD}, {0x06BF, 0x06BF, 0x06BF, 0x06BF},
+    {0xFBA4, 0xFBA5, 0xFBA4, 0xFBA5}, {0xFBA6, 0xFBA7, 0xFBA8, 0xFBA9},
+    {0x06C2, 0x06C2, 0x06C2, 0x06C2}, {0x06C3, 0x06C3, 0x06C3, 0x06C3},
+    {0x06C4, 0x06C4, 0x06C4, 0x06C4}, {0xFBE0, 0xFBE1, 0xFBE0, 0xFBE1},
+    {0xFBD9, 0xFBDA, 0xFBD9, 0xFBDA}, {0xFBD7, 0xFBD8, 0xFBD7, 0xFBD8},
+    {0xFBDB, 0xFBDC, 0xFBDB, 0xFBDC}, {0xFBE2, 0xFBE3, 0xFBE2, 0xFBE3},
+    {0x06CA, 0x06CA, 0x06CA, 0x06CA}, {0xFBDE, 0xFBDF, 0xFBDE, 0xFBDF},
+    {0xFBFC, 0xFBFD, 0xFBFE, 0xFBFF}, {0x06CD, 0x06CD, 0x06CD, 0x06CD},
+    {0x06CE, 0x06CE, 0x06CE, 0x06CE}, {0x06CF, 0x06CF, 0x06CF, 0x06CF},
+    {0xFBE4, 0xFBE5, 0xFBE6, 0xFBE7}, {0x06D1, 0x06D1, 0x06D1, 0x06D1},
+    {0xFBAE, 0xFBAF, 0xFBAE, 0xFBAF}, {0xFBB0, 0xFBB1, 0xFBB0, 0xFBB1},
+    {0x06D4, 0x06D4, 0x06D4, 0x06D4}, {0x06D5, 0x06D5, 0x06D5, 0x06D5},
+};
+
+const FX_ARAALEF gs_FX_AlefTable[] = {
+    {0x0622, 0xFEF5},
+    {0x0623, 0xFEF7},
+    {0x0625, 0xFEF9},
+    {0x0627, 0xFEFB},
+};
+
+const FX_ARASHADDA gs_FX_ShaddaTable[] = {
+    {0x064C, 0xFC5E}, {0x064D, 0xFC5F}, {0x064E, 0xFC60},
+    {0x064F, 0xFC61}, {0x0650, 0xFC62},
+};
+
+const FX_ARBFORMTABLE* GetArabicFormTable(wchar_t unicode) {
+  if (unicode < 0x622 || unicode > 0x6d5)
+    return nullptr;
+  return g_FX_ArabicFormTables + unicode - 0x622;
+}
+
+const FX_ARBFORMTABLE* ParseChar(const CFX_Char* pTC,
+                                 wchar_t* wChar,
+                                 FX_CHARTYPE* eType) {
+  if (!pTC) {
+    *eType = FX_CHARTYPE::kUnknown;
+    *wChar = 0xFEFF;
+    return nullptr;
+  }
+
+  *eType = pTC->GetCharType();
+  *wChar = static_cast<wchar_t>(pTC->char_code());
+  const FX_ARBFORMTABLE* pFT = GetArabicFormTable(*wChar);
+  if (!pFT || *eType >= FX_CHARTYPE::kArabicNormal)
+    *eType = FX_CHARTYPE::kUnknown;
+
+  return pFT;
+}
+
+wchar_t GetArabicFromAlefTable(wchar_t alef) {
+  static const size_t s_iAlefCount = FX_ArraySize(gs_FX_AlefTable);
+  for (size_t iStart = 0; iStart < s_iAlefCount; iStart++) {
+    const FX_ARAALEF& v = gs_FX_AlefTable[iStart];
+    if (v.wAlef == alef)
+      return v.wIsolated;
+  }
+  return alef;
+}
+
+}  // namespace
+
+namespace pdfium {
+namespace arabic {
+
+wchar_t GetFormChar(wchar_t wch, wchar_t prev, wchar_t next) {
+  CFX_Char c(wch);
+  CFX_Char p(prev);
+  CFX_Char n(next);
+  return GetFormChar(&c, &p, &n);
+}
+
+wchar_t GetFormChar(const CFX_Char* cur,
+                    const CFX_Char* prev,
+                    const CFX_Char* next) {
+  FX_CHARTYPE eCur;
+  wchar_t wCur;
+  const FX_ARBFORMTABLE* ft = ParseChar(cur, &wCur, &eCur);
+  if (eCur < FX_CHARTYPE::kArabicAlef || eCur >= FX_CHARTYPE::kArabicNormal)
+    return wCur;
+
+  FX_CHARTYPE ePrev;
+  wchar_t wPrev;
+  ParseChar(prev, &wPrev, &ePrev);
+  if (wPrev == 0x0644 && eCur == FX_CHARTYPE::kArabicAlef)
+    return 0xFEFF;
+
+  FX_CHARTYPE eNext;
+  wchar_t wNext;
+  ParseChar(next, &wNext, &eNext);
+  bool bAlef = (eNext == FX_CHARTYPE::kArabicAlef && wCur == 0x644);
+  if (ePrev < FX_CHARTYPE::kArabicAlef) {
+    if (bAlef)
+      return GetArabicFromAlefTable(wNext);
+    return (eNext < FX_CHARTYPE::kArabicAlef) ? ft->wIsolated : ft->wInitial;
+  }
+
+  if (bAlef) {
+    wCur = GetArabicFromAlefTable(wNext);
+    return (ePrev != FX_CHARTYPE::kArabicDistortion) ? wCur : ++wCur;
+  }
+
+  if (ePrev == FX_CHARTYPE::kArabicAlef || ePrev == FX_CHARTYPE::kArabicSpecial)
+    return (eNext < FX_CHARTYPE::kArabicAlef) ? ft->wIsolated : ft->wInitial;
+  return (eNext < FX_CHARTYPE::kArabicAlef) ? ft->wFinal : ft->wMedial;
+}
+
+}  // namespace arabic
+}  // namespace pdfium
+
+wchar_t FX_GetArabicFromShaddaTable(wchar_t shadda) {
+  static const size_t s_iShaddaCount = FX_ArraySize(gs_FX_ShaddaTable);
+  for (size_t iStart = 0; iStart < s_iShaddaCount; iStart++) {
+    const FX_ARASHADDA& v = gs_FX_ShaddaTable[iStart];
+    if (v.wShadda == shadda)
+      return v.wIsolated;
+  }
+  return shadda;
+}
diff --git a/xfa/fgas/layout/fx_arabic.h b/xfa/fgas/layout/fx_arabic.h
new file mode 100644
index 0000000..ca33aa5
--- /dev/null
+++ b/xfa/fgas/layout/fx_arabic.h
@@ -0,0 +1,26 @@
+// Copyright 2014 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_FGAS_LAYOUT_FX_ARABIC_H_
+#define XFA_FGAS_LAYOUT_FX_ARABIC_H_
+
+#include "core/fxcrt/fx_system.h"
+#include "xfa/fgas/layout/cfx_char.h"
+
+namespace pdfium {
+namespace arabic {
+
+wchar_t GetFormChar(wchar_t wch, wchar_t prev, wchar_t next);
+wchar_t GetFormChar(const CFX_Char* cur,
+                    const CFX_Char* prev,
+                    const CFX_Char* next);
+
+}  // namespace arabic
+}  // namespace pdfium
+
+wchar_t FX_GetArabicFromShaddaTable(wchar_t shadda);
+
+#endif  // XFA_FGAS_LAYOUT_FX_ARABIC_H_
diff --git a/xfa/fgas/layout/fx_linebreak.cpp b/xfa/fgas/layout/fx_linebreak.cpp
new file mode 100644
index 0000000..96821f1
--- /dev/null
+++ b/xfa/fgas/layout/fx_linebreak.cpp
@@ -0,0 +1,232 @@
+// Copyright 2014 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
+
+#include "xfa/fgas/layout/fx_linebreak.h"
+
+#include "core/fxcrt/fx_memory.h"
+#include "core/fxcrt/fx_unicode.h"
+
+namespace {
+
+#define FX_LBUN FX_LINEBREAKTYPE::kUNKNOWN
+#define FX_LBDB FX_LINEBREAKTYPE::kDIRECT_BRK
+#define FX_LBIB FX_LINEBREAKTYPE::kINDIRECT_BRK
+#define FX_LBCB FX_LINEBREAKTYPE::kCOM_INDIRECT_BRK
+#define FX_LBCP FX_LINEBREAKTYPE::kCOM_PROHIBITED_BRK
+#define FX_LBPB FX_LINEBREAKTYPE::kPROHIBITED_BRK
+#define FX_LBHS FX_LINEBREAKTYPE::kHANGUL_SPACE_BRK
+
+const FX_LINEBREAKTYPE gs_FX_LineBreak_PairTable[38][38] = {
+    {FX_LBPB, FX_LBPB, FX_LBPB, FX_LBPB, FX_LBPB, FX_LBPB, FX_LBPB, FX_LBPB,
+     FX_LBPB, FX_LBPB, FX_LBPB, FX_LBPB, FX_LBPB, FX_LBPB, FX_LBPB, FX_LBPB,
+     FX_LBPB, FX_LBPB, FX_LBPB, FX_LBCP, FX_LBPB, FX_LBPB, FX_LBPB, FX_LBPB,
+     FX_LBPB, FX_LBPB, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN,
+     FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN},
+    {FX_LBDB, FX_LBPB, FX_LBIB, FX_LBIB, FX_LBPB, FX_LBPB, FX_LBPB, FX_LBPB,
+     FX_LBIB, FX_LBIB, FX_LBDB, FX_LBDB, FX_LBDB, FX_LBDB, FX_LBIB, FX_LBIB,
+     FX_LBDB, FX_LBDB, FX_LBPB, FX_LBCB, FX_LBPB, FX_LBDB, FX_LBDB, FX_LBDB,
+     FX_LBDB, FX_LBDB, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN,
+     FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN},
+    {FX_LBPB, FX_LBPB, FX_LBIB, FX_LBIB, FX_LBIB, FX_LBPB, FX_LBPB, FX_LBPB,
+     FX_LBIB, FX_LBIB, FX_LBIB, FX_LBIB, FX_LBIB, FX_LBIB, FX_LBIB, FX_LBIB,
+     FX_LBIB, FX_LBIB, FX_LBPB, FX_LBCB, FX_LBPB, FX_LBIB, FX_LBIB, FX_LBIB,
+     FX_LBIB, FX_LBIB, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN,
+     FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN},
+    {FX_LBIB, FX_LBPB, FX_LBIB, FX_LBIB, FX_LBIB, FX_LBPB, FX_LBPB, FX_LBPB,
+     FX_LBIB, FX_LBIB, FX_LBIB, FX_LBIB, FX_LBIB, FX_LBIB, FX_LBIB, FX_LBIB,
+     FX_LBIB, FX_LBIB, FX_LBPB, FX_LBCB, FX_LBPB, FX_LBIB, FX_LBIB, FX_LBIB,
+     FX_LBIB, FX_LBIB, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN,
+     FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN},
+    {FX_LBDB, FX_LBPB, FX_LBIB, FX_LBIB, FX_LBIB, FX_LBPB, FX_LBPB, FX_LBPB,
+     FX_LBDB, FX_LBDB, FX_LBDB, FX_LBDB, FX_LBDB, FX_LBDB, FX_LBIB, FX_LBIB,
+     FX_LBDB, FX_LBDB, FX_LBPB, FX_LBCB, FX_LBPB, FX_LBDB, FX_LBDB, FX_LBDB,
+     FX_LBDB, FX_LBDB, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN,
+     FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN},
+    {FX_LBDB, FX_LBPB, FX_LBIB, FX_LBIB, FX_LBIB, FX_LBPB, FX_LBPB, FX_LBPB,
+     FX_LBDB, FX_LBDB, FX_LBDB, FX_LBDB, FX_LBDB, FX_LBDB, FX_LBIB, FX_LBIB,
+     FX_LBDB, FX_LBDB, FX_LBPB, FX_LBCB, FX_LBPB, FX_LBDB, FX_LBDB, FX_LBDB,
+     FX_LBDB, FX_LBDB, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN,
+     FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN},
+    {FX_LBDB, FX_LBPB, FX_LBIB, FX_LBIB, FX_LBIB, FX_LBPB, FX_LBPB, FX_LBPB,
+     FX_LBDB, FX_LBDB, FX_LBIB, FX_LBDB, FX_LBDB, FX_LBDB, FX_LBIB, FX_LBIB,
+     FX_LBDB, FX_LBDB, FX_LBPB, FX_LBCB, FX_LBPB, FX_LBDB, FX_LBDB, FX_LBDB,
+     FX_LBDB, FX_LBDB, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN,
+     FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN},
+    {FX_LBDB, FX_LBPB, FX_LBIB, FX_LBIB, FX_LBIB, FX_LBPB, FX_LBPB, FX_LBPB,
+     FX_LBDB, FX_LBDB, FX_LBIB, FX_LBIB, FX_LBDB, FX_LBDB, FX_LBIB, FX_LBIB,
+     FX_LBDB, FX_LBDB, FX_LBPB, FX_LBCB, FX_LBPB, FX_LBDB, FX_LBDB, FX_LBDB,
+     FX_LBDB, FX_LBDB, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN,
+     FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN},
+    {FX_LBIB, FX_LBPB, FX_LBIB, FX_LBIB, FX_LBIB, FX_LBPB, FX_LBPB, FX_LBPB,
+     FX_LBDB, FX_LBDB, FX_LBIB, FX_LBIB, FX_LBIB, FX_LBDB, FX_LBIB, FX_LBIB,
+     FX_LBDB, FX_LBDB, FX_LBPB, FX_LBCB, FX_LBPB, FX_LBIB, FX_LBIB, FX_LBIB,
+     FX_LBIB, FX_LBIB, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN,
+     FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN},
+    {FX_LBIB, FX_LBPB, FX_LBIB, FX_LBIB, FX_LBIB, FX_LBPB, FX_LBPB, FX_LBPB,
+     FX_LBDB, FX_LBDB, FX_LBIB, FX_LBIB, FX_LBDB, FX_LBDB, FX_LBIB, FX_LBIB,
+     FX_LBDB, FX_LBDB, FX_LBPB, FX_LBCB, FX_LBPB, FX_LBDB, FX_LBDB, FX_LBDB,
+     FX_LBDB, FX_LBDB, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN,
+     FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN},
+    {FX_LBIB, FX_LBPB, FX_LBIB, FX_LBIB, FX_LBIB, FX_LBPB, FX_LBPB, FX_LBPB,
+     FX_LBIB, FX_LBIB, FX_LBIB, FX_LBIB, FX_LBDB, FX_LBIB, FX_LBIB, FX_LBIB,
+     FX_LBDB, FX_LBDB, FX_LBPB, FX_LBCB, FX_LBPB, FX_LBDB, FX_LBDB, FX_LBDB,
+     FX_LBDB, FX_LBDB, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN,
+     FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN},
+    {FX_LBIB, FX_LBPB, FX_LBIB, FX_LBIB, FX_LBIB, FX_LBPB, FX_LBPB, FX_LBPB,
+     FX_LBDB, FX_LBDB, FX_LBIB, FX_LBIB, FX_LBDB, FX_LBIB, FX_LBIB, FX_LBIB,
+     FX_LBDB, FX_LBDB, FX_LBPB, FX_LBCB, FX_LBPB, FX_LBDB, FX_LBDB, FX_LBDB,
+     FX_LBDB, FX_LBDB, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN,
+     FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN},
+    {FX_LBDB, FX_LBPB, FX_LBIB, FX_LBIB, FX_LBIB, FX_LBPB, FX_LBPB, FX_LBPB,
+     FX_LBDB, FX_LBIB, FX_LBDB, FX_LBDB, FX_LBDB, FX_LBIB, FX_LBIB, FX_LBIB,
+     FX_LBDB, FX_LBDB, FX_LBPB, FX_LBCB, FX_LBPB, FX_LBDB, FX_LBDB, FX_LBDB,
+     FX_LBDB, FX_LBDB, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN,
+     FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN},
+    {FX_LBDB, FX_LBPB, FX_LBIB, FX_LBIB, FX_LBIB, FX_LBPB, FX_LBPB, FX_LBPB,
+     FX_LBDB, FX_LBDB, FX_LBDB, FX_LBDB, FX_LBDB, FX_LBIB, FX_LBIB, FX_LBIB,
+     FX_LBDB, FX_LBDB, FX_LBPB, FX_LBCB, FX_LBPB, FX_LBDB, FX_LBDB, FX_LBDB,
+     FX_LBDB, FX_LBDB, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN,
+     FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN},
+    {FX_LBDB, FX_LBPB, FX_LBIB, FX_LBDB, FX_LBIB, FX_LBPB, FX_LBPB, FX_LBPB,
+     FX_LBDB, FX_LBDB, FX_LBIB, FX_LBDB, FX_LBDB, FX_LBDB, FX_LBIB, FX_LBIB,
+     FX_LBDB, FX_LBDB, FX_LBPB, FX_LBCB, FX_LBPB, FX_LBDB, FX_LBDB, FX_LBDB,
+     FX_LBDB, FX_LBDB, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN,
+     FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN},
+    {FX_LBDB, FX_LBPB, FX_LBIB, FX_LBDB, FX_LBIB, FX_LBPB, FX_LBPB, FX_LBPB,
+     FX_LBDB, FX_LBDB, FX_LBDB, FX_LBDB, FX_LBDB, FX_LBDB, FX_LBIB, FX_LBIB,
+     FX_LBDB, FX_LBDB, FX_LBPB, FX_LBCB, FX_LBPB, FX_LBDB, FX_LBDB, FX_LBDB,
+     FX_LBDB, FX_LBDB, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN,
+     FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN},
+    {FX_LBIB, FX_LBPB, FX_LBIB, FX_LBIB, FX_LBIB, FX_LBPB, FX_LBPB, FX_LBPB,
+     FX_LBIB, FX_LBIB, FX_LBIB, FX_LBIB, FX_LBIB, FX_LBIB, FX_LBIB, FX_LBIB,
+     FX_LBIB, FX_LBIB, FX_LBPB, FX_LBCB, FX_LBPB, FX_LBIB, FX_LBIB, FX_LBIB,
+     FX_LBIB, FX_LBIB, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN,
+     FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN},
+    {FX_LBDB, FX_LBPB, FX_LBIB, FX_LBIB, FX_LBIB, FX_LBPB, FX_LBPB, FX_LBPB,
+     FX_LBDB, FX_LBDB, FX_LBDB, FX_LBDB, FX_LBDB, FX_LBDB, FX_LBIB, FX_LBIB,
+     FX_LBDB, FX_LBPB, FX_LBPB, FX_LBCB, FX_LBPB, FX_LBDB, FX_LBDB, FX_LBDB,
+     FX_LBDB, FX_LBDB, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN,
+     FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN},
+    {FX_LBDB, FX_LBDB, FX_LBDB, FX_LBDB, FX_LBDB, FX_LBDB, FX_LBDB, FX_LBDB,
+     FX_LBDB, FX_LBDB, FX_LBDB, FX_LBDB, FX_LBDB, FX_LBDB, FX_LBDB, FX_LBDB,
+     FX_LBDB, FX_LBDB, FX_LBPB, FX_LBDB, FX_LBDB, FX_LBDB, FX_LBDB, FX_LBDB,
+     FX_LBDB, FX_LBDB, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN,
+     FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN},
+    {FX_LBDB, FX_LBPB, FX_LBIB, FX_LBIB, FX_LBIB, FX_LBPB, FX_LBPB, FX_LBPB,
+     FX_LBDB, FX_LBDB, FX_LBIB, FX_LBIB, FX_LBDB, FX_LBIB, FX_LBIB, FX_LBIB,
+     FX_LBDB, FX_LBDB, FX_LBPB, FX_LBCB, FX_LBPB, FX_LBDB, FX_LBDB, FX_LBDB,
+     FX_LBDB, FX_LBDB, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN,
+     FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN},
+    {FX_LBIB, FX_LBPB, FX_LBIB, FX_LBIB, FX_LBIB, FX_LBPB, FX_LBPB, FX_LBPB,
+     FX_LBIB, FX_LBIB, FX_LBIB, FX_LBIB, FX_LBIB, FX_LBIB, FX_LBIB, FX_LBIB,
+     FX_LBIB, FX_LBIB, FX_LBPB, FX_LBCB, FX_LBPB, FX_LBIB, FX_LBIB, FX_LBIB,
+     FX_LBIB, FX_LBIB, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN,
+     FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN},
+    {FX_LBDB, FX_LBPB, FX_LBIB, FX_LBIB, FX_LBIB, FX_LBPB, FX_LBPB, FX_LBPB,
+     FX_LBDB, FX_LBIB, FX_LBDB, FX_LBDB, FX_LBDB, FX_LBIB, FX_LBIB, FX_LBIB,
+     FX_LBDB, FX_LBDB, FX_LBPB, FX_LBCB, FX_LBPB, FX_LBDB, FX_LBDB, FX_LBDB,
+     FX_LBIB, FX_LBIB, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN,
+     FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN},
+    {FX_LBDB, FX_LBPB, FX_LBIB, FX_LBIB, FX_LBIB, FX_LBPB, FX_LBPB, FX_LBPB,
+     FX_LBDB, FX_LBIB, FX_LBDB, FX_LBDB, FX_LBDB, FX_LBIB, FX_LBIB, FX_LBIB,
+     FX_LBDB, FX_LBDB, FX_LBPB, FX_LBCB, FX_LBPB, FX_LBDB, FX_LBDB, FX_LBDB,
+     FX_LBDB, FX_LBIB, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN,
+     FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN},
+    {FX_LBDB, FX_LBPB, FX_LBIB, FX_LBIB, FX_LBIB, FX_LBPB, FX_LBPB, FX_LBPB,
+     FX_LBDB, FX_LBIB, FX_LBDB, FX_LBDB, FX_LBDB, FX_LBIB, FX_LBIB, FX_LBIB,
+     FX_LBDB, FX_LBDB, FX_LBPB, FX_LBCB, FX_LBPB, FX_LBIB, FX_LBIB, FX_LBIB,
+     FX_LBIB, FX_LBDB, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN,
+     FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN},
+    {FX_LBDB, FX_LBPB, FX_LBIB, FX_LBIB, FX_LBIB, FX_LBPB, FX_LBPB, FX_LBPB,
+     FX_LBDB, FX_LBIB, FX_LBDB, FX_LBDB, FX_LBDB, FX_LBIB, FX_LBIB, FX_LBIB,
+     FX_LBDB, FX_LBDB, FX_LBPB, FX_LBCB, FX_LBPB, FX_LBDB, FX_LBDB, FX_LBDB,
+     FX_LBIB, FX_LBIB, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN,
+     FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN},
+    {FX_LBDB, FX_LBPB, FX_LBIB, FX_LBIB, FX_LBIB, FX_LBPB, FX_LBPB, FX_LBPB,
+     FX_LBDB, FX_LBIB, FX_LBDB, FX_LBDB, FX_LBDB, FX_LBIB, FX_LBIB, FX_LBIB,
+     FX_LBDB, FX_LBDB, FX_LBPB, FX_LBCB, FX_LBPB, FX_LBDB, FX_LBDB, FX_LBDB,
+     FX_LBDB, FX_LBIB, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN,
+     FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN},
+    {FX_LBDB, FX_LBPB, FX_LBIB, FX_LBIB, FX_LBIB, FX_LBPB, FX_LBPB, FX_LBPB,
+     FX_LBDB, FX_LBIB, FX_LBDB, FX_LBDB, FX_LBDB, FX_LBIB, FX_LBIB, FX_LBIB,
+     FX_LBDB, FX_LBDB, FX_LBPB, FX_LBCB, FX_LBPB, FX_LBDB, FX_LBDB, FX_LBDB,
+     FX_LBDB, FX_LBDB, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN,
+     FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN},
+    {FX_LBDB, FX_LBPB, FX_LBIB, FX_LBIB, FX_LBIB, FX_LBPB, FX_LBPB, FX_LBPB,
+     FX_LBDB, FX_LBIB, FX_LBDB, FX_LBDB, FX_LBDB, FX_LBIB, FX_LBIB, FX_LBIB,
+     FX_LBDB, FX_LBDB, FX_LBPB, FX_LBCB, FX_LBPB, FX_LBDB, FX_LBDB, FX_LBDB,
+     FX_LBDB, FX_LBDB, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN,
+     FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN},
+    {FX_LBDB, FX_LBPB, FX_LBIB, FX_LBIB, FX_LBIB, FX_LBPB, FX_LBPB, FX_LBPB,
+     FX_LBDB, FX_LBIB, FX_LBDB, FX_LBDB, FX_LBDB, FX_LBIB, FX_LBIB, FX_LBIB,
+     FX_LBDB, FX_LBDB, FX_LBPB, FX_LBCB, FX_LBPB, FX_LBDB, FX_LBDB, FX_LBDB,
+     FX_LBDB, FX_LBDB, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN,
+     FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN},
+    {FX_LBDB, FX_LBPB, FX_LBIB, FX_LBIB, FX_LBIB, FX_LBPB, FX_LBPB, FX_LBPB,
+     FX_LBDB, FX_LBIB, FX_LBDB, FX_LBDB, FX_LBDB, FX_LBIB, FX_LBIB, FX_LBIB,
+     FX_LBDB, FX_LBDB, FX_LBPB, FX_LBCB, FX_LBPB, FX_LBDB, FX_LBDB, FX_LBDB,
+     FX_LBDB, FX_LBDB, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN,
+     FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN},
+    {FX_LBDB, FX_LBPB, FX_LBIB, FX_LBIB, FX_LBIB, FX_LBPB, FX_LBPB, FX_LBPB,
+     FX_LBDB, FX_LBIB, FX_LBDB, FX_LBDB, FX_LBDB, FX_LBIB, FX_LBIB, FX_LBIB,
+     FX_LBDB, FX_LBDB, FX_LBPB, FX_LBCB, FX_LBPB, FX_LBDB, FX_LBDB, FX_LBDB,
+     FX_LBDB, FX_LBDB, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN,
+     FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN},
+    {FX_LBDB, FX_LBPB, FX_LBIB, FX_LBIB, FX_LBIB, FX_LBPB, FX_LBPB, FX_LBPB,
+     FX_LBDB, FX_LBIB, FX_LBDB, FX_LBDB, FX_LBDB, FX_LBIB, FX_LBIB, FX_LBIB,
+     FX_LBDB, FX_LBDB, FX_LBPB, FX_LBCB, FX_LBPB, FX_LBDB, FX_LBDB, FX_LBDB,
+     FX_LBDB, FX_LBDB, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN,
+     FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN},
+    {FX_LBDB, FX_LBPB, FX_LBIB, FX_LBIB, FX_LBIB, FX_LBPB, FX_LBPB, FX_LBPB,
+     FX_LBDB, FX_LBIB, FX_LBDB, FX_LBDB, FX_LBDB, FX_LBIB, FX_LBIB, FX_LBIB,
+     FX_LBDB, FX_LBDB, FX_LBPB, FX_LBCB, FX_LBPB, FX_LBDB, FX_LBDB, FX_LBDB,
+     FX_LBDB, FX_LBDB, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN,
+     FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN},
+    {FX_LBDB, FX_LBPB, FX_LBIB, FX_LBIB, FX_LBIB, FX_LBPB, FX_LBPB, FX_LBPB,
+     FX_LBDB, FX_LBIB, FX_LBDB, FX_LBDB, FX_LBDB, FX_LBIB, FX_LBIB, FX_LBIB,
+     FX_LBDB, FX_LBDB, FX_LBPB, FX_LBCB, FX_LBPB, FX_LBDB, FX_LBDB, FX_LBDB,
+     FX_LBDB, FX_LBDB, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN,
+     FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN},
+    {FX_LBDB, FX_LBPB, FX_LBIB, FX_LBIB, FX_LBIB, FX_LBPB, FX_LBPB, FX_LBPB,
+     FX_LBDB, FX_LBIB, FX_LBDB, FX_LBDB, FX_LBDB, FX_LBIB, FX_LBIB, FX_LBIB,
+     FX_LBDB, FX_LBDB, FX_LBPB, FX_LBCB, FX_LBPB, FX_LBDB, FX_LBDB, FX_LBDB,
+     FX_LBDB, FX_LBDB, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN,
+     FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN},
+    {FX_LBDB, FX_LBPB, FX_LBDB, FX_LBPB, FX_LBPB, FX_LBPB, FX_LBDB, FX_LBPB,
+     FX_LBDB, FX_LBIB, FX_LBDB, FX_LBDB, FX_LBDB, FX_LBPB, FX_LBPB, FX_LBIB,
+     FX_LBDB, FX_LBDB, FX_LBPB, FX_LBCB, FX_LBPB, FX_LBDB, FX_LBDB, FX_LBDB,
+     FX_LBPB, FX_LBDB, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN,
+     FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN},
+    {FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN,
+     FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN,
+     FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN,
+     FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN,
+     FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN},
+    {FX_LBDB, FX_LBPB, FX_LBIB, FX_LBDB, FX_LBIB, FX_LBPB, FX_LBPB, FX_LBPB,
+     FX_LBDB, FX_LBDB, FX_LBDB, FX_LBDB, FX_LBDB, FX_LBDB, FX_LBIB, FX_LBIB,
+     FX_LBDB, FX_LBDB, FX_LBPB, FX_LBCB, FX_LBPB, FX_LBDB, FX_LBDB, FX_LBDB,
+     FX_LBDB, FX_LBDB, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN,
+     FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN, FX_LBUN},
+};
+
+#undef FX_LBUN
+#undef FX_LBDB
+#undef FX_LBIB
+#undef FX_LBCB
+#undef FX_LBCP
+#undef FX_LBPB
+#undef FX_LBHS
+
+}  // namespace
+
+FX_LINEBREAKTYPE GetLineBreakTypeFromPair(FX_BREAKPROPERTY curr_char,
+                                          FX_BREAKPROPERTY next_char) {
+  size_t row = static_cast<size_t>(curr_char);
+  size_t col = static_cast<size_t>(next_char);
+  ASSERT(row < FX_ArraySize(gs_FX_LineBreak_PairTable));
+  ASSERT(col < FX_ArraySize(gs_FX_LineBreak_PairTable[0]));
+  return gs_FX_LineBreak_PairTable[row][col];
+}
diff --git a/xfa/fgas/layout/fx_linebreak.h b/xfa/fgas/layout/fx_linebreak.h
new file mode 100644
index 0000000..ac46a35
--- /dev/null
+++ b/xfa/fgas/layout/fx_linebreak.h
@@ -0,0 +1,26 @@
+// Copyright 2014 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_FGAS_LAYOUT_FX_LINEBREAK_H_
+#define XFA_FGAS_LAYOUT_FX_LINEBREAK_H_
+
+#include "core/fxcrt/fx_system.h"
+#include "core/fxcrt/fx_unicode.h"
+
+enum class FX_LINEBREAKTYPE : uint8_t {
+  kUNKNOWN = 0x00,
+  kDIRECT_BRK = 0x1A,
+  kINDIRECT_BRK = 0x2B,
+  kCOM_INDIRECT_BRK = 0x3C,
+  kCOM_PROHIBITED_BRK = 0x4D,
+  kPROHIBITED_BRK = 0x5E,
+  kHANGUL_SPACE_BRK = 0x6F,
+};
+
+FX_LINEBREAKTYPE GetLineBreakTypeFromPair(FX_BREAKPROPERTY curr_char,
+                                          FX_BREAKPROPERTY next_char);
+
+#endif  // XFA_FGAS_LAYOUT_FX_LINEBREAK_H_
diff --git a/xfa/fwl/BUILD.gn b/xfa/fwl/BUILD.gn
new file mode 100644
index 0000000..765704d
--- /dev/null
+++ b/xfa/fwl/BUILD.gn
@@ -0,0 +1,130 @@
+# Copyright 2018 The 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.
+
+import("../../pdfium.gni")
+import("../../testing/test.gni")
+
+assert(pdf_enable_xfa)
+
+source_set("fwl") {
+  sources = [
+    "cfwl_app.cpp",
+    "cfwl_app.h",
+    "cfwl_barcode.cpp",
+    "cfwl_barcode.h",
+    "cfwl_caret.cpp",
+    "cfwl_caret.h",
+    "cfwl_checkbox.cpp",
+    "cfwl_checkbox.h",
+    "cfwl_combobox.cpp",
+    "cfwl_combobox.h",
+    "cfwl_comboedit.cpp",
+    "cfwl_comboedit.h",
+    "cfwl_combolist.cpp",
+    "cfwl_combolist.h",
+    "cfwl_datetimeedit.cpp",
+    "cfwl_datetimeedit.h",
+    "cfwl_datetimepicker.cpp",
+    "cfwl_datetimepicker.h",
+    "cfwl_edit.cpp",
+    "cfwl_edit.h",
+    "cfwl_event.cpp",
+    "cfwl_event.h",
+    "cfwl_eventmouse.cpp",
+    "cfwl_eventmouse.h",
+    "cfwl_eventscroll.cpp",
+    "cfwl_eventscroll.h",
+    "cfwl_eventselectchanged.cpp",
+    "cfwl_eventselectchanged.h",
+    "cfwl_eventtarget.cpp",
+    "cfwl_eventtarget.h",
+    "cfwl_eventtextwillchange.cpp",
+    "cfwl_eventtextwillchange.h",
+    "cfwl_eventvalidate.cpp",
+    "cfwl_eventvalidate.h",
+    "cfwl_listbox.cpp",
+    "cfwl_listbox.h",
+    "cfwl_listitem.cpp",
+    "cfwl_listitem.h",
+    "cfwl_message.cpp",
+    "cfwl_message.h",
+    "cfwl_messagekey.cpp",
+    "cfwl_messagekey.h",
+    "cfwl_messagekillfocus.cpp",
+    "cfwl_messagekillfocus.h",
+    "cfwl_messagemouse.cpp",
+    "cfwl_messagemouse.h",
+    "cfwl_messagemousewheel.cpp",
+    "cfwl_messagemousewheel.h",
+    "cfwl_messagesetfocus.cpp",
+    "cfwl_messagesetfocus.h",
+    "cfwl_monthcalendar.cpp",
+    "cfwl_monthcalendar.h",
+    "cfwl_notedriver.cpp",
+    "cfwl_notedriver.h",
+    "cfwl_picturebox.cpp",
+    "cfwl_picturebox.h",
+    "cfwl_pushbutton.cpp",
+    "cfwl_pushbutton.h",
+    "cfwl_scrollbar.cpp",
+    "cfwl_scrollbar.h",
+    "cfwl_themebackground.h",
+    "cfwl_themepart.cpp",
+    "cfwl_themepart.h",
+    "cfwl_themetext.h",
+    "cfwl_widget.cpp",
+    "cfwl_widget.h",
+    "cfwl_widgetmgr.cpp",
+    "cfwl_widgetmgr.h",
+    "cfwl_widgetproperties.cpp",
+    "cfwl_widgetproperties.h",
+    "fwl_widgetdef.h",
+    "fwl_widgethit.h",
+    "ifwl_themeprovider.h",
+    "ifwl_widgetdelegate.h",
+    "theme/cfwl_barcodetp.cpp",
+    "theme/cfwl_barcodetp.h",
+    "theme/cfwl_carettp.cpp",
+    "theme/cfwl_carettp.h",
+    "theme/cfwl_checkboxtp.cpp",
+    "theme/cfwl_checkboxtp.h",
+    "theme/cfwl_comboboxtp.cpp",
+    "theme/cfwl_comboboxtp.h",
+    "theme/cfwl_datetimepickertp.cpp",
+    "theme/cfwl_datetimepickertp.h",
+    "theme/cfwl_edittp.cpp",
+    "theme/cfwl_edittp.h",
+    "theme/cfwl_listboxtp.cpp",
+    "theme/cfwl_listboxtp.h",
+    "theme/cfwl_monthcalendartp.cpp",
+    "theme/cfwl_monthcalendartp.h",
+    "theme/cfwl_pictureboxtp.cpp",
+    "theme/cfwl_pictureboxtp.h",
+    "theme/cfwl_pushbuttontp.cpp",
+    "theme/cfwl_pushbuttontp.h",
+    "theme/cfwl_scrollbartp.cpp",
+    "theme/cfwl_scrollbartp.h",
+    "theme/cfwl_utils.h",
+    "theme/cfwl_widgettp.cpp",
+    "theme/cfwl_widgettp.h",
+  ]
+  deps = [
+    "../../core/fxcrt",
+    "../../core/fxge",
+    "../../fxbarcode",
+    "../fde",
+    "../fgas",
+    "../fxgraphics",
+  ]
+  configs += [
+    "../../:pdfium_core_config",
+    "../:xfa_warnings",
+  ]
+  visibility = [ "../../*" ]
+}
+
+pdfium_embeddertest_source_set("embeddertests") {
+  sources = [ "cfwl_edit_embeddertest.cpp" ]
+  pdfium_root_dir = "../../"
+}
diff --git a/xfa/fwl/README.md b/xfa/fwl/README.md
index 9285e89..6460ff1 100644
--- a/xfa/fwl/README.md
+++ b/xfa/fwl/README.md
@@ -5,8 +5,6 @@
 
 * CFWL_Widget
     * CFWL_Form
-        * CFWL_FormProxy
-            * CFWL_ComboBoxProxy
     * CFWL_Caret
     * CFWL_CheckBox
     * CFWL_ComboBox
@@ -48,7 +46,7 @@
     * CFWL_EventMouse
     * CFWL_EventScroll
     * CFWL_EventSelectChanged
-    * CFWL_EventTextChanged
+    * CFWL_EventTextWillChange
     * CFWL_EventValidate
 
 The widgets use IFWL_ThemeProvider for rendering everything, calling
diff --git a/xfa/fwl/cfwl_app.cpp b/xfa/fwl/cfwl_app.cpp
index 58ca93d..c3a06e3 100644
--- a/xfa/fwl/cfwl_app.cpp
+++ b/xfa/fwl/cfwl_app.cpp
@@ -10,13 +10,13 @@
 #include "xfa/fwl/cfwl_notedriver.h"
 #include "xfa/fwl/cfwl_widget.h"
 #include "xfa/fwl/cfwl_widgetmgr.h"
-#include "xfa/fxfa/cxfa_fwladapterwidgetmgr.h"
 
-CFWL_App::CFWL_App(CXFA_FFApp* pAdapter)
+CFWL_App::CFWL_App(AdapterIface* pAdapter)
     : m_pAdapterNative(pAdapter),
-      m_pWidgetMgr(pdfium::MakeUnique<CFWL_WidgetMgr>(pAdapter)),
+      m_pWidgetMgr(
+          pdfium::MakeUnique<CFWL_WidgetMgr>(pAdapter->GetWidgetMgrAdapter())),
       m_pNoteDriver(pdfium::MakeUnique<CFWL_NoteDriver>()) {
   ASSERT(m_pAdapterNative);
 }
 
-CFWL_App::~CFWL_App() {}
+CFWL_App::~CFWL_App() = default;
diff --git a/xfa/fwl/cfwl_app.h b/xfa/fwl/cfwl_app.h
index ed47149..a911ab2 100644
--- a/xfa/fwl/cfwl_app.h
+++ b/xfa/fwl/cfwl_app.h
@@ -10,12 +10,11 @@
 #include <memory>
 
 #include "core/fxcrt/fx_string.h"
+#include "core/fxcrt/timerhandler_iface.h"
+#include "xfa/fwl/cfwl_widgetmgr.h"
 
 class CFWL_NoteDriver;
 class CFWL_WidgetMgr;
-class CXFA_FFApp;
-class CXFA_FWLAdapterWidgetMgr;
-class CFWL_Widget;
 
 enum FWL_KeyFlag {
   FWL_KEYFLAG_Ctrl = 1 << 0,
@@ -29,15 +28,22 @@
 
 class CFWL_App {
  public:
-  explicit CFWL_App(CXFA_FFApp* pAdapter);
+  class AdapterIface {
+   public:
+    virtual ~AdapterIface() = default;
+    virtual CFWL_WidgetMgr::AdapterIface* GetWidgetMgrAdapter() = 0;
+    virtual TimerHandlerIface* GetTimerHandler() = 0;
+  };
+
+  explicit CFWL_App(AdapterIface* pAdapter);
   ~CFWL_App();
 
-  CXFA_FFApp* GetAdapterNative() const { return m_pAdapterNative.Get(); }
+  AdapterIface* GetAdapterNative() const { return m_pAdapterNative.Get(); }
   CFWL_WidgetMgr* GetWidgetMgr() const { return m_pWidgetMgr.get(); }
   CFWL_NoteDriver* GetNoteDriver() const { return m_pNoteDriver.get(); }
 
  private:
-  UnownedPtr<CXFA_FFApp> const m_pAdapterNative;
+  UnownedPtr<AdapterIface> const m_pAdapterNative;
   std::unique_ptr<CFWL_WidgetMgr> m_pWidgetMgr;
   std::unique_ptr<CFWL_NoteDriver> m_pNoteDriver;
 };
diff --git a/xfa/fwl/cfwl_barcode.cpp b/xfa/fwl/cfwl_barcode.cpp
index f5d6ea9..008424d 100644
--- a/xfa/fwl/cfwl_barcode.cpp
+++ b/xfa/fwl/cfwl_barcode.cpp
@@ -8,21 +8,18 @@
 
 #include <utility>
 
+#include "fxbarcode/cfx_barcode.h"
 #include "third_party/base/ptr_util.h"
 #include "xfa/fgas/font/cfgas_gefont.h"
 #include "xfa/fwl/cfwl_notedriver.h"
 #include "xfa/fwl/cfwl_themepart.h"
-#include "xfa/fwl/cfx_barcode.h"
 #include "xfa/fwl/ifwl_themeprovider.h"
 #include "xfa/fwl/theme/cfwl_utils.h"
 
 CFWL_Barcode::CFWL_Barcode(const CFWL_App* app)
-    : CFWL_Edit(app, pdfium::MakeUnique<CFWL_WidgetProperties>(), nullptr),
-      m_dwStatus(0),
-      m_type(BC_UNKNOWN),
-      m_dwAttributeMask(FWL_BCDATTRIBUTE_NONE) {}
+    : CFWL_Edit(app, pdfium::MakeUnique<CFWL_WidgetProperties>(), nullptr) {}
 
-CFWL_Barcode::~CFWL_Barcode() {}
+CFWL_Barcode::~CFWL_Barcode() = default;
 
 FWL_Type CFWL_Barcode::GetClassID() const {
   return FWL_Type::Barcode;
@@ -44,7 +41,7 @@
     return;
   if ((m_pProperties->m_dwStates & FWL_WGTSTATE_Focused) == 0) {
     GenerateBarcodeImageCache();
-    if (!m_pBarcodeEngine || (m_dwStatus & XFA_BCS_EncodeSuccess) == 0)
+    if (!m_pBarcodeEngine || m_eStatus != Status::kEncodeSuccess)
       return;
 
     CFX_Matrix mt;
@@ -64,31 +61,34 @@
 
   m_pBarcodeEngine.reset();
   m_type = type;
-  m_dwStatus = XFA_BCS_NeedUpdate;
+  m_eStatus = Status::kNeedUpdate;
 }
 
 void CFWL_Barcode::SetText(const WideString& wsText) {
   m_pBarcodeEngine.reset();
-  m_dwStatus = XFA_BCS_NeedUpdate;
+  m_eStatus = Status::kNeedUpdate;
   CFWL_Edit::SetText(wsText);
 }
 
+void CFWL_Barcode::SetTextSkipNotify(const WideString& wsText) {
+  m_pBarcodeEngine.reset();
+  m_eStatus = Status::kNeedUpdate;
+  CFWL_Edit::SetTextSkipNotify(wsText);
+}
+
 bool CFWL_Barcode::IsProtectedType() const {
   if (!m_pBarcodeEngine)
     return true;
 
   BC_TYPE tEngineType = m_pBarcodeEngine->GetType();
-  if (tEngineType == BC_QR_CODE || tEngineType == BC_PDF417 ||
-      tEngineType == BC_DATAMATRIX) {
-    return true;
-  }
-  return false;
+  return tEngineType == BC_QR_CODE || tEngineType == BC_PDF417 ||
+         tEngineType == BC_DATAMATRIX;
 }
 
 void CFWL_Barcode::OnProcessEvent(CFWL_Event* pEvent) {
-  if (pEvent->GetType() == CFWL_Event::Type::TextChanged) {
+  if (pEvent->GetType() == CFWL_Event::Type::TextWillChange) {
     m_pBarcodeEngine.reset();
-    m_dwStatus = XFA_BCS_NeedUpdate;
+    m_eStatus = Status::kNeedUpdate;
   }
   CFWL_Edit::OnProcessEvent(pEvent);
 }
@@ -149,16 +149,11 @@
   m_nECLevel = ecLevel;
 }
 
-void CFWL_Barcode::SetTruncated(bool truncated) {
-  m_dwAttributeMask |= FWL_BCDATTRIBUTE_TRUNCATED;
-  m_bTruncated = truncated;
-}
-
 void CFWL_Barcode::GenerateBarcodeImageCache() {
-  if ((m_dwStatus & XFA_BCS_NeedUpdate) == 0)
+  if (m_eStatus != Status::kNeedUpdate)
     return;
 
-  m_dwStatus = 0;
+  m_eStatus = Status::kNormal;
   CreateBarcodeEngine();
   if (!m_pBarcodeEngine)
     return;
@@ -167,12 +162,12 @@
   if (pTheme) {
     CFWL_ThemePart part;
     part.m_pWidget = this;
-    if (RetainPtr<CFGAS_GEFont> pFont = pTheme->GetFont(&part)) {
+    if (RetainPtr<CFGAS_GEFont> pFont = pTheme->GetFont(part)) {
       if (CFX_Font* pCXFont = pFont->GetDevFont())
         m_pBarcodeEngine->SetFont(pCXFont);
     }
-    m_pBarcodeEngine->SetFontSize(pTheme->GetFontSize(&part));
-    m_pBarcodeEngine->SetFontColor(pTheme->GetTextColor(&part));
+    m_pBarcodeEngine->SetFontSize(pTheme->GetFontSize(part));
+    m_pBarcodeEngine->SetFontColor(pTheme->GetTextColor(part));
   } else {
     m_pBarcodeEngine->SetFontSize(FWLTHEME_CAPACITY_FontSize);
   }
@@ -201,19 +196,15 @@
     m_pBarcodeEngine->SetEndChar(m_cEndChar);
   if (m_dwAttributeMask & FWL_BCDATTRIBUTE_ECLEVEL)
     m_pBarcodeEngine->SetErrorCorrectionLevel(m_nECLevel);
-  if (m_dwAttributeMask & FWL_BCDATTRIBUTE_TRUNCATED)
-    m_pBarcodeEngine->SetTruncated(m_bTruncated);
 
-  m_dwStatus = m_pBarcodeEngine->Encode(GetText().AsStringView())
-                   ? XFA_BCS_EncodeSuccess
-                   : 0;
+  m_eStatus = m_pBarcodeEngine->Encode(GetText().AsStringView())
+                  ? Status::kEncodeSuccess
+                  : Status::kNormal;
 }
 
 void CFWL_Barcode::CreateBarcodeEngine() {
   if (m_pBarcodeEngine || m_type == BC_UNKNOWN)
     return;
 
-  auto pBarcode = pdfium::MakeUnique<CFX_Barcode>();
-  if (pBarcode->Create(m_type))
-    m_pBarcodeEngine = std::move(pBarcode);
+  m_pBarcodeEngine = CFX_Barcode::Create(m_type);
 }
diff --git a/xfa/fwl/cfwl_barcode.h b/xfa/fwl/cfwl_barcode.h
index 2fc7960..d2cd716 100644
--- a/xfa/fwl/cfwl_barcode.h
+++ b/xfa/fwl/cfwl_barcode.h
@@ -11,15 +11,8 @@
 
 #include "fxbarcode/BC_Library.h"
 #include "xfa/fwl/cfwl_edit.h"
-#include "xfa/fwl/cfwl_scrollbar.h"
-#include "xfa/fwl/cfwl_widget.h"
 
-class CFWL_WidgetProperties;
 class CFX_Barcode;
-class CFWL_Widget;
-
-#define XFA_BCS_NeedUpdate 0x0001
-#define XFA_BCS_EncodeSuccess 0x0002
 
 enum FWL_BCDAttribute {
   FWL_BCDATTRIBUTE_NONE = 0,
@@ -34,10 +27,9 @@
   FWL_BCDATTRIBUTE_STARTCHAR = 1 << 8,
   FWL_BCDATTRIBUTE_ENDCHAR = 1 << 9,
   FWL_BCDATTRIBUTE_ECLEVEL = 1 << 10,
-  FWL_BCDATTRIBUTE_TRUNCATED = 1 << 11,
 };
 
-class CFWL_Barcode : public CFWL_Edit {
+class CFWL_Barcode final : public CFWL_Edit {
  public:
   explicit CFWL_Barcode(const CFWL_App* pApp);
   ~CFWL_Barcode() override;
@@ -50,6 +42,7 @@
 
   // CFWL_Edit
   void SetText(const WideString& wsText) override;
+  void SetTextSkipNotify(const WideString& wsText) override;
 
   void SetType(BC_TYPE type);
   bool IsProtectedType() const;
@@ -65,28 +58,32 @@
   void SetStartChar(char startChar);
   void SetEndChar(char endChar);
   void SetErrorCorrectionLevel(int32_t ecLevel);
-  void SetTruncated(bool truncated);
 
  private:
+  enum class Status : uint8_t {
+    kNormal,
+    kNeedUpdate,
+    kEncodeSuccess,
+  };
+
   void GenerateBarcodeImageCache();
   void CreateBarcodeEngine();
 
+  BC_TYPE m_type = BC_UNKNOWN;
+  BC_CHAR_ENCODING m_eCharEncoding = CHAR_ENCODING_UTF8;
+  BC_TEXT_LOC m_eTextLocation = BC_TEXT_LOC_NONE;
+  Status m_eStatus = Status::kNormal;
+  bool m_bCalChecksum = false;
+  bool m_bPrintChecksum = false;
+  char m_cStartChar = 0;
+  char m_cEndChar = 0;
+  int8_t m_nWideNarrowRatio = 1;
+  int32_t m_nModuleHeight = -1;
+  int32_t m_nModuleWidth = -1;
+  int32_t m_nDataLength = 0;
+  int32_t m_nECLevel = 0;
+  uint32_t m_dwAttributeMask = 0;
   std::unique_ptr<CFX_Barcode> m_pBarcodeEngine;
-  uint32_t m_dwStatus;
-  BC_TYPE m_type;
-  BC_CHAR_ENCODING m_eCharEncoding;
-  int32_t m_nModuleHeight;
-  int32_t m_nModuleWidth;
-  int32_t m_nDataLength;
-  bool m_bCalChecksum;
-  bool m_bPrintChecksum;
-  BC_TEXT_LOC m_eTextLocation;
-  int8_t m_nWideNarrowRatio;
-  char m_cStartChar;
-  char m_cEndChar;
-  int32_t m_nECLevel;
-  bool m_bTruncated;
-  uint32_t m_dwAttributeMask;
 };
 
 #endif  // XFA_FWL_CFWL_BARCODE_H_
diff --git a/xfa/fwl/cfwl_caret.cpp b/xfa/fwl/cfwl_caret.cpp
index cd85041..ef5bdcc 100644
--- a/xfa/fwl/cfwl_caret.cpp
+++ b/xfa/fwl/cfwl_caret.cpp
@@ -9,15 +9,15 @@
 #include <utility>
 
 #include "third_party/base/ptr_util.h"
+#include "xfa/fwl/cfwl_app.h"
 #include "xfa/fwl/cfwl_notedriver.h"
 #include "xfa/fwl/cfwl_themebackground.h"
-#include "xfa/fwl/cfwl_timerinfo.h"
 #include "xfa/fwl/cfwl_widgetproperties.h"
 #include "xfa/fwl/ifwl_themeprovider.h"
 
 namespace {
 
-const uint32_t kFrequency = 400;
+const uint32_t kBlinkPeriodMs = 600;
 
 constexpr int kStateHighlight = (1 << 0);
 
@@ -26,18 +26,11 @@
 CFWL_Caret::CFWL_Caret(const CFWL_App* app,
                        std::unique_ptr<CFWL_WidgetProperties> properties,
                        CFWL_Widget* pOuter)
-    : CFWL_Widget(app, std::move(properties), pOuter),
-      m_pTimer(pdfium::MakeUnique<CFWL_Caret::Timer>(this)),
-      m_pTimerInfo(nullptr) {
+    : CFWL_Widget(app, std::move(properties), pOuter) {
   SetStates(kStateHighlight);
 }
 
-CFWL_Caret::~CFWL_Caret() {
-  if (m_pTimerInfo) {
-    m_pTimerInfo->StopTimer();
-    m_pTimerInfo = nullptr;
-  }
-}
+CFWL_Caret::~CFWL_Caret() = default;
 
 FWL_Type CFWL_Caret::GetClassID() const {
   return FWL_Type::Caret;
@@ -54,21 +47,19 @@
   if (!m_pProperties->m_pThemeProvider)
     return;
 
-  DrawCaretBK(pGraphics, m_pProperties->m_pThemeProvider, &matrix);
+  DrawCaretBK(pGraphics, m_pProperties->m_pThemeProvider.Get(), &matrix);
 }
 
 void CFWL_Caret::ShowCaret() {
-  if (m_pTimerInfo)
-    m_pTimerInfo->StopTimer();
-  m_pTimerInfo = m_pTimer->StartTimer(kFrequency, true);
+  m_pTimer = pdfium::MakeUnique<CFX_Timer>(
+      GetOwnerApp()->GetAdapterNative()->GetTimerHandler(), this,
+      kBlinkPeriodMs);
   RemoveStates(FWL_WGTSTATE_Invisible);
+  SetStates(kStateHighlight);
 }
 
 void CFWL_Caret::HideCaret() {
-  if (m_pTimerInfo) {
-    m_pTimerInfo->StopTimer();
-    m_pTimerInfo = nullptr;
-  }
+  m_pTimer.reset();
   SetStates(FWL_WGTSTATE_Invisible);
 }
 
@@ -86,7 +77,7 @@
   param.m_dwStates = CFWL_PartState_HightLight;
   if (pMatrix)
     param.m_matrix.Concat(*pMatrix);
-  pTheme->DrawBackground(&param);
+  pTheme->DrawBackground(param);
 }
 
 void CFWL_Caret::OnProcessMessage(CFWL_Message* pMessage) {}
@@ -96,15 +87,12 @@
   DrawWidget(pGraphics, matrix);
 }
 
-CFWL_Caret::Timer::Timer(CFWL_Caret* pCaret) : CFWL_Timer(pCaret) {}
-
-void CFWL_Caret::Timer::Run(CFWL_TimerInfo* pTimerInfo) {
-  CFWL_Caret* pCaret = static_cast<CFWL_Caret*>(m_pWidget.Get());
-  if (!(pCaret->GetStates() & kStateHighlight))
-    pCaret->SetStates(kStateHighlight);
+void CFWL_Caret::OnTimerFired() {
+  if (!(GetStates() & kStateHighlight))
+    SetStates(kStateHighlight);
   else
-    pCaret->RemoveStates(kStateHighlight);
+    RemoveStates(kStateHighlight);
 
-  CFX_RectF rt = pCaret->GetWidgetRect();
-  pCaret->RepaintRect(CFX_RectF(0, 0, rt.width + 1, rt.height));
+  CFX_RectF rt = GetWidgetRect();
+  RepaintRect(CFX_RectF(0, 0, rt.width + 1, rt.height));
 }
diff --git a/xfa/fwl/cfwl_caret.h b/xfa/fwl/cfwl_caret.h
index 90d62d6..7f5dfdf 100644
--- a/xfa/fwl/cfwl_caret.h
+++ b/xfa/fwl/cfwl_caret.h
@@ -9,21 +9,21 @@
 
 #include <memory>
 
-#include "xfa/fwl/cfwl_timer.h"
+#include "core/fxcrt/cfx_timer.h"
 #include "xfa/fwl/cfwl_widget.h"
 #include "xfa/fxgraphics/cxfa_gecolor.h"
 
 class CFWL_WidgetProperties;
 class CFWL_Widget;
 
-class CFWL_Caret : public CFWL_Widget {
+class CFWL_Caret final : public CFWL_Widget, public CFX_Timer::CallbackIface {
  public:
   CFWL_Caret(const CFWL_App* app,
              std::unique_ptr<CFWL_WidgetProperties> properties,
              CFWL_Widget* pOuter);
   ~CFWL_Caret() override;
 
-  // CFWL_Widget
+  // CFWL_Widget:
   FWL_Type GetClassID() const override;
   void DrawWidget(CXFA_Graphics* pGraphics, const CFX_Matrix& matrix) override;
   void OnProcessMessage(CFWL_Message* pMessage) override;
@@ -31,25 +31,18 @@
                     const CFX_Matrix& matrix) override;
   void Update() override;
 
+  // CFX_Timer::CallbackIface:
+  void OnTimerFired() override;
+
   void ShowCaret();
   void HideCaret();
 
  private:
-  class Timer : public CFWL_Timer {
-   public:
-    explicit Timer(CFWL_Caret* pCaret);
-    ~Timer() override {}
-
-    void Run(CFWL_TimerInfo* hTimer) override;
-  };
-  friend class CFWL_Caret::Timer;
-
   void DrawCaretBK(CXFA_Graphics* pGraphics,
                    IFWL_ThemeProvider* pTheme,
                    const CFX_Matrix* pMatrix);
 
-  std::unique_ptr<CFWL_Caret::Timer> m_pTimer;
-  UnownedPtr<CFWL_TimerInfo> m_pTimerInfo;
+  std::unique_ptr<CFX_Timer> m_pTimer;
 };
 
 #endif  // XFA_FWL_CFWL_CARET_H_
diff --git a/xfa/fwl/cfwl_checkbox.cpp b/xfa/fwl/cfwl_checkbox.cpp
index 42b6cad..1342554 100644
--- a/xfa/fwl/cfwl_checkbox.cpp
+++ b/xfa/fwl/cfwl_checkbox.cpp
@@ -21,6 +21,7 @@
 #include "xfa/fwl/cfwl_themebackground.h"
 #include "xfa/fwl/cfwl_themetext.h"
 #include "xfa/fwl/cfwl_widgetmgr.h"
+#include "xfa/fwl/fwl_widgetdef.h"
 #include "xfa/fwl/ifwl_themeprovider.h"
 
 namespace {
@@ -30,15 +31,8 @@
 }  // namespace
 
 CFWL_CheckBox::CFWL_CheckBox(const CFWL_App* app)
-    : CFWL_Widget(app, pdfium::MakeUnique<CFWL_WidgetProperties>(), nullptr),
-      m_iTTOAlign(FDE_TextAlignment::kCenter),
-      m_bBtnDown(false),
-      m_fBoxHeight(16.0f) {
-  m_dwTTOStyles.single_line_ = true;
-  m_rtClient.Reset();
-  m_rtBox.Reset();
-  m_rtCaption.Reset();
-  m_rtFocus.Reset();
+    : CFWL_Widget(app, pdfium::MakeUnique<CFWL_WidgetProperties>(), nullptr) {
+  m_TTOStyles.single_line_ = true;
 }
 
 CFWL_CheckBox::~CFWL_CheckBox() {}
@@ -65,14 +59,13 @@
                                const CFX_Matrix& matrix) {
   if (!pGraphics)
     return;
-  if (!m_pProperties->m_pThemeProvider)
+
+  IFWL_ThemeProvider* pTheme = m_pProperties->m_pThemeProvider.Get();
+  if (!pTheme)
     return;
 
-  IFWL_ThemeProvider* pTheme = m_pProperties->m_pThemeProvider;
-  if (HasBorder()) {
-    DrawBorder(pGraphics, CFWL_Part::Border, m_pProperties->m_pThemeProvider,
-               matrix);
-  }
+  if (HasBorder())
+    DrawBorder(pGraphics, CFWL_Part::Border, pTheme, matrix);
 
   int32_t dwStates = GetPartStates();
 
@@ -84,12 +77,13 @@
   param.m_matrix.Concat(matrix);
   param.m_rtPart = m_rtClient;
   if (m_pProperties->m_dwStates & FWL_WGTSTATE_Focused)
-    param.m_pData = &m_rtFocus;
-  pTheme->DrawBackground(&param);
+
+    param.m_pRtData = &m_rtFocus;
+  pTheme->DrawBackground(param);
 
   param.m_iPart = CFWL_Part::CheckBox;
   param.m_rtPart = m_rtBox;
-  pTheme->DrawBackground(&param);
+  pTheme->DrawBackground(param);
 
   CFWL_ThemeText textParam;
   textParam.m_pWidget = this;
@@ -99,9 +93,9 @@
   textParam.m_matrix.Concat(matrix);
   textParam.m_rtPart = m_rtCaption;
   textParam.m_wsText = L"Check box";
-  textParam.m_dwTTOStyles = m_dwTTOStyles;
+  textParam.m_dwTTOStyles = m_TTOStyles;
   textParam.m_iTTOAlign = m_iTTOAlign;
-  pTheme->DrawText(&textParam);
+  pTheme->DrawText(textParam);
 }
 
 void CFWL_CheckBox::SetCheckState(int32_t iCheck) {
@@ -122,9 +116,9 @@
 
 void CFWL_CheckBox::Layout() {
   m_pProperties->m_rtWidget.width =
-      FXSYS_round(m_pProperties->m_rtWidget.width);
+      FXSYS_roundf(m_pProperties->m_rtWidget.width);
   m_pProperties->m_rtWidget.height =
-      FXSYS_round(m_pProperties->m_rtWidget.height);
+      FXSYS_roundf(m_pProperties->m_rtWidget.height);
   m_rtClient = GetClientRect();
 
   float fTextLeft = m_rtClient.left + m_fBoxHeight;
@@ -133,11 +127,9 @@
                           m_rtClient.right() - fTextLeft, m_rtClient.height);
   m_rtCaption.Inflate(-kCaptionMargin, -kCaptionMargin);
 
-  CFX_RectF rtFocus(m_rtCaption.left, m_rtCaption.top, m_rtCaption.width,
-                    m_rtCaption.height);
-
-  CalcTextRect(L"Check box", m_pProperties->m_pThemeProvider, m_dwTTOStyles,
-               m_iTTOAlign, rtFocus);
+  CFX_RectF rtFocus = m_rtCaption;
+  CalcTextRect(L"Check box", m_pProperties->m_pThemeProvider.Get(), m_TTOStyles,
+               m_iTTOAlign, &rtFocus);
 
   m_rtFocus = CFX_RectF(m_rtCaption.TopLeft(),
                         std::max(m_rtCaption.width, rtFocus.width),
@@ -169,9 +161,8 @@
 
 void CFWL_CheckBox::UpdateTextOutStyles() {
   m_iTTOAlign = FDE_TextAlignment::kTopLeft;
-
-  m_dwTTOStyles.Reset();
-  m_dwTTOStyles.single_line_ = true;
+  m_TTOStyles.Reset();
+  m_TTOStyles.single_line_ = true;
 }
 
 void CFWL_CheckBox::NextStates() {
@@ -179,21 +170,6 @@
   if (m_pProperties->m_dwStyleExes & FWL_STYLEEXT_CKB_RadioButton) {
     if ((m_pProperties->m_dwStates & FWL_STATE_CKB_CheckMask) ==
         FWL_STATE_CKB_Unchecked) {
-      CFWL_WidgetMgr* pWidgetMgr = GetOwnerApp()->GetWidgetMgr();
-      if (!pWidgetMgr->IsFormDisabled()) {
-        std::vector<CFWL_Widget*> radioarr =
-            pWidgetMgr->GetSameGroupRadioButton(this);
-        for (auto* pWidget : radioarr) {
-          CFWL_CheckBox* pCheckBox = static_cast<CFWL_CheckBox*>(pWidget);
-          if (pCheckBox != this &&
-              pCheckBox->GetStates() & FWL_STATE_CKB_Checked) {
-            pCheckBox->SetCheckState(0);
-            m_pWidgetMgr->RepaintWidget(
-                pCheckBox, CFX_RectF(0, 0, pCheckBox->GetWidgetRect().Size()));
-            break;
-          }
-        }
-      }
       m_pProperties->m_dwStates |= FWL_STATE_CKB_Checked;
     }
   } else {
@@ -261,8 +237,9 @@
     default:
       break;
   }
-
-  CFWL_Widget::OnProcessMessage(pMessage);
+  // Dst target could be |this|, continue only if not destroyed by above.
+  if (pMessage->GetDstTarget())
+    CFWL_Widget::OnProcessMessage(pMessage);
 }
 
 void CFWL_CheckBox::OnDrawWidget(CXFA_Graphics* pGraphics,
@@ -282,8 +259,6 @@
 void CFWL_CheckBox::OnLButtonDown() {
   if (m_pProperties->m_dwStates & FWL_WGTSTATE_Disabled)
     return;
-  if ((m_pProperties->m_dwStates & FWL_WGTSTATE_Focused) == 0)
-    SetFocus(true);
 
   m_bBtnDown = true;
   m_pProperties->m_dwStates &= ~FWL_STATE_CKB_Hovered;
@@ -351,10 +326,10 @@
 }
 
 void CFWL_CheckBox::OnKeyDown(CFWL_MessageKey* pMsg) {
-  if (pMsg->m_dwKeyCode == FWL_VKEY_Tab)
+  if (pMsg->m_dwKeyCode == XFA_FWL_VKEY_Tab)
     return;
-  if (pMsg->m_dwKeyCode == FWL_VKEY_Return ||
-      pMsg->m_dwKeyCode == FWL_VKEY_Space) {
+  if (pMsg->m_dwKeyCode == XFA_FWL_VKEY_Return ||
+      pMsg->m_dwKeyCode == XFA_FWL_VKEY_Space) {
     NextStates();
   }
 }
diff --git a/xfa/fwl/cfwl_checkbox.h b/xfa/fwl/cfwl_checkbox.h
index 9ae6590..0fa0236 100644
--- a/xfa/fwl/cfwl_checkbox.h
+++ b/xfa/fwl/cfwl_checkbox.h
@@ -7,8 +7,6 @@
 #ifndef XFA_FWL_CFWL_CHECKBOX_H_
 #define XFA_FWL_CFWL_CHECKBOX_H_
 
-#include <memory>
-
 #include "xfa/fwl/cfwl_event.h"
 #include "xfa/fwl/cfwl_widget.h"
 #include "xfa/fwl/cfwl_widgetproperties.h"
@@ -33,7 +31,7 @@
 class CFWL_WidgetProperties;
 class CFWL_Widget;
 
-class CFWL_CheckBox : public CFWL_Widget {
+class CFWL_CheckBox final : public CFWL_Widget {
  public:
   explicit CFWL_CheckBox(const CFWL_App* pApp);
   ~CFWL_CheckBox() override;
@@ -66,10 +64,10 @@
   CFX_RectF m_rtBox;
   CFX_RectF m_rtCaption;
   CFX_RectF m_rtFocus;
-  FDE_TextStyle m_dwTTOStyles;
-  FDE_TextAlignment m_iTTOAlign;
-  bool m_bBtnDown;
-  float m_fBoxHeight;
+  FDE_TextStyle m_TTOStyles;
+  FDE_TextAlignment m_iTTOAlign = FDE_TextAlignment::kCenter;
+  bool m_bBtnDown = false;
+  float m_fBoxHeight = 16.0f;
 };
 
 #endif  // XFA_FWL_CFWL_CHECKBOX_H_
diff --git a/xfa/fwl/cfwl_combobox.cpp b/xfa/fwl/cfwl_combobox.cpp
index 143d797..9c5edf4 100644
--- a/xfa/fwl/cfwl_combobox.cpp
+++ b/xfa/fwl/cfwl_combobox.cpp
@@ -16,8 +16,6 @@
 #include "xfa/fwl/cfwl_app.h"
 #include "xfa/fwl/cfwl_event.h"
 #include "xfa/fwl/cfwl_eventselectchanged.h"
-#include "xfa/fwl/cfwl_eventtextchanged.h"
-#include "xfa/fwl/cfwl_formproxy.h"
 #include "xfa/fwl/cfwl_listbox.h"
 #include "xfa/fwl/cfwl_messagekey.h"
 #include "xfa/fwl/cfwl_messagekillfocus.h"
@@ -28,48 +26,22 @@
 #include "xfa/fwl/cfwl_themepart.h"
 #include "xfa/fwl/cfwl_themetext.h"
 #include "xfa/fwl/cfwl_widgetmgr.h"
+#include "xfa/fwl/fwl_widgetdef.h"
 #include "xfa/fwl/ifwl_themeprovider.h"
 
 CFWL_ComboBox::CFWL_ComboBox(const CFWL_App* app)
-    : CFWL_Widget(app, pdfium::MakeUnique<CFWL_WidgetProperties>(), nullptr),
-      m_pComboBoxProxy(nullptr),
-      m_bLButtonDown(false),
-      m_iCurSel(-1),
-      m_iBtnState(CFWL_PartState_Normal) {
-  m_rtClient.Reset();
-  m_rtBtn.Reset();
-  m_rtHandler.Reset();
-
-  if (m_pWidgetMgr->IsFormDisabled()) {
-    DisForm_InitComboList();
-    DisForm_InitComboEdit();
-    return;
-  }
-
-  auto prop = pdfium::MakeUnique<CFWL_WidgetProperties>();
-  prop->m_pThemeProvider = m_pProperties->m_pThemeProvider;
-  prop->m_dwStyles |= FWL_WGTSTYLE_Border | FWL_WGTSTYLE_VScroll;
-  m_pListBox = pdfium::MakeUnique<CFWL_ComboList>(m_pOwnerApp.Get(),
-                                                  std::move(prop), this);
-
-  if ((m_pProperties->m_dwStyleExes & FWL_STYLEEXT_CMB_DropDown) && !m_pEdit) {
-    m_pEdit = pdfium::MakeUnique<CFWL_ComboEdit>(
-        m_pOwnerApp.Get(), pdfium::MakeUnique<CFWL_WidgetProperties>(), this);
-    m_pEdit->SetOuter(this);
-  }
-  if (m_pEdit)
-    m_pEdit->SetParent(this);
-
-  SetStates(m_pProperties->m_dwStates);
+    : CFWL_Widget(app, pdfium::MakeUnique<CFWL_WidgetProperties>(), nullptr) {
+  InitComboList();
+  InitComboEdit();
 }
 
-CFWL_ComboBox::~CFWL_ComboBox() {}
+CFWL_ComboBox::~CFWL_ComboBox() = default;
 
 FWL_Type CFWL_ComboBox::GetClassID() const {
   return FWL_Type::ComboBox;
 }
 
-void CFWL_ComboBox::AddString(const WideStringView& wsText) {
+void CFWL_ComboBox::AddString(const WideString& wsText) {
   m_pListBox->AddString(wsText);
 }
 
@@ -83,118 +55,74 @@
 
 void CFWL_ComboBox::ModifyStylesEx(uint32_t dwStylesExAdded,
                                    uint32_t dwStylesExRemoved) {
-  if (m_pWidgetMgr->IsFormDisabled()) {
-    DisForm_ModifyStylesEx(dwStylesExAdded, dwStylesExRemoved);
-    return;
-  }
+  if (!m_pEdit)
+    InitComboEdit();
 
   bool bAddDropDown = !!(dwStylesExAdded & FWL_STYLEEXT_CMB_DropDown);
-  bool bRemoveDropDown = !!(dwStylesExRemoved & FWL_STYLEEXT_CMB_DropDown);
-  if (bAddDropDown && !m_pEdit) {
-    m_pEdit = pdfium::MakeUnique<CFWL_ComboEdit>(
-        m_pOwnerApp.Get(), pdfium::MakeUnique<CFWL_WidgetProperties>(),
-        nullptr);
-    m_pEdit->SetOuter(this);
-    m_pEdit->SetParent(this);
-  } else if (bRemoveDropDown && m_pEdit) {
-    m_pEdit->SetStates(FWL_WGTSTATE_Invisible);
-  }
+  bool bDelDropDown = !!(dwStylesExRemoved & FWL_STYLEEXT_CMB_DropDown);
+
+  dwStylesExRemoved &= ~FWL_STYLEEXT_CMB_DropDown;
+  m_pProperties->m_dwStyleExes |= FWL_STYLEEXT_CMB_DropDown;
+
+  if (bAddDropDown)
+    m_pEdit->ModifyStylesEx(0, FWL_STYLEEXT_EDT_ReadOnly);
+  else if (bDelDropDown)
+    m_pEdit->ModifyStylesEx(FWL_STYLEEXT_EDT_ReadOnly, 0);
   CFWL_Widget::ModifyStylesEx(dwStylesExAdded, dwStylesExRemoved);
 }
 
 void CFWL_ComboBox::Update() {
-  if (m_pWidgetMgr->IsFormDisabled()) {
-    DisForm_Update();
+  if (m_iLock)
     return;
-  }
-  if (IsLocked())
-    return;
-
-  ResetTheme();
-  if (IsDropDownStyle() && m_pEdit)
+  if (m_pEdit)
     ResetEditAlignment();
-  if (!m_pProperties->m_pThemeProvider)
-    m_pProperties->m_pThemeProvider = GetAvailableTheme();
-
+  ResetTheme();
   Layout();
 }
 
 FWL_WidgetHit CFWL_ComboBox::HitTest(const CFX_PointF& point) {
-  if (m_pWidgetMgr->IsFormDisabled())
-    return DisForm_HitTest(point);
-  return CFWL_Widget::HitTest(point);
+  CFX_RectF rect(0, 0, m_pProperties->m_rtWidget.width - m_rtBtn.width,
+                 m_pProperties->m_rtWidget.height);
+  if (rect.Contains(point))
+    return FWL_WidgetHit::Edit;
+  if (m_rtBtn.Contains(point))
+    return FWL_WidgetHit::Client;
+  if (IsDropListVisible()) {
+    rect = m_pListBox->GetWidgetRect();
+    if (rect.Contains(point))
+      return FWL_WidgetHit::Client;
+  }
+  return FWL_WidgetHit::Unknown;
 }
 
 void CFWL_ComboBox::DrawWidget(CXFA_Graphics* pGraphics,
                                const CFX_Matrix& matrix) {
-  if (m_pWidgetMgr->IsFormDisabled()) {
-    DisForm_DrawWidget(pGraphics, &matrix);
-    return;
-  }
-
-  if (!pGraphics)
-    return;
-  if (!m_pProperties->m_pThemeProvider)
-    return;
-
-  IFWL_ThemeProvider* pTheme = m_pProperties->m_pThemeProvider;
-  if (HasBorder())
-    DrawBorder(pGraphics, CFWL_Part::Border, pTheme, matrix);
-
-  if (!IsDropDownStyle()) {
-    CFX_RectF rtTextBk(m_rtClient);
-    rtTextBk.width -= m_rtBtn.width;
-
+  IFWL_ThemeProvider* pTheme = m_pProperties->m_pThemeProvider.Get();
+  pGraphics->SaveGraphState();
+  pGraphics->ConcatMatrix(&matrix);
+  if (!m_rtBtn.IsEmpty(0.1f)) {
     CFWL_ThemeBackground param;
     param.m_pWidget = this;
-    param.m_iPart = CFWL_Part::Background;
+    param.m_iPart = CFWL_Part::DropDownButton;
+    param.m_dwStates = m_iBtnState;
     param.m_pGraphics = pGraphics;
-    param.m_matrix.Concat(matrix);
-    param.m_rtPart = rtTextBk;
-
-    if (m_pProperties->m_dwStates & FWL_WGTSTATE_Disabled) {
-      param.m_dwStates = CFWL_PartState_Disabled;
-    } else if ((m_pProperties->m_dwStates & FWL_WGTSTATE_Focused) &&
-               (m_iCurSel >= 0)) {
-      param.m_dwStates = CFWL_PartState_Selected;
-    } else {
-      param.m_dwStates = CFWL_PartState_Normal;
-    }
-    pTheme->DrawBackground(&param);
-
-    if (m_iCurSel >= 0) {
-      if (!m_pListBox)
-        return;
-
-      CFWL_ListItem* hItem = m_pListBox->GetItem(this, m_iCurSel);
-
-      CFWL_ThemeText theme_text;
-      theme_text.m_pWidget = this;
-      theme_text.m_iPart = CFWL_Part::Caption;
-      theme_text.m_dwStates = m_iBtnState;
-      theme_text.m_pGraphics = pGraphics;
-      theme_text.m_matrix.Concat(matrix);
-      theme_text.m_rtPart = rtTextBk;
-      theme_text.m_dwStates = (m_pProperties->m_dwStates & FWL_WGTSTATE_Focused)
-                                  ? CFWL_PartState_Selected
-                                  : CFWL_PartState_Normal;
-      theme_text.m_wsText = hItem ? hItem->GetText() : L"";
-      theme_text.m_dwTTOStyles.single_line_ = true;
-      theme_text.m_iTTOAlign = FDE_TextAlignment::kCenterLeft;
-      pTheme->DrawText(&theme_text);
-    }
+    param.m_rtPart = m_rtBtn;
+    pTheme->DrawBackground(param);
   }
+  pGraphics->RestoreGraphState();
 
-  CFWL_ThemeBackground param;
-  param.m_pWidget = this;
-  param.m_iPart = CFWL_Part::DropDownButton;
-  param.m_dwStates = (m_pProperties->m_dwStates & FWL_WGTSTATE_Disabled)
-                         ? CFWL_PartState_Disabled
-                         : m_iBtnState;
-  param.m_pGraphics = pGraphics;
-  param.m_matrix.Concat(matrix);
-  param.m_rtPart = m_rtBtn;
-  pTheme->DrawBackground(&param);
+  if (m_pEdit) {
+    CFX_RectF rtEdit = m_pEdit->GetWidgetRect();
+    CFX_Matrix mt(1, 0, 0, 1, rtEdit.left, rtEdit.top);
+    mt.Concat(matrix);
+    m_pEdit->DrawWidget(pGraphics, mt);
+  }
+  if (m_pListBox && IsDropListVisible()) {
+    CFX_RectF rtList = m_pListBox->GetWidgetRect();
+    CFX_Matrix mt(1, 0, 0, 1, rtList.left, rtList.top);
+    mt.Concat(matrix);
+    m_pListBox->DrawWidget(pGraphics, mt);
+  }
 }
 
 void CFWL_ComboBox::SetThemeProvider(IFWL_ThemeProvider* pThemeProvider) {
@@ -211,7 +139,7 @@
 WideString CFWL_ComboBox::GetTextByIndex(int32_t iIndex) const {
   CFWL_ListItem* pItem = static_cast<CFWL_ListItem*>(
       m_pListBox->GetItem(m_pListBox.get(), iIndex));
-  return pItem ? pItem->GetText() : L"";
+  return pItem ? pItem->GetText() : WideString();
 }
 
 void CFWL_ComboBox::SetCurSel(int32_t iSel) {
@@ -222,7 +150,7 @@
       m_pEdit->SetText(WideString());
     } else {
       CFWL_ListItem* hItem = m_pListBox->GetItem(this, iSel);
-      m_pEdit->SetText(hItem ? hItem->GetText() : L"");
+      m_pEdit->SetText(hItem ? hItem->GetText() : WideString());
     }
     m_pEdit->Update();
   }
@@ -257,10 +185,10 @@
   if (m_pEdit)
     return m_pEdit->GetText();
   if (!m_pListBox)
-    return L"";
+    return WideString();
 
   CFWL_ListItem* hItem = m_pListBox->GetItem(this, m_iCurSel);
-  return hItem ? hItem->GetText() : L"";
+  return hItem ? hItem->GetText() : WideString();
 }
 
 void CFWL_ComboBox::OpenDropDownList(bool bActivate) {
@@ -268,9 +196,6 @@
 }
 
 CFX_RectF CFWL_ComboBox::GetBBox() const {
-  if (m_pWidgetMgr->IsFormDisabled())
-    return DisForm_GetBBox();
-
   CFX_RectF rect = m_pProperties->m_rtWidget;
   if (!m_pListBox || !IsDropListVisible())
     return rect;
@@ -287,69 +212,54 @@
     m_pEdit->ModifyStylesEx(dwStylesExAdded, dwStylesExRemoved);
 }
 
-void CFWL_ComboBox::DrawStretchHandler(CXFA_Graphics* pGraphics,
-                                       const CFX_Matrix* pMatrix) {
-  CFWL_ThemeBackground param;
-  param.m_pGraphics = pGraphics;
-  param.m_iPart = CFWL_Part::StretchHandler;
-  param.m_dwStates = CFWL_PartState_Normal;
-  param.m_pWidget = this;
-  if (pMatrix)
-    param.m_matrix.Concat(*pMatrix);
-  param.m_rtPart = m_rtHandler;
-  m_pProperties->m_pThemeProvider->DrawBackground(&param);
-}
-
 void CFWL_ComboBox::ShowDropList(bool bActivate) {
-  if (m_pWidgetMgr->IsFormDisabled())
-    return DisForm_ShowDropList(bActivate);
   if (IsDropListVisible() == bActivate)
     return;
-  if (!m_pComboBoxProxy)
-    InitProxyForm();
 
-  m_pComboBoxProxy->Reset();
-  if (!bActivate) {
-    m_pComboBoxProxy->EndDoModal();
+  if (bActivate) {
+    CFWL_Event preEvent(CFWL_Event::Type::PreDropDown, this);
+    DispatchEvent(&preEvent);
+    if (!preEvent.GetSrcTarget())
+      return;
 
-    m_bLButtonDown = false;
-    m_pListBox->SetNotifyOwner(true);
-    SetFocus(true);
-    return;
+    CFWL_ComboList* pComboList = m_pListBox.get();
+    int32_t iItems = pComboList->CountItems(nullptr);
+    if (iItems < 1)
+      return;
+
+    ResetListItemAlignment();
+    pComboList->ChangeSelected(m_iCurSel);
+
+    float fItemHeight = pComboList->CalcItemHeight();
+    float fBorder = GetCXBorderSize();
+    float fPopupMin = 0.0f;
+    if (iItems > 3)
+      fPopupMin = fItemHeight * 3 + fBorder * 2;
+
+    float fPopupMax = fItemHeight * iItems + fBorder * 2;
+    CFX_RectF rtList(m_rtClient.left, 0, m_pProperties->m_rtWidget.width, 0);
+    GetPopupPos(fPopupMin, fPopupMax, m_pProperties->m_rtWidget, &rtList);
+
+    m_pListBox->SetWidgetRect(rtList);
+    m_pListBox->Update();
   }
 
-  m_pListBox->ChangeSelected(m_iCurSel);
-  ResetListItemAlignment();
+  if (bActivate) {
+    m_pListBox->RemoveStates(FWL_WGTSTATE_Invisible);
+    CFWL_Event postEvent(CFWL_Event::Type::PostDropDown, this);
+    DispatchEvent(&postEvent);
+  } else {
+    m_pListBox->SetStates(FWL_WGTSTATE_Invisible);
+  }
 
-  uint32_t dwStyleAdd = m_pProperties->m_dwStyleExes &
-                        (FWL_STYLEEXT_CMB_Sort | FWL_STYLEEXT_CMB_OwnerDraw);
-  m_pListBox->ModifyStylesEx(dwStyleAdd, 0);
-  m_rtList = m_pListBox->GetAutosizedWidgetRect();
-
-  CFX_RectF rtAnchor(0, 0, m_pProperties->m_rtWidget.width,
-                     m_pProperties->m_rtWidget.height);
-
-  m_rtList.width = std::max(m_rtList.width, m_rtClient.width);
-  m_rtProxy = m_rtList;
-
-  GetPopupPos(0, m_rtProxy.height, rtAnchor, m_rtProxy);
-
-  m_pComboBoxProxy->SetWidgetRect(m_rtProxy);
-  m_pComboBoxProxy->Update();
-  m_pListBox->SetWidgetRect(m_rtList);
-  m_pListBox->Update();
-
-  CFWL_Event ev(CFWL_Event::Type::PreDropDown, this);
-  DispatchEvent(&ev);
-
-  m_pListBox->SetFocus(true);
-  m_pComboBoxProxy->DoModal();
-  m_pListBox->SetFocus(false);
+  CFX_RectF rect = m_pListBox->GetWidgetRect();
+  rect.Inflate(2, 2);
+  RepaintRect(rect);
 }
 
 void CFWL_ComboBox::MatchEditText() {
   WideString wsText = m_pEdit->GetText();
-  int32_t iMatch = m_pListBox->MatchItem(wsText);
+  int32_t iMatch = m_pListBox->MatchItem(wsText.AsStringView());
   if (iMatch != m_iCurSel) {
     m_pListBox->ChangeSelected(iMatch);
     if (iMatch >= 0)
@@ -362,45 +272,52 @@
 
 void CFWL_ComboBox::SyncEditText(int32_t iListItem) {
   CFWL_ListItem* hItem = m_pListBox->GetItem(this, iListItem);
-  m_pEdit->SetText(hItem ? hItem->GetText() : L"");
+  m_pEdit->SetText(hItem ? hItem->GetText() : WideString());
   m_pEdit->Update();
   m_pEdit->SetSelected();
 }
 
 void CFWL_ComboBox::Layout() {
-  if (m_pWidgetMgr->IsFormDisabled())
-    return DisForm_Layout();
-
   m_rtClient = GetClientRect();
+  m_rtContent = m_rtClient;
   IFWL_ThemeProvider* theme = GetAvailableTheme();
   if (!theme)
     return;
 
+  float borderWidth = 1;
   float fBtn = theme->GetScrollBarWidth();
-  m_rtBtn = CFX_RectF(m_rtClient.right() - fBtn, m_rtClient.top, fBtn,
-                      m_rtClient.height);
+  if (!(GetStylesEx() & FWL_STYLEEXT_CMB_ReadOnly)) {
+    m_rtBtn =
+        CFX_RectF(m_rtClient.right() - fBtn, m_rtClient.top + borderWidth,
+                  fBtn - borderWidth, m_rtClient.height - 2 * borderWidth);
+  }
+
+  CFWL_ThemePart part;
+  part.m_pWidget = this;
+  CFX_RectF pUIMargin = theme->GetUIMargin(part);
+  m_rtContent.Deflate(pUIMargin.left, pUIMargin.top, pUIMargin.width,
+                      pUIMargin.height);
+
   if (!IsDropDownStyle() || !m_pEdit)
     return;
 
-  CFX_RectF rtEdit(m_rtClient.left, m_rtClient.top, m_rtClient.width - fBtn,
-                   m_rtClient.height);
+  CFX_RectF rtEdit(m_rtContent.left, m_rtContent.top, m_rtContent.width - fBtn,
+                   m_rtContent.height);
   m_pEdit->SetWidgetRect(rtEdit);
 
   if (m_iCurSel >= 0) {
     CFWL_ListItem* hItem = m_pListBox->GetItem(this, m_iCurSel);
-    m_pEdit->LockUpdate();
-    m_pEdit->SetText(hItem ? hItem->GetText() : L"");
-    m_pEdit->UnlockUpdate();
+    ScopedUpdateLock update_lock(m_pEdit.get());
+    m_pEdit->SetText(hItem ? hItem->GetText() : WideString());
   }
   m_pEdit->Update();
 }
 
 void CFWL_ComboBox::ResetTheme() {
-  IFWL_ThemeProvider* pTheme = m_pProperties->m_pThemeProvider;
-  if (!pTheme) {
-    pTheme = GetAvailableTheme();
-    m_pProperties->m_pThemeProvider = pTheme;
-  }
+  if (!m_pProperties->m_pThemeProvider)
+    m_pProperties->m_pThemeProvider = GetAvailableTheme();
+
+  IFWL_ThemeProvider* pTheme = m_pProperties->m_pThemeProvider.Get();
   if (m_pListBox && !m_pListBox->GetThemeProvider())
     m_pListBox->SetThemeProvider(pTheme);
   if (m_pEdit && !m_pEdit->GetThemeProvider())
@@ -483,25 +400,7 @@
   DispatchEvent(&ev);
 }
 
-void CFWL_ComboBox::InitProxyForm() {
-  if (m_pComboBoxProxy)
-    return;
-  if (!m_pListBox)
-    return;
-
-  auto prop = pdfium::MakeUnique<CFWL_WidgetProperties>();
-  prop->m_pOwner = this;
-  prop->m_dwStyles = FWL_WGTSTYLE_Popup;
-  prop->m_dwStates = FWL_WGTSTATE_Invisible;
-
-  // TODO(dsinclair): Does this leak? I don't see a delete, but I'm not sure
-  // if the SetParent call is going to transfer ownership.
-  m_pComboBoxProxy = new CFWL_ComboBoxProxy(this, m_pOwnerApp.Get(),
-                                            std::move(prop), m_pListBox.get());
-  m_pListBox->SetParent(m_pComboBoxProxy);
-}
-
-void CFWL_ComboBox::DisForm_InitComboList() {
+void CFWL_ComboBox::InitComboList() {
   if (m_pListBox)
     return;
 
@@ -514,7 +413,7 @@
                                                   std::move(prop), this);
 }
 
-void CFWL_ComboBox::DisForm_InitComboEdit() {
+void CFWL_ComboBox::InitComboEdit() {
   if (m_pEdit)
     return;
 
@@ -527,370 +426,7 @@
   m_pEdit->SetOuter(this);
 }
 
-void CFWL_ComboBox::DisForm_ShowDropList(bool bActivate) {
-  if (DisForm_IsDropListVisible() == bActivate)
-    return;
-
-  if (bActivate) {
-    CFWL_Event preEvent(CFWL_Event::Type::PreDropDown, this);
-    DispatchEvent(&preEvent);
-
-    CFWL_ComboList* pComboList = m_pListBox.get();
-    int32_t iItems = pComboList->CountItems(nullptr);
-    if (iItems < 1)
-      return;
-
-    ResetListItemAlignment();
-    pComboList->ChangeSelected(m_iCurSel);
-
-    float fItemHeight = pComboList->CalcItemHeight();
-    float fBorder = GetBorderSize(true);
-    float fPopupMin = 0.0f;
-    if (iItems > 3)
-      fPopupMin = fItemHeight * 3 + fBorder * 2;
-
-    float fPopupMax = fItemHeight * iItems + fBorder * 2;
-    CFX_RectF rtList(m_rtClient.left, 0, m_pProperties->m_rtWidget.width, 0);
-    GetPopupPos(fPopupMin, fPopupMax, m_pProperties->m_rtWidget, rtList);
-
-    m_pListBox->SetWidgetRect(rtList);
-    m_pListBox->Update();
-  } else {
-    SetFocus(true);
-  }
-
-  if (bActivate) {
-    m_pListBox->RemoveStates(FWL_WGTSTATE_Invisible);
-    CFWL_Event postEvent(CFWL_Event::Type::PostDropDown, this);
-    DispatchEvent(&postEvent);
-  } else {
-    m_pListBox->SetStates(FWL_WGTSTATE_Invisible);
-  }
-
-  CFX_RectF rect = m_pListBox->GetWidgetRect();
-  rect.Inflate(2, 2);
-  RepaintRect(rect);
-}
-
-void CFWL_ComboBox::DisForm_ModifyStylesEx(uint32_t dwStylesExAdded,
-                                           uint32_t dwStylesExRemoved) {
-  if (!m_pEdit)
-    DisForm_InitComboEdit();
-
-  bool bAddDropDown = !!(dwStylesExAdded & FWL_STYLEEXT_CMB_DropDown);
-  bool bDelDropDown = !!(dwStylesExRemoved & FWL_STYLEEXT_CMB_DropDown);
-
-  dwStylesExRemoved &= ~FWL_STYLEEXT_CMB_DropDown;
-  m_pProperties->m_dwStyleExes |= FWL_STYLEEXT_CMB_DropDown;
-
-  if (bAddDropDown)
-    m_pEdit->ModifyStylesEx(0, FWL_STYLEEXT_EDT_ReadOnly);
-  else if (bDelDropDown)
-    m_pEdit->ModifyStylesEx(FWL_STYLEEXT_EDT_ReadOnly, 0);
-  CFWL_Widget::ModifyStylesEx(dwStylesExAdded, dwStylesExRemoved);
-}
-
-void CFWL_ComboBox::DisForm_Update() {
-  if (m_iLock)
-    return;
-  if (m_pEdit)
-    ResetEditAlignment();
-  ResetTheme();
-  Layout();
-}
-
-FWL_WidgetHit CFWL_ComboBox::DisForm_HitTest(const CFX_PointF& point) {
-  CFX_RectF rect(0, 0, m_pProperties->m_rtWidget.width - m_rtBtn.width,
-                 m_pProperties->m_rtWidget.height);
-  if (rect.Contains(point))
-    return FWL_WidgetHit::Edit;
-  if (m_rtBtn.Contains(point))
-    return FWL_WidgetHit::Client;
-  if (DisForm_IsDropListVisible()) {
-    rect = m_pListBox->GetWidgetRect();
-    if (rect.Contains(point))
-      return FWL_WidgetHit::Client;
-  }
-  return FWL_WidgetHit::Unknown;
-}
-
-void CFWL_ComboBox::DisForm_DrawWidget(CXFA_Graphics* pGraphics,
-                                       const CFX_Matrix* pMatrix) {
-  IFWL_ThemeProvider* pTheme = m_pProperties->m_pThemeProvider;
-  CFX_Matrix mtOrg;
-  if (pMatrix)
-    mtOrg = *pMatrix;
-
-  pGraphics->SaveGraphState();
-  pGraphics->ConcatMatrix(&mtOrg);
-  if (!m_rtBtn.IsEmpty(0.1f)) {
-    CFWL_ThemeBackground param;
-    param.m_pWidget = this;
-    param.m_iPart = CFWL_Part::DropDownButton;
-    param.m_dwStates = m_iBtnState;
-    param.m_pGraphics = pGraphics;
-    param.m_rtPart = m_rtBtn;
-    pTheme->DrawBackground(&param);
-  }
-  pGraphics->RestoreGraphState();
-
-  if (m_pEdit) {
-    CFX_RectF rtEdit = m_pEdit->GetWidgetRect();
-    CFX_Matrix mt(1, 0, 0, 1, rtEdit.left, rtEdit.top);
-    mt.Concat(mtOrg);
-    m_pEdit->DrawWidget(pGraphics, mt);
-  }
-  if (m_pListBox && DisForm_IsDropListVisible()) {
-    CFX_RectF rtList = m_pListBox->GetWidgetRect();
-    CFX_Matrix mt(1, 0, 0, 1, rtList.left, rtList.top);
-    mt.Concat(mtOrg);
-    m_pListBox->DrawWidget(pGraphics, mt);
-  }
-}
-
-CFX_RectF CFWL_ComboBox::DisForm_GetBBox() const {
-  CFX_RectF rect = m_pProperties->m_rtWidget;
-  if (!m_pListBox || !DisForm_IsDropListVisible())
-    return rect;
-
-  CFX_RectF rtList = m_pListBox->GetWidgetRect();
-  rtList.Offset(rect.left, rect.top);
-  rect.Union(rtList);
-  return rect;
-}
-
-void CFWL_ComboBox::DisForm_Layout() {
-  m_rtClient = GetClientRect();
-  m_rtContent = m_rtClient;
-  IFWL_ThemeProvider* theme = GetAvailableTheme();
-  if (!theme)
-    return;
-
-  float borderWidth = 1;
-  float fBtn = theme->GetScrollBarWidth();
-  if (!(GetStylesEx() & FWL_STYLEEXT_CMB_ReadOnly)) {
-    m_rtBtn =
-        CFX_RectF(m_rtClient.right() - fBtn, m_rtClient.top + borderWidth,
-                  fBtn - borderWidth, m_rtClient.height - 2 * borderWidth);
-  }
-
-  CFWL_ThemePart part;
-  part.m_pWidget = this;
-  CFX_RectF pUIMargin = theme->GetUIMargin(&part);
-  m_rtContent.Deflate(pUIMargin.left, pUIMargin.top, pUIMargin.width,
-                      pUIMargin.height);
-
-  if (!IsDropDownStyle() || !m_pEdit)
-    return;
-
-  CFX_RectF rtEdit(m_rtContent.left, m_rtContent.top, m_rtContent.width - fBtn,
-                   m_rtContent.height);
-  m_pEdit->SetWidgetRect(rtEdit);
-
-  if (m_iCurSel >= 0) {
-    CFWL_ListItem* hItem = m_pListBox->GetItem(this, m_iCurSel);
-    m_pEdit->LockUpdate();
-    m_pEdit->SetText(hItem ? hItem->GetText() : L"");
-    m_pEdit->UnlockUpdate();
-  }
-  m_pEdit->Update();
-}
-
 void CFWL_ComboBox::OnProcessMessage(CFWL_Message* pMessage) {
-  if (m_pWidgetMgr->IsFormDisabled()) {
-    DisForm_OnProcessMessage(pMessage);
-    return;
-  }
-  if (!pMessage)
-    return;
-
-  switch (pMessage->GetType()) {
-    case CFWL_Message::Type::SetFocus:
-      OnFocusChanged(pMessage, true);
-      break;
-    case CFWL_Message::Type::KillFocus:
-      OnFocusChanged(pMessage, false);
-      break;
-    case CFWL_Message::Type::Mouse: {
-      CFWL_MessageMouse* pMsg = static_cast<CFWL_MessageMouse*>(pMessage);
-      switch (pMsg->m_dwCmd) {
-        case FWL_MouseCommand::LeftButtonDown:
-          OnLButtonDown(pMsg);
-          break;
-        case FWL_MouseCommand::LeftButtonUp:
-          OnLButtonUp(pMsg);
-          break;
-        case FWL_MouseCommand::Move:
-          OnMouseMove(pMsg);
-          break;
-        case FWL_MouseCommand::Leave:
-          OnMouseLeave(pMsg);
-          break;
-        default:
-          break;
-      }
-      break;
-    }
-    case CFWL_Message::Type::Key:
-      OnKey(static_cast<CFWL_MessageKey*>(pMessage));
-      break;
-    default:
-      break;
-  }
-
-  CFWL_Widget::OnProcessMessage(pMessage);
-}
-
-void CFWL_ComboBox::OnProcessEvent(CFWL_Event* pEvent) {
-  CFWL_Event::Type type = pEvent->GetType();
-  if (type == CFWL_Event::Type::Scroll) {
-    CFWL_EventScroll* pScrollEvent = static_cast<CFWL_EventScroll*>(pEvent);
-    CFWL_EventScroll pScrollEv(this);
-    pScrollEv.m_iScrollCode = pScrollEvent->m_iScrollCode;
-    pScrollEv.m_fPos = pScrollEvent->m_fPos;
-    DispatchEvent(&pScrollEv);
-  } else if (type == CFWL_Event::Type::TextChanged) {
-    CFWL_Event pTemp(CFWL_Event::Type::EditChanged, this);
-    DispatchEvent(&pTemp);
-  }
-}
-
-void CFWL_ComboBox::OnDrawWidget(CXFA_Graphics* pGraphics,
-                                 const CFX_Matrix& matrix) {
-  DrawWidget(pGraphics, matrix);
-}
-
-void CFWL_ComboBox::OnFocusChanged(CFWL_Message* pMsg, bool bSet) {
-  if (bSet) {
-    m_pProperties->m_dwStates |= FWL_WGTSTATE_Focused;
-    if (IsDropDownStyle() && pMsg->m_pSrcTarget != m_pListBox.get()) {
-      if (!m_pEdit)
-        return;
-      m_pEdit->SetSelected();
-      return;
-    }
-
-    RepaintRect(m_rtClient);
-    return;
-  }
-
-  m_pProperties->m_dwStates &= ~FWL_WGTSTATE_Focused;
-  if (!IsDropDownStyle() || pMsg->m_pDstTarget == m_pListBox.get()) {
-    RepaintRect(m_rtClient);
-    return;
-  }
-  if (!m_pEdit)
-    return;
-
-  m_pEdit->FlagFocus(false);
-  m_pEdit->ClearSelected();
-}
-
-void CFWL_ComboBox::OnLButtonDown(CFWL_MessageMouse* pMsg) {
-  if (m_pProperties->m_dwStates & FWL_WGTSTATE_Disabled)
-    return;
-
-  CFX_RectF& rtBtn = IsDropDownStyle() ? m_rtBtn : m_rtClient;
-  if (!rtBtn.Contains(pMsg->m_pos))
-    return;
-
-  if (IsDropDownStyle() && m_pEdit)
-    MatchEditText();
-
-  m_bLButtonDown = true;
-  m_iBtnState = CFWL_PartState_Pressed;
-  RepaintRect(m_rtClient);
-
-  ShowDropList(true);
-  m_iBtnState = CFWL_PartState_Normal;
-  RepaintRect(m_rtClient);
-}
-
-void CFWL_ComboBox::OnLButtonUp(CFWL_MessageMouse* pMsg) {
-  m_bLButtonDown = false;
-  if (m_rtBtn.Contains(pMsg->m_pos))
-    m_iBtnState = CFWL_PartState_Hovered;
-  else
-    m_iBtnState = CFWL_PartState_Normal;
-
-  RepaintRect(m_rtBtn);
-}
-
-void CFWL_ComboBox::OnMouseMove(CFWL_MessageMouse* pMsg) {
-  int32_t iOldState = m_iBtnState;
-  if (m_rtBtn.Contains(pMsg->m_pos)) {
-    m_iBtnState =
-        m_bLButtonDown ? CFWL_PartState_Pressed : CFWL_PartState_Hovered;
-  } else {
-    m_iBtnState = CFWL_PartState_Normal;
-  }
-  if ((iOldState != m_iBtnState) &&
-      !((m_pProperties->m_dwStates & FWL_WGTSTATE_Disabled) ==
-        FWL_WGTSTATE_Disabled)) {
-    RepaintRect(m_rtBtn);
-  }
-}
-
-void CFWL_ComboBox::OnMouseLeave(CFWL_MessageMouse* pMsg) {
-  if (!IsDropListVisible() &&
-      !((m_pProperties->m_dwStates & FWL_WGTSTATE_Disabled) ==
-        FWL_WGTSTATE_Disabled)) {
-    m_iBtnState = CFWL_PartState_Normal;
-    RepaintRect(m_rtBtn);
-  }
-}
-
-void CFWL_ComboBox::OnKey(CFWL_MessageKey* pMsg) {
-  uint32_t dwKeyCode = pMsg->m_dwKeyCode;
-  if (dwKeyCode == FWL_VKEY_Tab)
-    return;
-  if (pMsg->m_pDstTarget == this)
-    DoSubCtrlKey(pMsg);
-}
-
-void CFWL_ComboBox::DoSubCtrlKey(CFWL_MessageKey* pMsg) {
-  uint32_t dwKeyCode = pMsg->m_dwKeyCode;
-  const bool bUp = dwKeyCode == FWL_VKEY_Up;
-  const bool bDown = dwKeyCode == FWL_VKEY_Down;
-  if (bUp || bDown) {
-    int32_t iCount = m_pListBox->CountItems(nullptr);
-    if (iCount < 1)
-      return;
-
-    bool bMatchEqual = false;
-    int32_t iCurSel = m_iCurSel;
-    bool bDropDown = IsDropDownStyle();
-    if (bDropDown && m_pEdit) {
-      WideString wsText = m_pEdit->GetText();
-      iCurSel = m_pListBox->MatchItem(wsText);
-      if (iCurSel >= 0) {
-        CFWL_ListItem* hItem = m_pListBox->GetItem(this, iCurSel);
-        bMatchEqual = wsText == (hItem ? hItem->GetText() : L"");
-      }
-    }
-    if (iCurSel < 0) {
-      iCurSel = 0;
-    } else if (!bDropDown || bMatchEqual) {
-      if ((bUp && iCurSel == 0) || (bDown && iCurSel == iCount - 1))
-        return;
-      if (bUp)
-        iCurSel--;
-      else
-        iCurSel++;
-    }
-    m_iCurSel = iCurSel;
-    if (bDropDown && m_pEdit)
-      SyncEditText(m_iCurSel);
-    else
-      RepaintRect(m_rtClient);
-    return;
-  }
-
-  if (IsDropDownStyle())
-    m_pEdit->GetDelegate()->OnProcessMessage(pMsg);
-}
-
-void CFWL_ComboBox::DisForm_OnProcessMessage(CFWL_Message* pMessage) {
   if (!pMessage)
     return;
 
@@ -898,12 +434,12 @@
   switch (pMessage->GetType()) {
     case CFWL_Message::Type::SetFocus: {
       backDefault = false;
-      DisForm_OnFocusChanged(pMessage, true);
+      OnFocusChanged(pMessage, true);
       break;
     }
     case CFWL_Message::Type::KillFocus: {
       backDefault = false;
-      DisForm_OnFocusChanged(pMessage, false);
+      OnFocusChanged(pMessage, false);
       break;
     }
     case CFWL_Message::Type::Mouse: {
@@ -911,7 +447,7 @@
       CFWL_MessageMouse* pMsg = static_cast<CFWL_MessageMouse*>(pMessage);
       switch (pMsg->m_dwCmd) {
         case FWL_MouseCommand::LeftButtonDown:
-          DisForm_OnLButtonDown(pMsg);
+          OnLButtonDown(pMsg);
           break;
         case FWL_MouseCommand::LeftButtonUp:
           OnLButtonUp(pMsg);
@@ -926,43 +462,71 @@
       CFWL_MessageKey* pKey = static_cast<CFWL_MessageKey*>(pMessage);
       if (pKey->m_dwCmd == FWL_KeyCommand::KeyUp)
         break;
-      if (DisForm_IsDropListVisible() &&
-          pKey->m_dwCmd == FWL_KeyCommand::KeyDown) {
-        bool bListKey = pKey->m_dwKeyCode == FWL_VKEY_Up ||
-                        pKey->m_dwKeyCode == FWL_VKEY_Down ||
-                        pKey->m_dwKeyCode == FWL_VKEY_Return ||
-                        pKey->m_dwKeyCode == FWL_VKEY_Escape;
+      if (IsDropListVisible() && pKey->m_dwCmd == FWL_KeyCommand::KeyDown) {
+        bool bListKey = pKey->m_dwKeyCode == XFA_FWL_VKEY_Up ||
+                        pKey->m_dwKeyCode == XFA_FWL_VKEY_Down ||
+                        pKey->m_dwKeyCode == XFA_FWL_VKEY_Return ||
+                        pKey->m_dwKeyCode == XFA_FWL_VKEY_Escape;
         if (bListKey) {
           m_pListBox->GetDelegate()->OnProcessMessage(pMessage);
           break;
         }
       }
-      DisForm_OnKey(pKey);
+      OnKey(pKey);
       break;
     }
     default:
       break;
   }
-  if (backDefault)
+  // Dst target could be |this|, continue only if not destroyed by above.
+  if (backDefault && pMessage->GetDstTarget())
     CFWL_Widget::OnProcessMessage(pMessage);
 }
 
-void CFWL_ComboBox::DisForm_OnLButtonDown(CFWL_MessageMouse* pMsg) {
-  bool bDropDown = DisForm_IsDropListVisible();
+void CFWL_ComboBox::OnProcessEvent(CFWL_Event* pEvent) {
+  CFWL_Event::Type type = pEvent->GetType();
+  if (type == CFWL_Event::Type::Scroll) {
+    CFWL_EventScroll* pScrollEvent = static_cast<CFWL_EventScroll*>(pEvent);
+    CFWL_EventScroll pScrollEv(this);
+    pScrollEv.m_iScrollCode = pScrollEvent->m_iScrollCode;
+    pScrollEv.m_fPos = pScrollEvent->m_fPos;
+    DispatchEvent(&pScrollEv);
+  } else if (type == CFWL_Event::Type::TextWillChange) {
+    CFWL_Event pTemp(CFWL_Event::Type::EditChanged, this);
+    DispatchEvent(&pTemp);
+  }
+}
+
+void CFWL_ComboBox::OnDrawWidget(CXFA_Graphics* pGraphics,
+                                 const CFX_Matrix& matrix) {
+  DrawWidget(pGraphics, matrix);
+}
+
+void CFWL_ComboBox::OnLButtonUp(CFWL_MessageMouse* pMsg) {
+  if (m_rtBtn.Contains(pMsg->m_pos))
+    m_iBtnState = CFWL_PartState_Hovered;
+  else
+    m_iBtnState = CFWL_PartState_Normal;
+
+  RepaintRect(m_rtBtn);
+}
+
+void CFWL_ComboBox::OnLButtonDown(CFWL_MessageMouse* pMsg) {
+  bool bDropDown = IsDropListVisible();
   CFX_RectF& rtBtn = bDropDown ? m_rtBtn : m_rtClient;
   if (!rtBtn.Contains(pMsg->m_pos))
     return;
 
-  if (DisForm_IsDropListVisible()) {
-    DisForm_ShowDropList(false);
+  if (IsDropListVisible()) {
+    ShowDropList(false);
     return;
   }
   if (m_pEdit)
     MatchEditText();
-  DisForm_ShowDropList(true);
+  ShowDropList(true);
 }
 
-void CFWL_ComboBox::DisForm_OnFocusChanged(CFWL_Message* pMsg, bool bSet) {
+void CFWL_ComboBox::OnFocusChanged(CFWL_Message* pMsg, bool bSet) {
   if (bSet) {
     m_pProperties->m_dwStates |= FWL_WGTSTATE_Focused;
     if ((m_pEdit->GetStates() & FWL_WGTSTATE_Focused) == 0) {
@@ -971,16 +535,16 @@
     }
   } else {
     m_pProperties->m_dwStates &= ~FWL_WGTSTATE_Focused;
-    DisForm_ShowDropList(false);
+    ShowDropList(false);
     CFWL_MessageKillFocus msg(m_pEdit.get());
     m_pEdit->GetDelegate()->OnProcessMessage(&msg);
   }
 }
 
-void CFWL_ComboBox::DisForm_OnKey(CFWL_MessageKey* pMsg) {
+void CFWL_ComboBox::OnKey(CFWL_MessageKey* pMsg) {
   uint32_t dwKeyCode = pMsg->m_dwKeyCode;
-  const bool bUp = dwKeyCode == FWL_VKEY_Up;
-  const bool bDown = dwKeyCode == FWL_VKEY_Down;
+  const bool bUp = dwKeyCode == XFA_FWL_VKEY_Up;
+  const bool bDown = dwKeyCode == XFA_FWL_VKEY_Down;
   if (bUp || bDown) {
     CFWL_ComboList* pComboList = m_pListBox.get();
     int32_t iCount = pComboList->CountItems(nullptr);
@@ -991,10 +555,10 @@
     int32_t iCurSel = m_iCurSel;
     if (m_pEdit) {
       WideString wsText = m_pEdit->GetText();
-      iCurSel = pComboList->MatchItem(wsText);
+      iCurSel = pComboList->MatchItem(wsText.AsStringView());
       if (iCurSel >= 0) {
         CFWL_ListItem* item = m_pListBox->GetSelItem(iCurSel);
-        bMatchEqual = wsText == (item ? item->GetText() : L"");
+        bMatchEqual = wsText == (item ? item->GetText() : WideString());
       }
     }
     if (iCurSel < 0) {
@@ -1014,3 +578,11 @@
   if (m_pEdit)
     m_pEdit->GetDelegate()->OnProcessMessage(pMsg);
 }
+
+void CFWL_ComboBox::GetPopupPos(float fMinHeight,
+                                float fMaxHeight,
+                                const CFX_RectF& rtAnchor,
+                                CFX_RectF* pPopupRect) {
+  m_pWidgetMgr->GetAdapterPopupPos(this, fMinHeight, fMaxHeight, rtAnchor,
+                                   pPopupRect);
+}
diff --git a/xfa/fwl/cfwl_combobox.h b/xfa/fwl/cfwl_combobox.h
index a9dc635..39c952c 100644
--- a/xfa/fwl/cfwl_combobox.h
+++ b/xfa/fwl/cfwl_combobox.h
@@ -9,17 +9,13 @@
 
 #include <memory>
 
-#include "xfa/fwl/cfwl_comboboxproxy.h"
 #include "xfa/fwl/cfwl_comboedit.h"
 #include "xfa/fwl/cfwl_combolist.h"
-#include "xfa/fwl/cfwl_form.h"
 #include "xfa/fwl/cfwl_listbox.h"
 #include "xfa/fxgraphics/cxfa_graphics.h"
 
 class CFWL_WidgetProperties;
 class CFWL_ComboBox;
-class CFWL_ComboBoxProxy;
-class CFWL_FormProxy;
 class CFWL_ListBox;
 class CFWL_Widget;
 
@@ -39,7 +35,7 @@
 #define FWL_STYLEEXT_CMB_ListItemAlignMask (3L << 10)
 #define FWL_STYLEEXT_CMB_ReadOnly (1L << 13)
 
-class CFWL_ComboBox : public CFWL_Widget {
+class CFWL_ComboBox final : public CFWL_Widget {
  public:
   explicit CFWL_ComboBox(const CFWL_App* pApp);
   ~CFWL_ComboBox() override;
@@ -63,7 +59,7 @@
   int32_t GetCurSel() const { return m_iCurSel; }
   void SetCurSel(int32_t iSel);
 
-  void AddString(const WideStringView& wsText);
+  void AddString(const WideString& wsText);
   void RemoveAt(int32_t iIndex);
   void RemoveAll();
 
@@ -92,12 +88,6 @@
 
   CFX_RectF GetBBox() const;
   void EditModifyStylesEx(uint32_t dwStylesExAdded, uint32_t dwStylesExRemoved);
-
-  void DrawStretchHandler(CXFA_Graphics* pGraphics, const CFX_Matrix* pMatrix);
-  bool IsDropListVisible() const {
-    return m_pComboBoxProxy &&
-           !(m_pComboBoxProxy->GetStates() & FWL_WGTSTATE_Invisible);
-  }
   void ShowDropList(bool bActivate);
 
   CFWL_ComboEdit* GetComboEdit() const { return m_pEdit.get(); }
@@ -115,45 +105,26 @@
   void ResetTheme();
   void ResetEditAlignment();
   void ResetListItemAlignment();
-  void InitProxyForm();
-  void OnFocusChanged(CFWL_Message* pMsg, bool bSet);
-  void OnLButtonDown(CFWL_MessageMouse* pMsg);
+  void GetPopupPos(float fMinHeight,
+                   float fMaxHeight,
+                   const CFX_RectF& rtAnchor,
+                   CFX_RectF* pPopupRect);
   void OnLButtonUp(CFWL_MessageMouse* pMsg);
-  void OnMouseMove(CFWL_MessageMouse* pMsg);
-  void OnMouseLeave(CFWL_MessageMouse* pMsg);
-  void OnKey(CFWL_MessageKey* pMsg);
-  void DoSubCtrlKey(CFWL_MessageKey* pMsg);
 
-  void DisForm_InitComboList();
-  void DisForm_InitComboEdit();
-  void DisForm_ShowDropList(bool bActivate);
-  bool DisForm_IsDropListVisible() const {
-    return !(m_pListBox->GetStates() & FWL_WGTSTATE_Invisible);
-  }
-  void DisForm_ModifyStylesEx(uint32_t dwStylesExAdded,
-                              uint32_t dwStylesExRemoved);
-  void DisForm_Update();
-  FWL_WidgetHit DisForm_HitTest(const CFX_PointF& point);
-  void DisForm_DrawWidget(CXFA_Graphics* pGraphics, const CFX_Matrix* pMatrix);
-  CFX_RectF DisForm_GetBBox() const;
-  void DisForm_Layout();
-  void DisForm_OnProcessMessage(CFWL_Message* pMessage);
-  void DisForm_OnLButtonDown(CFWL_MessageMouse* pMsg);
-  void DisForm_OnFocusChanged(CFWL_Message* pMsg, bool bSet);
-  void DisForm_OnKey(CFWL_MessageKey* pMsg);
+  void InitComboList();
+  void InitComboEdit();
+  bool IsDropListVisible() const { return m_pListBox->IsVisible(); }
+  void OnLButtonDown(CFWL_MessageMouse* pMsg);
+  void OnFocusChanged(CFWL_Message* pMsg, bool bSet);
+  void OnKey(CFWL_MessageKey* pMsg);
 
   CFX_RectF m_rtClient;
   CFX_RectF m_rtContent;
   CFX_RectF m_rtBtn;
-  CFX_RectF m_rtList;
-  CFX_RectF m_rtProxy;
-  CFX_RectF m_rtHandler;
   std::unique_ptr<CFWL_ComboEdit> m_pEdit;
   std::unique_ptr<CFWL_ComboList> m_pListBox;
-  CFWL_ComboBoxProxy* m_pComboBoxProxy;  // Can this be a unique_ptr?
-  bool m_bLButtonDown;
-  int32_t m_iCurSel;
-  int32_t m_iBtnState;
+  int32_t m_iCurSel = -1;
+  int32_t m_iBtnState = CFWL_PartState_Normal;
 };
 
 #endif  // XFA_FWL_CFWL_COMBOBOX_H_
diff --git a/xfa/fwl/cfwl_comboboxproxy.cpp b/xfa/fwl/cfwl_comboboxproxy.cpp
deleted file mode 100644
index d1db1c0..0000000
--- a/xfa/fwl/cfwl_comboboxproxy.cpp
+++ /dev/null
@@ -1,112 +0,0 @@
-// Copyright 2016 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
-
-#include "xfa/fwl/cfwl_comboboxproxy.h"
-
-#include <memory>
-#include <utility>
-
-#include "xfa/fwl/cfwl_app.h"
-#include "xfa/fwl/cfwl_combobox.h"
-#include "xfa/fwl/cfwl_messagekillfocus.h"
-#include "xfa/fwl/cfwl_messagemouse.h"
-#include "xfa/fwl/cfwl_notedriver.h"
-
-CFWL_ComboBoxProxy::CFWL_ComboBoxProxy(
-    CFWL_ComboBox* pComboBox,
-    const CFWL_App* app,
-    std::unique_ptr<CFWL_WidgetProperties> properties,
-    CFWL_Widget* pOuter)
-    : CFWL_FormProxy(app, std::move(properties), pOuter),
-      m_bLButtonDown(false),
-      m_bLButtonUpSelf(false),
-      m_pComboBox(pComboBox) {}
-
-CFWL_ComboBoxProxy::~CFWL_ComboBoxProxy() {}
-
-void CFWL_ComboBoxProxy::OnProcessMessage(CFWL_Message* pMessage) {
-  if (!pMessage)
-    return;
-
-  switch (pMessage->GetType()) {
-    case CFWL_Message::Type::Mouse: {
-      CFWL_MessageMouse* pMsg = static_cast<CFWL_MessageMouse*>(pMessage);
-      switch (pMsg->m_dwCmd) {
-        case FWL_MouseCommand::LeftButtonDown:
-          OnLButtonDown(pMsg);
-          break;
-        case FWL_MouseCommand::LeftButtonUp:
-          OnLButtonUp(pMsg);
-          break;
-        default:
-          break;
-      }
-      break;
-    }
-    case CFWL_Message::Type::KillFocus:
-      OnFocusChanged(pMessage, false);
-      break;
-    case CFWL_Message::Type::SetFocus:
-      OnFocusChanged(pMessage, true);
-      break;
-    default:
-      break;
-  }
-  CFWL_Widget::OnProcessMessage(pMessage);
-}
-
-void CFWL_ComboBoxProxy::OnDrawWidget(CXFA_Graphics* pGraphics,
-                                      const CFX_Matrix& matrix) {
-  m_pComboBox->DrawStretchHandler(pGraphics, &matrix);
-}
-
-void CFWL_ComboBoxProxy::OnLButtonDown(CFWL_Message* pMessage) {
-  const CFWL_App* pApp = GetOwnerApp();
-  if (!pApp)
-    return;
-
-  CFWL_NoteDriver* pDriver =
-      static_cast<CFWL_NoteDriver*>(pApp->GetNoteDriver());
-  CFWL_MessageMouse* pMsg = static_cast<CFWL_MessageMouse*>(pMessage);
-  if (CFX_RectF(0, 0, GetWidgetRect().Size()).Contains(pMsg->m_pos)) {
-    m_bLButtonDown = true;
-    pDriver->SetGrab(this, true);
-  } else {
-    m_bLButtonDown = false;
-    pDriver->SetGrab(this, false);
-    m_pComboBox->ShowDropList(false);
-  }
-}
-
-void CFWL_ComboBoxProxy::OnLButtonUp(CFWL_Message* pMessage) {
-  m_bLButtonDown = false;
-  const CFWL_App* pApp = GetOwnerApp();
-  if (!pApp)
-    return;
-
-  CFWL_NoteDriver* pDriver =
-      static_cast<CFWL_NoteDriver*>(pApp->GetNoteDriver());
-  pDriver->SetGrab(this, false);
-  if (!m_bLButtonUpSelf) {
-    m_bLButtonUpSelf = true;
-    return;
-  }
-
-  CFWL_MessageMouse* pMsg = static_cast<CFWL_MessageMouse*>(pMessage);
-  if (!CFX_RectF(0, 0, GetWidgetRect().Size()).Contains(pMsg->m_pos) &&
-      m_pComboBox->IsDropListVisible()) {
-    m_pComboBox->ShowDropList(false);
-  }
-}
-
-void CFWL_ComboBoxProxy::OnFocusChanged(CFWL_Message* pMessage, bool bSet) {
-  if (bSet)
-    return;
-
-  CFWL_MessageKillFocus* pMsg = static_cast<CFWL_MessageKillFocus*>(pMessage);
-  if (!pMsg->m_pSetFocus)
-    m_pComboBox->ShowDropList(false);
-}
diff --git a/xfa/fwl/cfwl_comboboxproxy.h b/xfa/fwl/cfwl_comboboxproxy.h
deleted file mode 100644
index bb21707..0000000
--- a/xfa/fwl/cfwl_comboboxproxy.h
+++ /dev/null
@@ -1,41 +0,0 @@
-// Copyright 2016 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_FWL_CFWL_COMBOBOXPROXY_H_
-#define XFA_FWL_CFWL_COMBOBOXPROXY_H_
-
-#include <memory>
-
-#include "xfa/fwl/cfwl_formproxy.h"
-
-class CFWL_ComboBox;
-
-class CFWL_ComboBoxProxy : public CFWL_FormProxy {
- public:
-  CFWL_ComboBoxProxy(CFWL_ComboBox* pCombobBox,
-                     const CFWL_App* app,
-                     std::unique_ptr<CFWL_WidgetProperties> properties,
-                     CFWL_Widget* pOuter);
-  ~CFWL_ComboBoxProxy() override;
-
-  // CFWL_FormProxy
-  void OnProcessMessage(CFWL_Message* pMessage) override;
-  void OnDrawWidget(CXFA_Graphics* pGraphics,
-                    const CFX_Matrix& matrix) override;
-
-  void Reset() { m_bLButtonUpSelf = false; }
-
- private:
-  void OnLButtonDown(CFWL_Message* pMsg);
-  void OnLButtonUp(CFWL_Message* pMsg);
-  void OnFocusChanged(CFWL_Message* pMsg, bool bSet);
-
-  bool m_bLButtonDown;
-  bool m_bLButtonUpSelf;
-  CFWL_ComboBox* m_pComboBox;
-};
-
-#endif  // XFA_FWL_CFWL_COMBOBOXPROXY_H_
diff --git a/xfa/fwl/cfwl_comboedit.cpp b/xfa/fwl/cfwl_comboedit.cpp
index 4fa1277..6ab081a 100644
--- a/xfa/fwl/cfwl_comboedit.cpp
+++ b/xfa/fwl/cfwl_comboedit.cpp
@@ -18,9 +18,10 @@
     std::unique_ptr<CFWL_WidgetProperties> properties,
     CFWL_Widget* pOuter)
     : CFWL_Edit(app, std::move(properties), pOuter) {
-  m_pOuter = static_cast<CFWL_ComboBox*>(pOuter);
 }
 
+CFWL_ComboEdit::~CFWL_ComboEdit() = default;
+
 void CFWL_ComboEdit::ClearSelected() {
   ClearSelection();
   RepaintRect(GetRTClient());
@@ -62,7 +63,6 @@
       if ((pMsg->m_dwCmd == FWL_MouseCommand::LeftButtonDown) &&
           ((m_pProperties->m_dwStates & FWL_WGTSTATE_Focused) == 0)) {
         SetSelected();
-        m_pOuter->SetFocus(true);
       }
       break;
     }
diff --git a/xfa/fwl/cfwl_comboedit.h b/xfa/fwl/cfwl_comboedit.h
index efdabd3..68e6caa 100644
--- a/xfa/fwl/cfwl_comboedit.h
+++ b/xfa/fwl/cfwl_comboedit.h
@@ -15,11 +15,12 @@
 
 class CFWL_ComboBox;
 
-class CFWL_ComboEdit : public CFWL_Edit {
+class CFWL_ComboEdit final : public CFWL_Edit {
  public:
   CFWL_ComboEdit(const CFWL_App* app,
                  std::unique_ptr<CFWL_WidgetProperties> properties,
                  CFWL_Widget* pOuter);
+  ~CFWL_ComboEdit() override;
 
   // CFWL_Edit.
   void OnProcessMessage(CFWL_Message* pMessage) override;
@@ -27,9 +28,6 @@
   void ClearSelected();
   void SetSelected();
   void FlagFocus(bool bSet);
-
- private:
-  CFWL_ComboBox* m_pOuter;
 };
 
 #endif  // XFA_FWL_CFWL_COMBOEDIT_H_
diff --git a/xfa/fwl/cfwl_combolist.cpp b/xfa/fwl/cfwl_combolist.cpp
index 1180acf..d25f312 100644
--- a/xfa/fwl/cfwl_combolist.cpp
+++ b/xfa/fwl/cfwl_combolist.cpp
@@ -9,31 +9,31 @@
 #include <memory>
 #include <utility>
 
-#include "third_party/base/ptr_util.h"
 #include "xfa/fwl/cfwl_combobox.h"
 #include "xfa/fwl/cfwl_comboedit.h"
 #include "xfa/fwl/cfwl_listbox.h"
 #include "xfa/fwl/cfwl_messagekey.h"
 #include "xfa/fwl/cfwl_messagekillfocus.h"
 #include "xfa/fwl/cfwl_messagemouse.h"
+#include "xfa/fwl/fwl_widgetdef.h"
 
 CFWL_ComboList::CFWL_ComboList(
     const CFWL_App* app,
     std::unique_ptr<CFWL_WidgetProperties> properties,
     CFWL_Widget* pOuter)
-    : CFWL_ListBox(app, std::move(properties), pOuter), m_bNotifyOwner(true) {
+    : CFWL_ListBox(app, std::move(properties), pOuter) {
   ASSERT(pOuter);
 }
 
-int32_t CFWL_ComboList::MatchItem(const WideString& wsMatch) {
+int32_t CFWL_ComboList::MatchItem(WideStringView wsMatch) {
   if (wsMatch.IsEmpty())
     return -1;
 
   int32_t iCount = CountItems(this);
   for (int32_t i = 0; i < iCount; i++) {
     CFWL_ListItem* hItem = GetItem(this, i);
-    WideString wsText = hItem ? hItem->GetText() : L"";
-    auto pos = wsText.Find(wsMatch.c_str());
+    WideString wsText = hItem ? hItem->GetText() : WideString();
+    auto pos = wsText.Find(wsMatch);
     if (pos.has_value() && pos.value() == 0)
       return i;
   }
@@ -122,8 +122,8 @@
 
   CFWL_MessageKillFocus* pKill = static_cast<CFWL_MessageKillFocus*>(pMsg);
   CFWL_ComboBox* pOuter = static_cast<CFWL_ComboBox*>(m_pOuter);
-  if (pKill->m_pSetFocus == m_pOuter ||
-      pKill->m_pSetFocus == pOuter->GetComboEdit()) {
+  if (pKill->IsFocusedOnWidget(m_pOuter) ||
+      pKill->IsFocusedOnWidget(pOuter->GetComboEdit())) {
     pOuter->ShowDropList(false);
   }
 }
@@ -188,13 +188,13 @@
   if (pKey->m_dwCmd == FWL_KeyCommand::KeyDown) {
     uint32_t dwKeyCode = pKey->m_dwKeyCode;
     switch (dwKeyCode) {
-      case FWL_VKEY_Return:
-      case FWL_VKEY_Escape: {
+      case XFA_FWL_VKEY_Return:
+      case XFA_FWL_VKEY_Escape: {
         pOuter->ShowDropList(false);
         return true;
       }
-      case FWL_VKEY_Up:
-      case FWL_VKEY_Down: {
+      case XFA_FWL_VKEY_Up:
+      case XFA_FWL_VKEY_Down: {
         OnDropListKeyDown(pKey);
         pOuter->ProcessSelChanged(false);
         return true;
@@ -208,7 +208,7 @@
     bPropagate = true;
   }
   if (bPropagate) {
-    pKey->m_pDstTarget = m_pOuter;
+    pKey->SetDstTarget(m_pOuter);
     pOuter->GetDelegate()->OnProcessMessage(pKey);
     return true;
   }
@@ -218,10 +218,10 @@
 void CFWL_ComboList::OnDropListKeyDown(CFWL_MessageKey* pKey) {
   uint32_t dwKeyCode = pKey->m_dwKeyCode;
   switch (dwKeyCode) {
-    case FWL_VKEY_Up:
-    case FWL_VKEY_Down:
-    case FWL_VKEY_Home:
-    case FWL_VKEY_End: {
+    case XFA_FWL_VKEY_Up:
+    case XFA_FWL_VKEY_Down:
+    case XFA_FWL_VKEY_Home:
+    case XFA_FWL_VKEY_End: {
       CFWL_ComboBox* pOuter = static_cast<CFWL_ComboBox*>(m_pOuter);
       CFWL_ListItem* hItem = GetItem(this, pOuter->GetCurrentSelection());
       hItem = GetListItem(hItem, dwKeyCode);
diff --git a/xfa/fwl/cfwl_combolist.h b/xfa/fwl/cfwl_combolist.h
index a4d5135..c275c72 100644
--- a/xfa/fwl/cfwl_combolist.h
+++ b/xfa/fwl/cfwl_combolist.h
@@ -13,7 +13,7 @@
 #include "xfa/fwl/cfwl_widget.h"
 #include "xfa/fwl/cfwl_widgetproperties.h"
 
-class CFWL_ComboList : public CFWL_ListBox {
+class CFWL_ComboList final : public CFWL_ListBox {
  public:
   CFWL_ComboList(const CFWL_App* app,
                  std::unique_ptr<CFWL_WidgetProperties> properties,
@@ -22,10 +22,8 @@
   // CFWL_ListBox.
   void OnProcessMessage(CFWL_Message* pMessage) override;
 
-  int32_t MatchItem(const WideString& wsMatch);
-
+  int32_t MatchItem(WideStringView wsMatch);
   void ChangeSelected(int32_t iSel);
-
   void SetNotifyOwner(bool notify) { m_bNotifyOwner = notify; }
 
  private:
@@ -37,7 +35,7 @@
   bool OnDropListKey(CFWL_MessageKey* pKey);
   void OnDropListKeyDown(CFWL_MessageKey* pKey);
 
-  bool m_bNotifyOwner;
+  bool m_bNotifyOwner = true;
 };
 
 #endif  // XFA_FWL_CFWL_COMBOLIST_H_
diff --git a/xfa/fwl/cfwl_datetimeedit.cpp b/xfa/fwl/cfwl_datetimeedit.cpp
index f1ddbb1..313e89a 100644
--- a/xfa/fwl/cfwl_datetimeedit.cpp
+++ b/xfa/fwl/cfwl_datetimeedit.cpp
@@ -9,7 +9,6 @@
 #include <memory>
 #include <utility>
 
-#include "third_party/base/ptr_util.h"
 #include "xfa/fwl/cfwl_datetimepicker.h"
 #include "xfa/fwl/cfwl_messagemouse.h"
 #include "xfa/fwl/cfwl_widgetmgr.h"
@@ -20,23 +19,10 @@
     CFWL_Widget* pOuter)
     : CFWL_Edit(app, std::move(properties), pOuter) {}
 
+CFWL_DateTimeEdit::~CFWL_DateTimeEdit() = default;
+
 void CFWL_DateTimeEdit::OnProcessMessage(CFWL_Message* pMessage) {
-  if (m_pWidgetMgr->IsFormDisabled()) {
-    DisForm_OnProcessMessage(pMessage);
-    return;
-  }
-
-  CFWL_Message::Type type = pMessage->GetType();
-  if (type == CFWL_Message::Type::SetFocus ||
-      type == CFWL_Message::Type::KillFocus) {
-    CFWL_Widget* pOuter = GetOuter();
-    pOuter->GetDelegate()->OnProcessMessage(pMessage);
-  }
-}
-
-void CFWL_DateTimeEdit::DisForm_OnProcessMessage(CFWL_Message* pMessage) {
-  if (!m_pWidgetMgr->IsFormDisabled() ||
-      pMessage->GetType() != CFWL_Message::Type::Mouse) {
+  if (pMessage->GetType() != CFWL_Message::Type::Mouse) {
     CFWL_Edit::OnProcessMessage(pMessage);
     return;
   }
diff --git a/xfa/fwl/cfwl_datetimeedit.h b/xfa/fwl/cfwl_datetimeedit.h
index 923ad05..e617ff4 100644
--- a/xfa/fwl/cfwl_datetimeedit.h
+++ b/xfa/fwl/cfwl_datetimeedit.h
@@ -13,17 +13,15 @@
 #include "xfa/fwl/cfwl_widget.h"
 #include "xfa/fwl/cfwl_widgetproperties.h"
 
-class CFWL_DateTimeEdit : public CFWL_Edit {
+class CFWL_DateTimeEdit final : public CFWL_Edit {
  public:
   CFWL_DateTimeEdit(const CFWL_App* app,
                     std::unique_ptr<CFWL_WidgetProperties> properties,
                     CFWL_Widget* pOuter);
+  ~CFWL_DateTimeEdit() override;
 
   // CFWL_Edit.
   void OnProcessMessage(CFWL_Message* pMessage) override;
-
- private:
-  void DisForm_OnProcessMessage(CFWL_Message* pMessage);
 };
 
 #endif  // XFA_FWL_CFWL_DATETIMEEDIT_H_
diff --git a/xfa/fwl/cfwl_datetimepicker.cpp b/xfa/fwl/cfwl_datetimepicker.cpp
index f3da454..11ea810 100644
--- a/xfa/fwl/cfwl_datetimepicker.cpp
+++ b/xfa/fwl/cfwl_datetimepicker.cpp
@@ -12,7 +12,6 @@
 #include "third_party/base/ptr_util.h"
 #include "xfa/fwl/cfwl_event.h"
 #include "xfa/fwl/cfwl_eventselectchanged.h"
-#include "xfa/fwl/cfwl_formproxy.h"
 #include "xfa/fwl/cfwl_messagemouse.h"
 #include "xfa/fwl/cfwl_messagesetfocus.h"
 #include "xfa/fwl/cfwl_notedriver.h"
@@ -26,12 +25,7 @@
 
 }  // namespace
 CFWL_DateTimePicker::CFWL_DateTimePicker(const CFWL_App* app)
-    : CFWL_Widget(app, pdfium::MakeUnique<CFWL_WidgetProperties>(), nullptr),
-      m_iBtnState(1),
-      m_iYear(-1),
-      m_iMonth(-1),
-      m_iDay(-1),
-      m_bLBtnDown(false) {
+    : CFWL_Widget(app, pdfium::MakeUnique<CFWL_WidgetProperties>(), nullptr) {
   m_pProperties->m_dwStyleExes = FWL_STYLEEXT_DTP_ShortDateFormat;
 
   auto monthProp = pdfium::MakeUnique<CFWL_WidgetProperties>();
@@ -64,50 +58,42 @@
 }
 
 void CFWL_DateTimePicker::Update() {
-  if (m_pWidgetMgr->IsFormDisabled()) {
-    DisForm_Update();
-    return;
-  }
   if (m_iLock)
     return;
+
   if (!m_pProperties->m_pThemeProvider)
     m_pProperties->m_pThemeProvider = GetAvailableTheme();
-
-  m_pEdit->SetThemeProvider(m_pProperties->m_pThemeProvider);
+  m_pEdit->SetThemeProvider(m_pProperties->m_pThemeProvider.Get());
   m_rtClient = GetClientRect();
+  m_pEdit->SetWidgetRect(m_rtClient);
+  ResetEditAlignment();
+  m_pEdit->Update();
+  if (!m_pMonthCal->GetThemeProvider())
+    m_pMonthCal->SetThemeProvider(m_pProperties->m_pThemeProvider.Get());
 
   IFWL_ThemeProvider* theme = GetAvailableTheme();
   if (!theme)
     return;
 
-  float fBtn = theme->GetScrollBarWidth();
-  m_rtBtn = CFX_RectF(m_rtClient.right() - fBtn, m_rtClient.top, fBtn - 1,
-                      m_rtClient.height - 1);
-
-  CFX_RectF rtEdit(m_rtClient.left, m_rtClient.top, m_rtClient.width - fBtn,
-                   m_rtClient.height);
-  m_pEdit->SetWidgetRect(rtEdit);
-  ResetEditAlignment();
-  m_pEdit->Update();
-  if (!(m_pMonthCal->GetThemeProvider()))
-    m_pMonthCal->SetThemeProvider(m_pProperties->m_pThemeProvider);
-
+  m_fBtn = theme->GetScrollBarWidth();
   CFX_RectF rtMonthCal = m_pMonthCal->GetAutosizedWidgetRect();
   CFX_RectF rtPopUp(rtMonthCal.left, rtMonthCal.top + kDateTimePickerHeight,
                     rtMonthCal.width, rtMonthCal.height);
   m_pMonthCal->SetWidgetRect(rtPopUp);
   m_pMonthCal->Update();
-  return;
 }
 
 FWL_WidgetHit CFWL_DateTimePicker::HitTest(const CFX_PointF& point) {
-  if (m_pWidgetMgr->IsFormDisabled())
-    return DisForm_HitTest(point);
-  if (m_rtClient.Contains(point))
+  CFX_RectF rect(0, 0, m_pProperties->m_rtWidget.width,
+                 m_pProperties->m_rtWidget.height);
+  if (rect.Contains(point))
+    return FWL_WidgetHit::Edit;
+  if (NeedsToShowButton())
+    rect.width += m_fBtn;
+  if (rect.Contains(point))
     return FWL_WidgetHit::Client;
   if (IsMonthCalendarVisible()) {
-    CFX_RectF rect = m_pMonthCal->GetWidgetRect();
-    if (rect.Contains(point))
+    if (m_pMonthCal->GetWidgetRect().Contains(point))
       return FWL_WidgetHit::Client;
   }
   return FWL_WidgetHit::Unknown;
@@ -117,18 +103,30 @@
                                      const CFX_Matrix& matrix) {
   if (!pGraphics)
     return;
-  if (!m_pProperties->m_pThemeProvider)
+
+  IFWL_ThemeProvider* pTheme = m_pProperties->m_pThemeProvider.Get();
+  if (!pTheme)
     return;
 
-  IFWL_ThemeProvider* pTheme = m_pProperties->m_pThemeProvider;
   if (HasBorder())
     DrawBorder(pGraphics, CFWL_Part::Border, pTheme, matrix);
   if (!m_rtBtn.IsEmpty())
     DrawDropDownButton(pGraphics, pTheme, &matrix);
-  if (m_pWidgetMgr->IsFormDisabled()) {
-    DisForm_DrawWidget(pGraphics, &matrix);
-    return;
+
+  if (m_pEdit) {
+    CFX_RectF rtEdit = m_pEdit->GetWidgetRect();
+
+    CFX_Matrix mt(1, 0, 0, 1, rtEdit.left, rtEdit.top);
+    mt.Concat(matrix);
+    m_pEdit->DrawWidget(pGraphics, mt);
   }
+  if (!IsMonthCalendarVisible())
+    return;
+
+  CFX_RectF rtMonth = m_pMonthCal->GetWidgetRect();
+  CFX_Matrix mt(1, 0, 0, 1, rtMonth.left, rtMonth.top);
+  mt.Concat(matrix);
+  m_pMonthCal->DrawWidget(pGraphics, mt);
 }
 
 void CFWL_DateTimePicker::SetThemeProvider(IFWL_ThemeProvider* pTP) {
@@ -172,14 +170,17 @@
 }
 
 WideString CFWL_DateTimePicker::GetEditText() const {
-  return m_pEdit ? m_pEdit->GetText() : L"";
+  return m_pEdit ? m_pEdit->GetText() : WideString();
+}
+
+int32_t CFWL_DateTimePicker::GetEditTextLength() const {
+  return m_pEdit ? m_pEdit->GetTextLength() : 0;
 }
 
 CFX_RectF CFWL_DateTimePicker::GetBBox() const {
-  if (m_pWidgetMgr->IsFormDisabled())
-    return DisForm_GetBBox();
-
   CFX_RectF rect = m_pProperties->m_rtWidget;
+  if (NeedsToShowButton())
+    rect.width += m_fBtn;
   if (!IsMonthCalendarVisible())
     return rect;
 
@@ -205,61 +206,57 @@
   param.m_rtPart = m_rtBtn;
   if (pMatrix)
     param.m_matrix.Concat(*pMatrix);
-  pTheme->DrawBackground(&param);
+  pTheme->DrawBackground(param);
 }
 
 WideString CFWL_DateTimePicker::FormatDateString(int32_t iYear,
                                                  int32_t iMonth,
                                                  int32_t iDay) {
-  if ((m_pProperties->m_dwStyleExes & FWL_STYLEEXT_DTP_ShortDateFormat) ==
-      FWL_STYLEEXT_DTP_ShortDateFormat) {
+  if (m_pProperties->m_dwStyleExes & FWL_STYLEEXT_DTP_ShortDateFormat)
     return WideString::Format(L"%d-%d-%d", iYear, iMonth, iDay);
-  }
 
-  if ((m_pProperties->m_dwStyleExes & FWL_STYLEEXT_DTP_LongDateFormat) ==
-      FWL_STYLEEXT_DTP_LongDateFormat) {
-    return WideString::Format(L"%d Year %d Month %d Day", iYear, iMonth, iDay);
-  }
-
-  return WideString();
+  return WideString::Format(L"%d Year %d Month %d Day", iYear, iMonth, iDay);
 }
 
 void CFWL_DateTimePicker::ShowMonthCalendar(bool bActivate) {
-  if (m_pWidgetMgr->IsFormDisabled())
-    return DisForm_ShowMonthCalendar(bActivate);
   if (IsMonthCalendarVisible() == bActivate)
     return;
-  if (!m_pForm)
-    InitProxyForm();
 
-  if (!bActivate) {
-    m_pForm->EndDoModal();
-    return;
+  if (bActivate) {
+    CFX_RectF rtMonthCal = m_pMonthCal->GetAutosizedWidgetRect();
+    float fPopupMin = rtMonthCal.height;
+    float fPopupMax = rtMonthCal.height;
+    CFX_RectF rtAnchor(m_pProperties->m_rtWidget);
+    rtAnchor.width = rtMonthCal.width;
+    rtMonthCal.left = m_rtClient.left;
+    rtMonthCal.top = rtAnchor.Height();
+    GetPopupPos(fPopupMin, fPopupMax, rtAnchor, &rtMonthCal);
+    m_pMonthCal->SetWidgetRect(rtMonthCal);
+    if (m_iYear > 0 && m_iMonth > 0 && m_iDay > 0)
+      m_pMonthCal->SetSelect(m_iYear, m_iMonth, m_iDay);
+    m_pMonthCal->Update();
   }
-
-  CFX_RectF rtMonth = m_pMonthCal->GetWidgetRect();
-
-  CFX_RectF rtAnchor(0, 0, m_pProperties->m_rtWidget.width,
-                     m_pProperties->m_rtWidget.height);
-  GetPopupPos(0, rtMonth.height, rtAnchor, rtMonth);
-  m_pForm->SetWidgetRect(rtMonth);
-
-  rtMonth.left = rtMonth.top = 0;
   if (bActivate)
     m_pMonthCal->RemoveStates(FWL_WGTSTATE_Invisible);
   else
     m_pMonthCal->SetStates(FWL_WGTSTATE_Invisible);
-  m_pMonthCal->SetWidgetRect(rtMonth);
-  m_pMonthCal->Update();
-  m_pForm->DoModal();
+
+  if (bActivate) {
+    CFWL_MessageSetFocus msg(m_pEdit.get(), m_pMonthCal.get());
+    m_pEdit->GetDelegate()->OnProcessMessage(&msg);
+  }
+
+  CFX_RectF rtInvalidate(0, 0, m_pProperties->m_rtWidget.width,
+                         m_pProperties->m_rtWidget.height);
+
+  CFX_RectF rtCal = m_pMonthCal->GetWidgetRect();
+  rtInvalidate.Union(rtCal);
+  rtInvalidate.Inflate(2, 2);
+  RepaintRect(rtInvalidate);
 }
 
 bool CFWL_DateTimePicker::IsMonthCalendarVisible() const {
-  if (m_pWidgetMgr->IsFormDisabled())
-    return DisForm_IsMonthCalendarVisible();
-  if (!m_pForm)
-    return false;
-  return !(m_pForm->GetStates() & FWL_WGTSTATE_Invisible);
+  return m_pMonthCal && m_pMonthCal->IsVisible();
 }
 
 void CFWL_DateTimePicker::ResetEditAlignment() {
@@ -322,150 +319,12 @@
   DispatchEvent(&ev);
 }
 
-void CFWL_DateTimePicker::InitProxyForm() {
-  if (m_pForm)
-    return;
-  if (!m_pMonthCal)
-    return;
-
-  auto prop = pdfium::MakeUnique<CFWL_WidgetProperties>();
-  prop->m_dwStyles = FWL_WGTSTYLE_Popup;
-  prop->m_dwStates = FWL_WGTSTATE_Invisible;
-  prop->m_pOwner = this;
-
-  m_pForm = pdfium::MakeUnique<CFWL_FormProxy>(
-      m_pOwnerApp.Get(), std::move(prop), m_pMonthCal.get());
-  m_pMonthCal->SetParent(m_pForm.get());
-}
-
-bool CFWL_DateTimePicker::DisForm_IsMonthCalendarVisible() const {
-  if (!m_pMonthCal)
-    return false;
-  return !(m_pMonthCal->GetStates() & FWL_WGTSTATE_Invisible);
-}
-
-void CFWL_DateTimePicker::DisForm_ShowMonthCalendar(bool bActivate) {
-  if (IsMonthCalendarVisible() == bActivate)
-    return;
-
-  if (bActivate) {
-    CFX_RectF rtMonthCal = m_pMonthCal->GetAutosizedWidgetRect();
-    float fPopupMin = rtMonthCal.height;
-    float fPopupMax = rtMonthCal.height;
-    CFX_RectF rtAnchor(m_pProperties->m_rtWidget);
-    rtAnchor.width = rtMonthCal.width;
-    rtMonthCal.left = m_rtClient.left;
-    rtMonthCal.top = rtAnchor.Height();
-    GetPopupPos(fPopupMin, fPopupMax, rtAnchor, rtMonthCal);
-    m_pMonthCal->SetWidgetRect(rtMonthCal);
-    if (m_iYear > 0 && m_iMonth > 0 && m_iDay > 0)
-      m_pMonthCal->SetSelect(m_iYear, m_iMonth, m_iDay);
-    m_pMonthCal->Update();
-  }
-  if (bActivate)
-    m_pMonthCal->RemoveStates(FWL_WGTSTATE_Invisible);
-  else
-    m_pMonthCal->SetStates(FWL_WGTSTATE_Invisible);
-
-  if (bActivate) {
-    CFWL_MessageSetFocus msg(m_pEdit.get(), m_pMonthCal.get());
-    m_pEdit->GetDelegate()->OnProcessMessage(&msg);
-  }
-
-  CFX_RectF rtInvalidate(0, 0, m_pProperties->m_rtWidget.width,
-                         m_pProperties->m_rtWidget.height);
-
-  CFX_RectF rtCal = m_pMonthCal->GetWidgetRect();
-  rtInvalidate.Union(rtCal);
-  rtInvalidate.Inflate(2, 2);
-  RepaintRect(rtInvalidate);
-}
-
-FWL_WidgetHit CFWL_DateTimePicker::DisForm_HitTest(
-    const CFX_PointF& point) const {
-  CFX_RectF rect(0, 0, m_pProperties->m_rtWidget.width,
-                 m_pProperties->m_rtWidget.height);
-  if (rect.Contains(point))
-    return FWL_WidgetHit::Edit;
-  if (DisForm_IsNeedShowButton())
-    rect.width += m_fBtn;
-  if (rect.Contains(point))
-    return FWL_WidgetHit::Client;
-  if (IsMonthCalendarVisible()) {
-    if (m_pMonthCal->GetWidgetRect().Contains(point))
-      return FWL_WidgetHit::Client;
-  }
-  return FWL_WidgetHit::Unknown;
-}
-
-bool CFWL_DateTimePicker::DisForm_IsNeedShowButton() const {
+bool CFWL_DateTimePicker::NeedsToShowButton() const {
   return m_pProperties->m_dwStates & FWL_WGTSTATE_Focused ||
          m_pMonthCal->GetStates() & FWL_WGTSTATE_Focused ||
          m_pEdit->GetStates() & FWL_WGTSTATE_Focused;
 }
 
-void CFWL_DateTimePicker::DisForm_Update() {
-  if (m_iLock)
-    return;
-  if (!m_pProperties->m_pThemeProvider)
-    m_pProperties->m_pThemeProvider = GetAvailableTheme();
-
-  m_pEdit->SetThemeProvider(m_pProperties->m_pThemeProvider);
-  m_rtClient = GetClientRect();
-  m_pEdit->SetWidgetRect(m_rtClient);
-  ResetEditAlignment();
-  m_pEdit->Update();
-
-  if (!m_pMonthCal->GetThemeProvider())
-    m_pMonthCal->SetThemeProvider(m_pProperties->m_pThemeProvider);
-
-  IFWL_ThemeProvider* theme = GetAvailableTheme();
-  if (!theme)
-    return;
-
-  m_fBtn = theme->GetScrollBarWidth();
-  CFX_RectF rtMonthCal = m_pMonthCal->GetAutosizedWidgetRect();
-  CFX_RectF rtPopUp(rtMonthCal.left, rtMonthCal.top + kDateTimePickerHeight,
-                    rtMonthCal.width, rtMonthCal.height);
-  m_pMonthCal->SetWidgetRect(rtPopUp);
-  m_pMonthCal->Update();
-}
-
-CFX_RectF CFWL_DateTimePicker::DisForm_GetBBox() const {
-  CFX_RectF rect = m_pProperties->m_rtWidget;
-  if (DisForm_IsNeedShowButton())
-    rect.width += m_fBtn;
-  if (!IsMonthCalendarVisible())
-    return rect;
-
-  CFX_RectF rtMonth = m_pMonthCal->GetWidgetRect();
-  rtMonth.Offset(m_pProperties->m_rtWidget.left, m_pProperties->m_rtWidget.top);
-  rect.Union(rtMonth);
-  return rect;
-}
-
-void CFWL_DateTimePicker::DisForm_DrawWidget(CXFA_Graphics* pGraphics,
-                                             const CFX_Matrix* pMatrix) {
-  if (!pGraphics)
-    return;
-  if (m_pEdit) {
-    CFX_RectF rtEdit = m_pEdit->GetWidgetRect();
-
-    CFX_Matrix mt(1, 0, 0, 1, rtEdit.left, rtEdit.top);
-    if (pMatrix)
-      mt.Concat(*pMatrix);
-    m_pEdit->DrawWidget(pGraphics, mt);
-  }
-  if (!IsMonthCalendarVisible())
-    return;
-
-  CFX_RectF rtMonth = m_pMonthCal->GetWidgetRect();
-  CFX_Matrix mt(1, 0, 0, 1, rtMonth.left, rtMonth.top);
-  if (pMatrix)
-    mt.Concat(*pMatrix);
-  m_pMonthCal->DrawWidget(pGraphics, mt);
-}
-
 void CFWL_DateTimePicker::OnProcessMessage(CFWL_Message* pMessage) {
   if (!pMessage)
     return;
@@ -507,8 +366,9 @@
     default:
       break;
   }
-
-  CFWL_Widget::OnProcessMessage(pMessage);
+  // Dst target could be |this|, continue only if not destroyed by above.
+  if (pMessage->GetDstTarget())
+    CFWL_Widget::OnProcessMessage(pMessage);
 }
 
 void CFWL_DateTimePicker::OnDrawWidget(CXFA_Graphics* pGraphics,
@@ -519,27 +379,34 @@
 void CFWL_DateTimePicker::OnFocusChanged(CFWL_Message* pMsg, bool bSet) {
   if (!pMsg)
     return;
-  if (m_pWidgetMgr->IsFormDisabled())
-    return DisForm_OnFocusChanged(pMsg, bSet);
 
+  CFX_RectF rtInvalidate(m_rtBtn);
   if (bSet) {
-    m_pProperties->m_dwStates |= (FWL_WGTSTATE_Focused);
-    RepaintRect(m_rtClient);
+    m_pProperties->m_dwStates |= FWL_WGTSTATE_Focused;
+    if (m_pEdit && !(m_pEdit->GetStylesEx() & FWL_STYLEEXT_EDT_ReadOnly)) {
+      m_rtBtn = CFX_RectF(m_pProperties->m_rtWidget.width, 0, m_fBtn,
+                          m_pProperties->m_rtWidget.height - 1);
+    }
+    rtInvalidate = m_rtBtn;
+    pMsg->SetDstTarget(m_pEdit.get());
+    m_pEdit->GetDelegate()->OnProcessMessage(pMsg);
   } else {
-    m_pProperties->m_dwStates &= ~(FWL_WGTSTATE_Focused);
-    RepaintRect(m_rtClient);
+    m_pProperties->m_dwStates &= ~FWL_WGTSTATE_Focused;
+    m_rtBtn = CFX_RectF();
+    if (IsMonthCalendarVisible())
+      ShowMonthCalendar(false);
+    if (m_pEdit->GetStates() & FWL_WGTSTATE_Focused) {
+      pMsg->SetSrcTarget(m_pEdit.get());
+      m_pEdit->GetDelegate()->OnProcessMessage(pMsg);
+    }
   }
-  if (pMsg->m_pSrcTarget == m_pMonthCal.get() && IsMonthCalendarVisible()) {
-    ShowMonthCalendar(false);
-  }
-  RepaintRect(m_rtClient);
+  rtInvalidate.Inflate(2, 2);
+  RepaintRect(rtInvalidate);
 }
 
 void CFWL_DateTimePicker::OnLButtonDown(CFWL_MessageMouse* pMsg) {
   if (!pMsg)
     return;
-  if ((m_pProperties->m_dwStates & FWL_WGTSTATE_Focused) == 0)
-    SetFocus(true);
   if (!m_rtBtn.Contains(pMsg->m_pos))
     return;
 
@@ -578,29 +445,50 @@
   RepaintRect(m_rtBtn);
 }
 
-void CFWL_DateTimePicker::DisForm_OnFocusChanged(CFWL_Message* pMsg,
-                                                 bool bSet) {
-  CFX_RectF rtInvalidate(m_rtBtn);
-  if (bSet) {
-    m_pProperties->m_dwStates |= FWL_WGTSTATE_Focused;
-    if (m_pEdit && !(m_pEdit->GetStylesEx() & FWL_STYLEEXT_EDT_ReadOnly)) {
-      m_rtBtn = CFX_RectF(m_pProperties->m_rtWidget.width, 0, m_fBtn,
-                          m_pProperties->m_rtWidget.height - 1);
-    }
-    rtInvalidate = m_rtBtn;
-    pMsg->m_pDstTarget = m_pEdit.get();
-    m_pEdit->GetDelegate()->OnProcessMessage(pMsg);
-  } else {
-    m_pProperties->m_dwStates &= ~FWL_WGTSTATE_Focused;
-    m_rtBtn.Reset();
+void CFWL_DateTimePicker::GetPopupPos(float fMinHeight,
+                                      float fMaxHeight,
+                                      const CFX_RectF& rtAnchor,
+                                      CFX_RectF* pPopupRect) {
+  m_pWidgetMgr->GetAdapterPopupPos(this, fMinHeight, fMaxHeight, rtAnchor,
+                                   pPopupRect);
+}
 
-    if (DisForm_IsMonthCalendarVisible())
-      ShowMonthCalendar(false);
-    if (m_pEdit->GetStates() & FWL_WGTSTATE_Focused) {
-      pMsg->m_pSrcTarget = m_pEdit.get();
-      m_pEdit->GetDelegate()->OnProcessMessage(pMsg);
-    }
-  }
-  rtInvalidate.Inflate(2, 2);
-  RepaintRect(rtInvalidate);
+void CFWL_DateTimePicker::ClearText() {
+  m_pEdit->ClearText();
+}
+
+void CFWL_DateTimePicker::SelectAll() {
+  m_pEdit->SelectAll();
+}
+
+void CFWL_DateTimePicker::ClearSelection() {
+  m_pEdit->ClearSelection();
+}
+
+Optional<WideString> CFWL_DateTimePicker::Copy() {
+  return m_pEdit->Copy();
+}
+
+Optional<WideString> CFWL_DateTimePicker::Cut() {
+  return m_pEdit->Cut();
+}
+
+bool CFWL_DateTimePicker::Paste(const WideString& wsPaste) {
+  return m_pEdit->Paste(wsPaste);
+}
+
+bool CFWL_DateTimePicker::Undo() {
+  return m_pEdit->Undo();
+}
+
+bool CFWL_DateTimePicker::Redo() {
+  return m_pEdit->Redo();
+}
+
+bool CFWL_DateTimePicker::CanUndo() {
+  return m_pEdit->CanUndo();
+}
+
+bool CFWL_DateTimePicker::CanRedo() {
+  return m_pEdit->CanRedo();
 }
diff --git a/xfa/fwl/cfwl_datetimepicker.h b/xfa/fwl/cfwl_datetimepicker.h
index 6d53601..69520eb 100644
--- a/xfa/fwl/cfwl_datetimepicker.h
+++ b/xfa/fwl/cfwl_datetimepicker.h
@@ -16,22 +16,20 @@
 #include "xfa/fwl/cfwl_widget.h"
 #include "xfa/fwl/cfwl_widgetproperties.h"
 
-#define FWL_STYLEEXT_DTP_LongDateFormat 0
 #define FWL_STYLEEXT_DTP_ShortDateFormat (1L << 1)
-#define FWL_STYLEEXT_DTP_EditHNear 0
+#define FWL_STYLEEXT_DTP_EditHAlignMask (3L << 4)
+#define FWL_STYLEEXT_DTP_EditHNear (0L << 4)
 #define FWL_STYLEEXT_DTP_EditHCenter (1L << 4)
 #define FWL_STYLEEXT_DTP_EditHFar (2L << 4)
-#define FWL_STYLEEXT_DTP_EditVNear 0
+#define FWL_STYLEEXT_DTP_EditVAlignMask (3L << 6)
+#define FWL_STYLEEXT_DTP_EditVNear (0L << 6)
 #define FWL_STYLEEXT_DTP_EditVCenter (1L << 6)
 #define FWL_STYLEEXT_DTP_EditVFar (2L << 6)
 #define FWL_STYLEEXT_DTP_EditJustified (1L << 8)
-#define FWL_STYLEEXT_DTP_EditHAlignMask (3L << 4)
-#define FWL_STYLEEXT_DTP_EditVAlignMask (3L << 6)
 
 class CFWL_DateTimeEdit;
-class CFWL_FormProxy;
 
-class CFWL_DateTimePicker : public CFWL_Widget {
+class CFWL_DateTimePicker final : public CFWL_Widget {
  public:
   explicit CFWL_DateTimePicker(const CFWL_App* pApp);
   ~CFWL_DateTimePicker() override;
@@ -50,13 +48,24 @@
   void SetCurSel(int32_t iYear, int32_t iMonth, int32_t iDay);
 
   void SetEditText(const WideString& wsText);
+  int32_t GetEditTextLength() const;
   WideString GetEditText() const;
+  void ClearText();
 
+  void SelectAll();
+  void ClearSelection();
   bool HasSelection() const { return m_pEdit->HasSelection(); }
   // Returns <start, count> of the selection.
   std::pair<size_t, size_t> GetSelection() const {
     return m_pEdit->GetSelection();
   }
+  Optional<WideString> Copy();
+  Optional<WideString> Cut();
+  bool Paste(const WideString& wsPaste);
+  bool Undo();
+  bool Redo();
+  bool CanUndo();
+  bool CanRedo();
 
   CFX_RectF GetBBox() const;
   void SetEditLimit(int32_t nLimit) { m_pEdit->SetLimit(nLimit); }
@@ -66,41 +75,34 @@
   void ShowMonthCalendar(bool bActivate);
   void ProcessSelChanged(int32_t iYear, int32_t iMonth, int32_t iDay);
 
-  CFWL_FormProxy* GetFormProxy() const { return m_pForm.get(); }
-
  private:
   void DrawDropDownButton(CXFA_Graphics* pGraphics,
                           IFWL_ThemeProvider* pTheme,
                           const CFX_Matrix* pMatrix);
   WideString FormatDateString(int32_t iYear, int32_t iMonth, int32_t iDay);
   void ResetEditAlignment();
-  void InitProxyForm();
+  void GetPopupPos(float fMinHeight,
+                   float fMaxHeight,
+                   const CFX_RectF& rtAnchor,
+                   CFX_RectF* pPopupRect);
   void OnFocusChanged(CFWL_Message* pMsg, bool bSet);
   void OnLButtonDown(CFWL_MessageMouse* pMsg);
   void OnLButtonUp(CFWL_MessageMouse* pMsg);
   void OnMouseMove(CFWL_MessageMouse* pMsg);
   void OnMouseLeave(CFWL_MessageMouse* pMsg);
 
-  bool DisForm_IsMonthCalendarVisible() const;
-  void DisForm_ShowMonthCalendar(bool bActivate);
-  FWL_WidgetHit DisForm_HitTest(const CFX_PointF& point) const;
-  bool DisForm_IsNeedShowButton() const;
-  void DisForm_Update();
-  CFX_RectF DisForm_GetBBox() const;
-  void DisForm_DrawWidget(CXFA_Graphics* pGraphics, const CFX_Matrix* pMatrix);
-  void DisForm_OnFocusChanged(CFWL_Message* pMsg, bool bSet);
+  bool NeedsToShowButton() const;
 
+  bool m_bLBtnDown = false;
+  int32_t m_iBtnState = 1;
+  int32_t m_iYear = -1;
+  int32_t m_iMonth = -1;
+  int32_t m_iDay = -1;
+  float m_fBtn = 0.0f;
   CFX_RectF m_rtBtn;
   CFX_RectF m_rtClient;
-  int32_t m_iBtnState;
-  int32_t m_iYear;
-  int32_t m_iMonth;
-  int32_t m_iDay;
-  bool m_bLBtnDown;
   std::unique_ptr<CFWL_DateTimeEdit> m_pEdit;
   std::unique_ptr<CFWL_MonthCalendar> m_pMonthCal;
-  std::unique_ptr<CFWL_FormProxy> m_pForm;
-  float m_fBtn;
 };
 
 #endif  // XFA_FWL_CFWL_DATETIMEPICKER_H_
diff --git a/xfa/fwl/cfwl_edit.cpp b/xfa/fwl/cfwl_edit.cpp
index 960ec99..1f265b5 100644
--- a/xfa/fwl/cfwl_edit.cpp
+++ b/xfa/fwl/cfwl_edit.cpp
@@ -11,79 +11,50 @@
 #include <utility>
 #include <vector>
 
+#include "build/build_config.h"
+#include "core/fxge/cfx_renderdevice.h"
+#include "core/fxge/text_char_pos.h"
 #include "third_party/base/ptr_util.h"
 #include "third_party/base/stl_util.h"
-#include "xfa/fde/cfde_texteditengine.h"
 #include "xfa/fde/cfde_textout.h"
 #include "xfa/fgas/font/cfgas_gefont.h"
 #include "xfa/fwl/cfwl_app.h"
 #include "xfa/fwl/cfwl_caret.h"
 #include "xfa/fwl/cfwl_event.h"
-#include "xfa/fwl/cfwl_eventcheckword.h"
-#include "xfa/fwl/cfwl_eventtextchanged.h"
+#include "xfa/fwl/cfwl_eventtextwillchange.h"
 #include "xfa/fwl/cfwl_eventvalidate.h"
 #include "xfa/fwl/cfwl_messagekey.h"
 #include "xfa/fwl/cfwl_messagemouse.h"
 #include "xfa/fwl/cfwl_themebackground.h"
 #include "xfa/fwl/cfwl_themepart.h"
 #include "xfa/fwl/cfwl_widgetmgr.h"
+#include "xfa/fwl/fwl_widgetdef.h"
 #include "xfa/fwl/ifwl_themeprovider.h"
 #include "xfa/fwl/theme/cfwl_utils.h"
-#include "xfa/fxfa/cxfa_ffdoc.h"
-#include "xfa/fxfa/cxfa_ffwidget.h"
 #include "xfa/fxgraphics/cxfa_gepath.h"
 
 namespace {
 
-const int kEditMargin = 3;
+constexpr int kEditMargin = 3;
 
-#if (_FX_OS_ == _FX_OS_MACOSX_)
+#if defined(OS_MACOSX)
 constexpr int kEditingModifier = FWL_KEYFLAG_Command;
 #else
 constexpr int kEditingModifier = FWL_KEYFLAG_Ctrl;
 #endif
 
-bool FxEditIsLatinWord(wchar_t c) {
-  return c == 0x2D || (c <= 0x005A && c >= 0x0041) ||
-         (c <= 0x007A && c >= 0x0061) || (c <= 0x02AF && c >= 0x00C0) ||
-         c == 0x0027;
-}
-
-void AddSquigglyPath(CXFA_GEPath* pPathData,
-                     float fStartX,
-                     float fEndX,
-                     float fY,
-                     float fStep) {
-  pPathData->MoveTo(CFX_PointF(fStartX, fY));
-  int i = 1;
-  for (float fx = fStartX + fStep; fx < fEndX; fx += fStep, ++i)
-    pPathData->LineTo(CFX_PointF(fx, fY + (i & 1) * fStep));
-}
-
 }  // namespace
 
 CFWL_Edit::CFWL_Edit(const CFWL_App* app,
                      std::unique_ptr<CFWL_WidgetProperties> properties,
                      CFWL_Widget* pOuter)
     : CFWL_Widget(app, std::move(properties), pOuter),
-      m_fVAlignOffset(0.0f),
-      m_fScrollOffsetX(0.0f),
-      m_fScrollOffsetY(0.0f),
-      m_bLButtonDown(false),
-      m_CursorPosition(0),
-      m_nLimit(-1),
-      m_fFontSize(0),
-      m_bSetRange(false),
-      m_iMax(0xFFFFFFF) {
-  m_rtClient.Reset();
-  m_rtEngine.Reset();
-  m_rtStatic.Reset();
-
-  InitCaret();
-  m_EdtEngine.SetDelegate(this);
+      m_pEditEngine(pdfium::MakeUnique<CFDE_TextEditEngine>()) {
+  m_pEditEngine->SetDelegate(this);
 }
 
 CFWL_Edit::~CFWL_Edit() {
+  m_pEditEngine->SetDelegate(nullptr);
   if (m_pProperties->m_dwStates & FWL_WGTSTATE_Focused)
     HideCaret(nullptr);
 }
@@ -112,9 +83,9 @@
 CFX_RectF CFWL_Edit::GetAutosizedWidgetRect() {
   CFX_RectF rect;
 
-  if (m_EdtEngine.GetLength() > 0) {
+  if (m_pEditEngine->GetLength() > 0) {
     CFX_SizeF size = CalcTextSize(
-        m_EdtEngine.GetText(), m_pProperties->m_pThemeProvider,
+        m_pEditEngine->GetText(), m_pProperties->m_pThemeProvider.Get(),
         !!(m_pProperties->m_dwStyleExes & FWL_STYLEEXT_EDT_MultiLine));
     rect = CFX_RectF(0, 0, size);
   }
@@ -163,97 +134,18 @@
   return FWL_WidgetHit::Unknown;
 }
 
-void CFWL_Edit::AddSpellCheckObj(CXFA_GEPath& PathData,
-                                 int32_t nStart,
-                                 int32_t nCount,
-                                 float fOffSetX,
-                                 float fOffSetY) {
-  float fStep = m_EdtEngine.GetFontSize() / 16.0f;
-  float font_ascent = m_EdtEngine.GetFontAscent();
-
-  std::vector<CFX_RectF> rects =
-      m_EdtEngine.GetCharacterRectsInRange(nStart, nCount);
-  for (const auto& rect : rects) {
-    float fY = rect.top + font_ascent + fOffSetY;
-    float fStartX = rect.left + fOffSetX;
-    float fEndX = fStartX + rect.Width();
-
-    AddSquigglyPath(&PathData, fStartX, fEndX, fY, fStep);
-  }
-}
-
-void CFWL_Edit::DrawSpellCheck(CXFA_Graphics* pGraphics,
-                               const CFX_Matrix* pMatrix) {
-  pGraphics->SaveGraphState();
-  if (pMatrix)
-    pGraphics->ConcatMatrix(pMatrix);
-
-  CFWL_EventCheckWord checkWordEvent(this);
-  ByteString sLatinWord;
-  CXFA_GEPath pathSpell;
-  int32_t nStart = 0;
-  float fOffSetX = m_rtEngine.left - m_fScrollOffsetX;
-  float fOffSetY = m_rtEngine.top - m_fScrollOffsetY + m_fVAlignOffset;
-  WideString wsSpell = GetText();
-  int32_t nContentLen = wsSpell.GetLength();
-  for (int i = 0; i < nContentLen; i++) {
-    if (FxEditIsLatinWord(wsSpell[i])) {
-      if (sLatinWord.IsEmpty())
-        nStart = i;
-      sLatinWord += (char)wsSpell[i];
-      continue;
-    }
-    checkWordEvent.bsWord = sLatinWord;
-    checkWordEvent.bCheckWord = true;
-    DispatchEvent(&checkWordEvent);
-
-    if (!sLatinWord.IsEmpty() && !checkWordEvent.bCheckWord) {
-      AddSpellCheckObj(pathSpell, nStart, sLatinWord.GetLength(), fOffSetX,
-                       fOffSetY);
-    }
-    sLatinWord.clear();
-  }
-
-  checkWordEvent.bsWord = sLatinWord;
-  checkWordEvent.bCheckWord = true;
-  DispatchEvent(&checkWordEvent);
-
-  if (!sLatinWord.IsEmpty() && !checkWordEvent.bCheckWord) {
-    AddSpellCheckObj(pathSpell, nStart, sLatinWord.GetLength(), fOffSetX,
-                     fOffSetY);
-  }
-  if (!pathSpell.IsEmpty()) {
-    CFX_RectF rtClip = m_rtEngine;
-    CFX_Matrix mt(1, 0, 0, 1, fOffSetX, fOffSetY);
-    if (pMatrix) {
-      rtClip = pMatrix->TransformRect(rtClip);
-      mt.Concat(*pMatrix);
-    }
-    pGraphics->SetClipRect(rtClip);
-    pGraphics->SetStrokeColor(CXFA_GEColor(0xFFFF0000));
-    pGraphics->SetLineWidth(0);
-    pGraphics->StrokePath(&pathSpell, nullptr);
-  }
-  pGraphics->RestoreGraphState();
-}
-
 void CFWL_Edit::DrawWidget(CXFA_Graphics* pGraphics, const CFX_Matrix& matrix) {
   if (!pGraphics)
     return;
-  if (!m_pProperties->m_pThemeProvider)
-    return;
+
   if (m_rtClient.IsEmpty())
     return;
 
-  IFWL_ThemeProvider* pTheme = m_pProperties->m_pThemeProvider;
-  if (!m_pWidgetMgr->IsFormDisabled())
-    DrawTextBk(pGraphics, pTheme, &matrix);
-  DrawContent(pGraphics, pTheme, &matrix);
+  IFWL_ThemeProvider* pTheme = m_pProperties->m_pThemeProvider.Get();
+  if (!pTheme)
+    return;
 
-  if ((m_pProperties->m_dwStates & FWL_WGTSTATE_Focused) &&
-      !(m_pProperties->m_dwStyleExes & FWL_STYLEEXT_EDT_ReadOnly)) {
-    DrawSpellCheck(pGraphics, &matrix);
-  }
+  DrawContent(pGraphics, pTheme, &matrix);
   if (HasBorder())
     DrawBorder(pGraphics, CFWL_Part::Border, pTheme, matrix);
 }
@@ -271,36 +163,43 @@
 }
 
 void CFWL_Edit::SetText(const WideString& wsText) {
-  m_EdtEngine.Clear();
-  m_EdtEngine.Insert(0, wsText);
+  m_pEditEngine->Clear();
+  m_pEditEngine->Insert(0, wsText,
+                        CFDE_TextEditEngine::RecordOperation::kInsertRecord);
+}
+
+void CFWL_Edit::SetTextSkipNotify(const WideString& wsText) {
+  m_pEditEngine->Clear();
+  m_pEditEngine->Insert(0, wsText,
+                        CFDE_TextEditEngine::RecordOperation::kSkipNotify);
 }
 
 int32_t CFWL_Edit::GetTextLength() const {
-  return m_EdtEngine.GetLength();
+  return m_pEditEngine->GetLength();
 }
 
 WideString CFWL_Edit::GetText() const {
-  return m_EdtEngine.GetText();
+  return m_pEditEngine->GetText();
 }
 
 void CFWL_Edit::ClearText() {
-  m_EdtEngine.Clear();
+  m_pEditEngine->Clear();
 }
 
 void CFWL_Edit::SelectAll() {
-  m_EdtEngine.SelectAll();
+  m_pEditEngine->SelectAll();
 }
 
 bool CFWL_Edit::HasSelection() const {
-  return m_EdtEngine.HasSelection();
+  return m_pEditEngine->HasSelection();
 }
 
 std::pair<size_t, size_t> CFWL_Edit::GetSelection() const {
-  return m_EdtEngine.GetSelection();
+  return m_pEditEngine->GetSelection();
 }
 
 void CFWL_Edit::ClearSelection() {
-  return m_EdtEngine.ClearSelection();
+  return m_pEditEngine->ClearSelection();
 }
 
 int32_t CFWL_Edit::GetLimit() const {
@@ -311,54 +210,56 @@
   m_nLimit = nLimit;
 
   if (m_nLimit > 0) {
-    m_EdtEngine.SetHasCharacterLimit(true);
-    m_EdtEngine.SetCharacterLimit(nLimit);
+    m_pEditEngine->SetHasCharacterLimit(true);
+    m_pEditEngine->SetCharacterLimit(nLimit);
   } else {
-    m_EdtEngine.SetHasCharacterLimit(false);
+    m_pEditEngine->SetHasCharacterLimit(false);
   }
 }
 
 void CFWL_Edit::SetAliasChar(wchar_t wAlias) {
-  m_EdtEngine.SetAliasChar(wAlias);
+  m_pEditEngine->SetAliasChar(wAlias);
 }
 
 Optional<WideString> CFWL_Edit::Copy() {
-  if (!m_EdtEngine.HasSelection())
+  if (!m_pEditEngine->HasSelection())
     return {};
 
-  return {m_EdtEngine.GetSelectedText()};
+  return {m_pEditEngine->GetSelectedText()};
 }
 
 Optional<WideString> CFWL_Edit::Cut() {
-  if (!m_EdtEngine.HasSelection())
+  if (!m_pEditEngine->HasSelection())
     return {};
 
-  return {m_EdtEngine.DeleteSelectedText()};
+  WideString cut_text = m_pEditEngine->DeleteSelectedText();
+  UpdateCaret();
+  return {cut_text};
 }
 
 bool CFWL_Edit::Paste(const WideString& wsPaste) {
-  if (m_EdtEngine.HasSelection())
-    m_EdtEngine.ReplaceSelectedText(wsPaste);
+  if (m_pEditEngine->HasSelection())
+    m_pEditEngine->ReplaceSelectedText(wsPaste);
   else
-    m_EdtEngine.Insert(m_CursorPosition, wsPaste);
+    m_pEditEngine->Insert(m_CursorPosition, wsPaste);
 
   return true;
 }
 
 bool CFWL_Edit::Undo() {
-  return CanUndo() ? m_EdtEngine.Undo() : false;
+  return CanUndo() && m_pEditEngine->Undo();
 }
 
 bool CFWL_Edit::Redo() {
-  return CanRedo() ? m_EdtEngine.Redo() : false;
+  return CanRedo() && m_pEditEngine->Redo();
 }
 
 bool CFWL_Edit::CanUndo() {
-  return m_EdtEngine.CanUndo();
+  return m_pEditEngine->CanUndo();
 }
 
 bool CFWL_Edit::CanRedo() {
-  return m_EdtEngine.CanRedo();
+  return m_pEditEngine->CanRedo();
 }
 
 void CFWL_Edit::SetOuter(CFWL_Widget* pOuter) {
@@ -394,14 +295,26 @@
   }
 }
 
-void CFWL_Edit::OnTextChanged(const WideString& prevText) {
+void CFWL_Edit::OnTextWillChange(CFDE_TextEditEngine::TextChange* change) {
+  CFWL_EventTextWillChange event(this);
+  event.previous_text = change->previous_text;
+  event.change_text = change->text;
+  event.selection_start = change->selection_start;
+  event.selection_end = change->selection_end;
+  event.cancelled = false;
+
+  DispatchEvent(&event);
+
+  change->text = event.change_text;
+  change->selection_start = event.selection_start;
+  change->selection_end = event.selection_end;
+  change->cancelled = event.cancelled;
+}
+
+void CFWL_Edit::OnTextChanged() {
   if (m_pProperties->m_dwStyleExes & FWL_STYLEEXT_EDT_VAlignMask)
     UpdateVAlignment();
 
-  CFWL_EventTextChanged event(this);
-  event.wsPrevText = prevText;
-  DispatchEvent(&event);
-
   LayoutScrollBar();
   RepaintRect(GetClientRect());
 }
@@ -411,10 +324,6 @@
 }
 
 bool CFWL_Edit::OnValidate(const WideString& wsText) {
-  CFWL_Widget* pDst = GetOuter();
-  if (!pDst)
-    pDst = this;
-
   CFWL_EventValidate event(this);
   event.wsInsert = wsText;
   event.bValidate = true;
@@ -442,7 +351,7 @@
   param.m_pGraphics = pGraphics;
   param.m_matrix = *pMatrix;
   param.m_rtPart = m_rtClient;
-  pTheme->DrawBackground(&param);
+  pTheme->DrawBackground(param);
 
   if (!IsShowScrollBar(true) || !IsShowScrollBar(false))
     return;
@@ -455,7 +364,7 @@
   param.m_bStaticBackground = true;
   param.m_bMaximize = true;
   param.m_rtPart = rtStatic;
-  pTheme->DrawBackground(&param);
+  pTheme->DrawBackground(param);
 }
 
 void CFWL_Edit::DrawContent(CXFA_Graphics* pGraphics,
@@ -477,12 +386,12 @@
   }
 
   bool bShowSel = !!(m_pProperties->m_dwStates & FWL_WGTSTATE_Focused);
-  if (bShowSel && m_EdtEngine.HasSelection()) {
+  if (bShowSel && m_pEditEngine->HasSelection()) {
     size_t sel_start;
     size_t count;
-    std::tie(sel_start, count) = m_EdtEngine.GetSelection();
+    std::tie(sel_start, count) = m_pEditEngine->GetSelection();
     std::vector<CFX_RectF> rects =
-        m_EdtEngine.GetCharacterRectsInRange(sel_start, count);
+        m_pEditEngine->GetCharacterRectsInRange(sel_start, count);
 
     CXFA_GEPath path;
     for (auto& rect : rects) {
@@ -498,13 +407,10 @@
     param.m_pWidget = this;
     param.m_iPart = CFWL_Part::Background;
     param.m_pPath = &path;
-    pTheme->DrawBackground(&param);
+    pTheme->DrawBackground(param);
   }
 
   CFX_RenderDevice* pRenderDev = pGraphics->GetRenderDevice();
-  if (!pRenderDev)
-    return;
-
   RenderText(pRenderDev, rtClip, mt);
 
   if (m_pProperties->m_dwStyleExes & FWL_STYLEEXT_EDT_CombText) {
@@ -526,7 +432,7 @@
     param.m_pWidget = this;
     param.m_iPart = CFWL_Part::CombTextLine;
     param.m_pPath = &path;
-    pTheme->DrawBackground(&param);
+    pTheme->DrawBackground(param);
   }
   pGraphics->RestoreGraphState();
 }
@@ -536,11 +442,11 @@
                            const CFX_Matrix& mt) {
   ASSERT(pRenderDev);
 
-  RetainPtr<CFGAS_GEFont> font = m_EdtEngine.GetFont();
+  RetainPtr<CFGAS_GEFont> font = m_pEditEngine->GetFont();
   if (!font)
     return;
 
-  pRenderDev->SetClip_Rect(clipRect);
+  pRenderDev->SetClip_Rect(clipRect.GetOuterRect());
 
   CFX_RectF rtDocClip = clipRect;
   if (rtDocClip.IsEmpty()) {
@@ -551,18 +457,17 @@
   }
   rtDocClip = mt.GetInverse().TransformRect(rtDocClip);
 
-  for (const FDE_TEXTEDITPIECE& info : m_EdtEngine.GetTextPieces()) {
+  for (const FDE_TEXTEDITPIECE& info : m_pEditEngine->GetTextPieces()) {
     // If this character is outside the clip, skip it.
     if (!rtDocClip.IntersectWith(info.rtPiece))
       continue;
 
-    std::vector<FXTEXT_CHARPOS> char_pos = m_EdtEngine.GetDisplayPos(info);
+    std::vector<TextCharPos> char_pos = m_pEditEngine->GetDisplayPos(info);
     if (char_pos.empty())
       continue;
 
-    CFDE_TextOut::DrawString(pRenderDev, m_EdtEngine.GetFontColor(), font,
-                             char_pos.data(), char_pos.size(),
-                             m_EdtEngine.GetFontSize(), &mt);
+    CFDE_TextOut::DrawString(pRenderDev, m_pEditEngine->GetFontColor(), font,
+                             char_pos, m_pEditEngine->GetFontSize(), mt);
   }
 }
 
@@ -572,13 +477,13 @@
 }
 
 void CFWL_Edit::UpdateEditParams() {
-  m_EdtEngine.SetAvailableWidth(m_rtEngine.width);
-  m_EdtEngine.SetCombText(
+  m_pEditEngine->SetAvailableWidth(m_rtEngine.width);
+  m_pEditEngine->SetCombText(
       !!(m_pProperties->m_dwStyleExes & FWL_STYLEEXT_EDT_CombText));
 
-  m_EdtEngine.EnableValidation(
+  m_pEditEngine->EnableValidation(
       !!(m_pProperties->m_dwStyleExes & FWL_STYLEEXT_EDT_Validate));
-  m_EdtEngine.EnablePasswordMode(
+  m_pEditEngine->EnablePasswordMode(
       !!(m_pProperties->m_dwStyleExes & FWL_STYLEEXT_EDT_Password));
 
   uint32_t alignment = 0;
@@ -606,22 +511,22 @@
     default:
       break;
   }
-  m_EdtEngine.SetAlignment(alignment);
+  m_pEditEngine->SetAlignment(alignment);
 
   bool auto_hscroll =
       !!(m_pProperties->m_dwStyleExes & FWL_STYLEEXT_EDT_AutoHScroll);
   if (m_pProperties->m_dwStyleExes & FWL_STYLEEXT_EDT_MultiLine) {
-    m_EdtEngine.EnableMultiLine(true);
-    m_EdtEngine.EnableLineWrap(!auto_hscroll);
-    m_EdtEngine.LimitVerticalScroll(
+    m_pEditEngine->EnableMultiLine(true);
+    m_pEditEngine->EnableLineWrap(!auto_hscroll);
+    m_pEditEngine->LimitVerticalScroll(
         (m_pProperties->m_dwStyles & FWL_WGTSTYLE_VScroll) == 0 &&
         (m_pProperties->m_dwStyleExes & FWL_STYLEEXT_EDT_AutoVScroll) == 0);
   } else {
-    m_EdtEngine.EnableMultiLine(false);
-    m_EdtEngine.EnableLineWrap(false);
-    m_EdtEngine.LimitVerticalScroll(false);
+    m_pEditEngine->EnableMultiLine(false);
+    m_pEditEngine->EnableLineWrap(false);
+    m_pEditEngine->LimitVerticalScroll(false);
   }
-  m_EdtEngine.LimitHorizontalScroll(!auto_hscroll);
+  m_pEditEngine->LimitHorizontalScroll(!auto_hscroll);
 
   IFWL_ThemeProvider* theme = GetAvailableTheme();
   CFWL_ThemePart part;
@@ -631,23 +536,23 @@
     m_fFontSize = FWLTHEME_CAPACITY_FontSize;
     return;
   }
-  m_fFontSize = theme->GetFontSize(&part);
+  m_fFontSize = theme->GetFontSize(part);
 
-  RetainPtr<CFGAS_GEFont> pFont = theme->GetFont(&part);
+  RetainPtr<CFGAS_GEFont> pFont = theme->GetFont(part);
   if (!pFont)
     return;
 
-  m_EdtEngine.SetFont(pFont);
-  m_EdtEngine.SetFontColor(theme->GetTextColor(&part));
-  m_EdtEngine.SetFontSize(m_fFontSize);
-  m_EdtEngine.SetLineSpace(theme->GetLineHeight(&part));
-  m_EdtEngine.SetTabWidth(m_fFontSize);
-  m_EdtEngine.SetVisibleLineCount(m_rtEngine.height /
-                                  theme->GetLineHeight(&part));
+  m_pEditEngine->SetFont(pFont);
+  m_pEditEngine->SetFontColor(theme->GetTextColor(part));
+  m_pEditEngine->SetFontSize(m_fFontSize);
+  m_pEditEngine->SetLineSpace(theme->GetLineHeight(part));
+  m_pEditEngine->SetTabWidth(m_fFontSize);
+  m_pEditEngine->SetVisibleLineCount(m_rtEngine.height /
+                                     theme->GetLineHeight(part));
 }
 
 void CFWL_Edit::UpdateEditLayout() {
-  m_EdtEngine.Layout();
+  m_pEditEngine->Layout();
 }
 
 bool CFWL_Edit::UpdateOffset() {
@@ -659,7 +564,7 @@
 
   const CFX_RectF& edit_bounds = m_rtEngine;
   if (edit_bounds.Contains(rtCaret)) {
-    CFX_RectF contents_bounds = m_EdtEngine.GetContentsBoundingBox();
+    CFX_RectF contents_bounds = m_pEditEngine->GetContentsBoundingBox();
     contents_bounds.Offset(fOffSetX, fOffSetY);
     if (contents_bounds.right() < edit_bounds.right() && m_fScrollOffsetX > 0) {
       m_fScrollOffsetX += contents_bounds.right() - edit_bounds.right();
@@ -708,13 +613,13 @@
     CFWL_ThemePart part;
     part.m_pWidget = this;
 
-    CFX_SizeF pSpace = theme->GetSpaceAboveBelow(&part);
+    CFX_SizeF pSpace = theme->GetSpaceAboveBelow(part);
     fSpaceAbove = pSpace.width >= 0.1f ? pSpace.width : 0.0f;
     fSpaceBelow = pSpace.height >= 0.1f ? pSpace.height : 0.0f;
   }
 
   float fOffsetY = 0.0f;
-  CFX_RectF contents_bounds = m_EdtEngine.GetContentsBoundingBox();
+  CFX_RectF contents_bounds = m_pEditEngine->GetContentsBoundingBox();
   if (m_pProperties->m_dwStyleExes & FWL_STYLEEXT_EDT_VCenter) {
     fOffsetY = (m_rtEngine.height - contents_bounds.height) / 2.0f;
     if (fOffsetY < (fSpaceAbove + fSpaceBelow) / 2.0f &&
@@ -751,38 +656,36 @@
 }
 
 CFWL_ScrollBar* CFWL_Edit::UpdateScroll() {
-  bool bShowHorz =
-      m_pHorzScrollBar &&
-      ((m_pHorzScrollBar->GetStates() & FWL_WGTSTATE_Invisible) == 0);
-  bool bShowVert =
-      m_pVertScrollBar &&
-      ((m_pVertScrollBar->GetStates() & FWL_WGTSTATE_Invisible) == 0);
+  bool bShowHorz = m_pHorzScrollBar && m_pHorzScrollBar->IsVisible();
+  bool bShowVert = m_pVertScrollBar && m_pVertScrollBar->IsVisible();
   if (!bShowHorz && !bShowVert)
     return nullptr;
 
-  CFX_RectF contents_bounds = m_EdtEngine.GetContentsBoundingBox();
+  CFX_RectF contents_bounds = m_pEditEngine->GetContentsBoundingBox();
   CFWL_ScrollBar* pRepaint = nullptr;
   if (bShowHorz) {
     CFX_RectF rtScroll = m_pHorzScrollBar->GetWidgetRect();
     if (rtScroll.width < contents_bounds.width) {
-      m_pHorzScrollBar->LockUpdate();
-      float fRange = contents_bounds.width - rtScroll.width;
-      m_pHorzScrollBar->SetRange(0.0f, fRange);
+      {
+        ScopedUpdateLock update_lock(m_pHorzScrollBar.get());
+        float fRange = contents_bounds.width - rtScroll.width;
+        m_pHorzScrollBar->SetRange(0.0f, fRange);
 
-      float fPos = pdfium::clamp(m_fScrollOffsetX, 0.0f, fRange);
-      m_pHorzScrollBar->SetPos(fPos);
-      m_pHorzScrollBar->SetTrackPos(fPos);
-      m_pHorzScrollBar->SetPageSize(rtScroll.width);
-      m_pHorzScrollBar->SetStepSize(rtScroll.width / 10);
-      m_pHorzScrollBar->RemoveStates(FWL_WGTSTATE_Disabled);
-      m_pHorzScrollBar->UnlockUpdate();
+        float fPos = pdfium::clamp(m_fScrollOffsetX, 0.0f, fRange);
+        m_pHorzScrollBar->SetPos(fPos);
+        m_pHorzScrollBar->SetTrackPos(fPos);
+        m_pHorzScrollBar->SetPageSize(rtScroll.width);
+        m_pHorzScrollBar->SetStepSize(rtScroll.width / 10);
+        m_pHorzScrollBar->RemoveStates(FWL_WGTSTATE_Disabled);
+      }
       m_pHorzScrollBar->Update();
       pRepaint = m_pHorzScrollBar.get();
     } else if ((m_pHorzScrollBar->GetStates() & FWL_WGTSTATE_Disabled) == 0) {
-      m_pHorzScrollBar->LockUpdate();
-      m_pHorzScrollBar->SetRange(0, -1);
-      m_pHorzScrollBar->SetStates(FWL_WGTSTATE_Disabled);
-      m_pHorzScrollBar->UnlockUpdate();
+      {
+        ScopedUpdateLock update_lock(m_pHorzScrollBar.get());
+        m_pHorzScrollBar->SetRange(0, -1);
+        m_pHorzScrollBar->SetStates(FWL_WGTSTATE_Disabled);
+      }
       m_pHorzScrollBar->Update();
       pRepaint = m_pHorzScrollBar.get();
     }
@@ -791,26 +694,28 @@
   if (bShowVert) {
     CFX_RectF rtScroll = m_pVertScrollBar->GetWidgetRect();
     if (rtScroll.height < contents_bounds.height) {
-      m_pVertScrollBar->LockUpdate();
-      float fStep = m_EdtEngine.GetLineSpace();
-      float fRange =
-          std::max(contents_bounds.height - m_rtEngine.height, fStep);
+      {
+        ScopedUpdateLock update_lock(m_pHorzScrollBar.get());
+        float fStep = m_pEditEngine->GetLineSpace();
+        float fRange =
+            std::max(contents_bounds.height - m_rtEngine.height, fStep);
 
-      m_pVertScrollBar->SetRange(0.0f, fRange);
-      float fPos = pdfium::clamp(m_fScrollOffsetY, 0.0f, fRange);
-      m_pVertScrollBar->SetPos(fPos);
-      m_pVertScrollBar->SetTrackPos(fPos);
-      m_pVertScrollBar->SetPageSize(rtScroll.height);
-      m_pVertScrollBar->SetStepSize(fStep);
-      m_pVertScrollBar->RemoveStates(FWL_WGTSTATE_Disabled);
-      m_pVertScrollBar->UnlockUpdate();
+        m_pVertScrollBar->SetRange(0.0f, fRange);
+        float fPos = pdfium::clamp(m_fScrollOffsetY, 0.0f, fRange);
+        m_pVertScrollBar->SetPos(fPos);
+        m_pVertScrollBar->SetTrackPos(fPos);
+        m_pVertScrollBar->SetPageSize(rtScroll.height);
+        m_pVertScrollBar->SetStepSize(fStep);
+        m_pVertScrollBar->RemoveStates(FWL_WGTSTATE_Disabled);
+      }
       m_pVertScrollBar->Update();
       pRepaint = m_pVertScrollBar.get();
     } else if ((m_pVertScrollBar->GetStates() & FWL_WGTSTATE_Disabled) == 0) {
-      m_pVertScrollBar->LockUpdate();
-      m_pVertScrollBar->SetRange(0, -1);
-      m_pVertScrollBar->SetStates(FWL_WGTSTATE_Disabled);
-      m_pVertScrollBar->UnlockUpdate();
+      {
+        ScopedUpdateLock update_lock(m_pHorzScrollBar.get());
+        m_pVertScrollBar->SetRange(0, -1);
+        m_pVertScrollBar->SetStates(FWL_WGTSTATE_Disabled);
+      }
       m_pVertScrollBar->Update();
       pRepaint = m_pVertScrollBar.get();
     }
@@ -832,7 +737,8 @@
 }
 
 bool CFWL_Edit::IsContentHeightOverflow() {
-  return m_EdtEngine.GetContentsBoundingBox().height > m_rtEngine.height + 1.0f;
+  return m_pEditEngine->GetContentsBoundingBox().height >
+         m_rtEngine.height + 1.0f;
 }
 
 void CFWL_Edit::Layout() {
@@ -846,12 +752,12 @@
   CFWL_ThemePart part;
   if (!m_pOuter) {
     part.m_pWidget = this;
-    CFX_RectF pUIMargin = theme->GetUIMargin(&part);
+    CFX_RectF pUIMargin = theme->GetUIMargin(part);
     m_rtEngine.Deflate(pUIMargin.left, pUIMargin.top, pUIMargin.width,
                        pUIMargin.height);
   } else if (m_pOuter->GetClassID() == FWL_Type::DateTimePicker) {
     part.m_pWidget = m_pOuter;
-    CFX_RectF pUIMargin = theme->GetUIMargin(&part);
+    CFX_RectF pUIMargin = theme->GetUIMargin(part);
     m_rtEngine.Deflate(pUIMargin.left, pUIMargin.top, pUIMargin.width,
                        pUIMargin.height);
   }
@@ -1008,17 +914,12 @@
     pRect->Offset(rtOuter.left, rtOuter.top);
   }
 
-  CXFA_FFWidget* pXFAWidget = pOuter->GetLayoutItem();
+  CFWL_Widget::AdapterIface* pXFAWidget = pOuter->GetAdapterIface();
   if (!pXFAWidget)
     return;
 
-  IXFA_DocEnvironment* pDocEnvironment =
-      pXFAWidget->GetDoc()->GetDocEnvironment();
-  if (!pDocEnvironment)
-    return;
-
   CFX_RectF rt = pXFAWidget->GetRotateMatrix().TransformRect(*pRect);
-  pDocEnvironment->DisplayCaret(pXFAWidget, true, &rt);
+  pXFAWidget->DisplayCaret(true, &rt);
 }
 
 void CFWL_Edit::HideCaret(CFX_RectF* pRect) {
@@ -1032,23 +933,18 @@
   while (pOuter->GetOuter())
     pOuter = pOuter->GetOuter();
 
-  CXFA_FFWidget* pXFAWidget = pOuter->GetLayoutItem();
+  CFWL_Widget::AdapterIface* pXFAWidget = pOuter->GetAdapterIface();
   if (!pXFAWidget)
     return;
 
-  IXFA_DocEnvironment* pDocEnvironment =
-      pXFAWidget->GetDoc()->GetDocEnvironment();
-  if (!pDocEnvironment)
-    return;
-
-  pDocEnvironment->DisplayCaret(pXFAWidget, false, pRect);
+  pXFAWidget->DisplayCaret(false, pRect);
 }
 
 bool CFWL_Edit::ValidateNumberChar(wchar_t cNum) {
   if (!m_bSetRange)
     return true;
 
-  WideString wsText = m_EdtEngine.GetText();
+  WideString wsText = m_pEditEngine->GetText();
   if (wsText.IsEmpty())
     return cNum != L'0';
 
@@ -1058,35 +954,48 @@
     return false;
 
   int32_t nLen = wsText.GetLength();
-  WideString l = wsText.Left(m_CursorPosition);
-  WideString r = wsText.Right(nLen - m_CursorPosition);
-  WideString wsNew = l + cNum + r;
+  WideString first = wsText.First(m_CursorPosition);
+  WideString last = wsText.Last(nLen - m_CursorPosition);
+  WideString wsNew = first + cNum + last;
   return wsNew.GetInteger() <= m_iMax;
 }
 
 void CFWL_Edit::InitCaret() {
-  m_pCaret.reset();
-  m_rtCaret = CFX_RectF();
+  if (m_pCaret)
+    return;
+
+  m_pCaret = pdfium::MakeUnique<CFWL_Caret>(
+      m_pOwnerApp.Get(), pdfium::MakeUnique<CFWL_WidgetProperties>(), this);
+  m_pCaret->SetParent(this);
+  m_pCaret->SetStates(m_pProperties->m_dwStates);
+  UpdateCursorRect();
 }
 
 void CFWL_Edit::UpdateCursorRect() {
-  int32_t bidi_level = 0;
-  m_rtCaret = CFX_RectF();
-  std::tie(bidi_level, m_rtCaret) =
-      m_EdtEngine.GetCharacterInfo(m_CursorPosition);
+  int32_t bidi_level;
+  if (m_pEditEngine->GetLength() > 0) {
+    std::tie(bidi_level, m_rtCaret) =
+        m_pEditEngine->GetCharacterInfo(m_CursorPosition);
+  } else {
+    bidi_level = 0;
+    m_rtCaret = CFX_RectF();
+  }
+
   // TODO(dsinclair): This should handle bidi level  ...
 
-  if (m_rtCaret.width == 0 && m_rtCaret.left > 1.0f)
-    m_rtCaret.left -= 1.0f;
-
   m_rtCaret.width = 1.0f;
+
+  // TODO(hnakashima): Handle correctly edits with empty text instead of using
+  // these defaults.
+  if (m_rtCaret.height == 0)
+    m_rtCaret.height = 8.0f;
 }
 
 void CFWL_Edit::SetCursorPosition(size_t position) {
   if (m_CursorPosition == position)
     return;
 
-  m_CursorPosition = position;
+  m_CursorPosition = std::min(position, m_pEditEngine->GetLength());
   UpdateCursorRect();
   OnCaretChanged();
 }
@@ -1136,14 +1045,16 @@
     default:
       break;
   }
-  CFWL_Widget::OnProcessMessage(pMessage);
+  // Dst target could be |this|, continue only if not destroyed by above.
+  if (pMessage->GetDstTarget())
+    CFWL_Widget::OnProcessMessage(pMessage);
 }
 
 void CFWL_Edit::OnProcessEvent(CFWL_Event* pEvent) {
   if (!pEvent || pEvent->GetType() != CFWL_Event::Type::Scroll)
     return;
 
-  CFWL_Widget* pSrcTarget = pEvent->m_pSrcTarget;
+  CFWL_Widget* pSrcTarget = pEvent->GetSrcTarget();
   if ((pSrcTarget == m_pVertScrollBar.get() && m_pVertScrollBar) ||
       (pSrcTarget == m_pHorzScrollBar.get() && m_pHorzScrollBar)) {
     CFWL_EventScroll* pScrollEvent = static_cast<CFWL_EventScroll*>(pEvent);
@@ -1158,10 +1069,8 @@
 }
 
 void CFWL_Edit::DoRButtonDown(CFWL_MessageMouse* pMsg) {
-  if ((m_pProperties->m_dwStates & FWL_WGTSTATE_Focused) == 0)
-    SetFocus(true);
-
-  m_CursorPosition = m_EdtEngine.GetIndexForPoint(DeviceToEngine(pMsg->m_pos));
+  SetCursorPosition(
+      m_pEditEngine->GetIndexForPoint(DeviceToEngine(pMsg->m_pos)));
 }
 
 void CFWL_Edit::OnFocusChanged(CFWL_Message* pMsg, bool bSet) {
@@ -1199,27 +1108,24 @@
   m_bLButtonDown = true;
   SetGrab(true);
 
-  if ((m_pProperties->m_dwStates & FWL_WGTSTATE_Focused) == 0)
-    SetFocus(true);
-
   bool bRepaint = false;
-  if (m_EdtEngine.HasSelection()) {
-    m_EdtEngine.ClearSelection();
+  if (m_pEditEngine->HasSelection()) {
+    m_pEditEngine->ClearSelection();
     bRepaint = true;
   }
 
   size_t index_at_click =
-      m_EdtEngine.GetIndexForPoint(DeviceToEngine(pMsg->m_pos));
+      m_pEditEngine->GetIndexForPoint(DeviceToEngine(pMsg->m_pos));
 
   if (index_at_click != m_CursorPosition &&
       !!(pMsg->m_dwFlags & FWL_KEYFLAG_Shift)) {
     size_t start = std::min(m_CursorPosition, index_at_click);
     size_t end = std::max(m_CursorPosition, index_at_click);
 
-    m_EdtEngine.SetSelection(start, end - start);
+    m_pEditEngine->SetSelection(start, end - start);
     bRepaint = true;
   } else {
-    m_CursorPosition = index_at_click;
+    SetCursorPosition(index_at_click);
   }
 
   if (bRepaint)
@@ -1232,12 +1138,13 @@
 }
 
 void CFWL_Edit::OnButtonDoubleClick(CFWL_MessageMouse* pMsg) {
-  size_t click_idx = m_EdtEngine.GetIndexForPoint(DeviceToEngine(pMsg->m_pos));
+  size_t click_idx =
+      m_pEditEngine->GetIndexForPoint(DeviceToEngine(pMsg->m_pos));
   size_t start_idx;
   size_t count;
-  std::tie(start_idx, count) = m_EdtEngine.BoundsForWordAt(click_idx);
+  std::tie(start_idx, count) = m_pEditEngine->BoundsForWordAt(click_idx);
 
-  m_EdtEngine.SetSelection(start_idx, count);
+  m_pEditEngine->SetSelection(start_idx, count);
   m_CursorPosition = start_idx + count;
   RepaintRect(m_rtEngine);
 }
@@ -1248,24 +1155,25 @@
     return;
 
   size_t old_cursor_pos = m_CursorPosition;
-  SetCursorPosition(m_EdtEngine.GetIndexForPoint(DeviceToEngine(pMsg->m_pos)));
+  SetCursorPosition(
+      m_pEditEngine->GetIndexForPoint(DeviceToEngine(pMsg->m_pos)));
   if (old_cursor_pos == m_CursorPosition)
     return;
 
-  size_t length = m_EdtEngine.GetLength();
+  size_t length = m_pEditEngine->GetLength();
   if (m_CursorPosition > length)
     SetCursorPosition(length);
 
   size_t sel_start = 0;
   size_t count = 0;
-  if (m_EdtEngine.HasSelection())
-    std::tie(sel_start, count) = m_EdtEngine.GetSelection();
+  if (m_pEditEngine->HasSelection())
+    std::tie(sel_start, count) = m_pEditEngine->GetSelection();
   else
     sel_start = old_cursor_pos;
 
   size_t start_pos = std::min(sel_start, m_CursorPosition);
   size_t end_pos = std::max(sel_start, m_CursorPosition);
-  m_EdtEngine.SetSelection(start_pos, end_pos - start_pos);
+  m_pEditEngine->SetSelection(start_pos, end_pos - start_pos);
 }
 
 void CFWL_Edit::OnKeyDown(CFWL_MessageKey* pMsg) {
@@ -1273,58 +1181,56 @@
   bool bCtrl = !!(pMsg->m_dwFlags & FWL_KEYFLAG_Ctrl);
 
   size_t sel_start = m_CursorPosition;
-  if (m_EdtEngine.HasSelection()) {
+  if (m_pEditEngine->HasSelection()) {
     size_t start_idx;
     size_t count;
-    std::tie(start_idx, count) = m_EdtEngine.GetSelection();
+    std::tie(start_idx, count) = m_pEditEngine->GetSelection();
     sel_start = start_idx;
   }
 
   switch (pMsg->m_dwKeyCode) {
-    case FWL_VKEY_Left:
-      SetCursorPosition(m_EdtEngine.GetIndexLeft(m_CursorPosition));
+    case XFA_FWL_VKEY_Left:
+      SetCursorPosition(m_pEditEngine->GetIndexLeft(m_CursorPosition));
       break;
-    case FWL_VKEY_Right:
-      SetCursorPosition(m_EdtEngine.GetIndexRight(m_CursorPosition));
+    case XFA_FWL_VKEY_Right:
+      SetCursorPosition(m_pEditEngine->GetIndexRight(m_CursorPosition));
       break;
-    case FWL_VKEY_Up:
-      SetCursorPosition(m_EdtEngine.GetIndexUp(m_CursorPosition));
+    case XFA_FWL_VKEY_Up:
+      SetCursorPosition(m_pEditEngine->GetIndexUp(m_CursorPosition));
       break;
-    case FWL_VKEY_Down:
-      SetCursorPosition(m_EdtEngine.GetIndexDown(m_CursorPosition));
+    case XFA_FWL_VKEY_Down:
+      SetCursorPosition(m_pEditEngine->GetIndexDown(m_CursorPosition));
       break;
-    case FWL_VKEY_Home:
+    case XFA_FWL_VKEY_Home:
       SetCursorPosition(
-          bCtrl ? 0 : m_EdtEngine.GetIndexAtStartOfLine(m_CursorPosition));
+          bCtrl ? 0 : m_pEditEngine->GetIndexAtStartOfLine(m_CursorPosition));
       break;
-    case FWL_VKEY_End:
+    case XFA_FWL_VKEY_End:
       SetCursorPosition(
-          bCtrl ? m_EdtEngine.GetLength()
-                : m_EdtEngine.GetIndexAtEndOfLine(m_CursorPosition));
+          bCtrl ? m_pEditEngine->GetLength()
+                : m_pEditEngine->GetIndexAtEndOfLine(m_CursorPosition));
       break;
-    case FWL_VKEY_Delete: {
+    case XFA_FWL_VKEY_Delete: {
       if ((m_pProperties->m_dwStyleExes & FWL_STYLEEXT_EDT_ReadOnly) ||
           (m_pProperties->m_dwStates & FWL_WGTSTATE_Disabled)) {
         break;
       }
 
-      if (m_CursorPosition > 0) {
-        SetCursorPosition(m_EdtEngine.GetIndexBefore(m_CursorPosition));
-        m_EdtEngine.Delete(m_CursorPosition, 1);
-      }
+      m_pEditEngine->Delete(m_CursorPosition, 1);
+      UpdateCaret();
       break;
     }
-    case FWL_VKEY_Insert:
-    case FWL_VKEY_F2:
-    case FWL_VKEY_Tab:
+    case XFA_FWL_VKEY_Insert:
+    case XFA_FWL_VKEY_F2:
+    case XFA_FWL_VKEY_Tab:
     default:
       break;
   }
 
   // Update the selection.
   if (bShift && sel_start != m_CursorPosition) {
-    m_EdtEngine.SetSelection(std::min(sel_start, m_CursorPosition),
-                             std::max(sel_start, m_CursorPosition));
+    m_pEditEngine->SetSelection(std::min(sel_start, m_CursorPosition),
+                                std::max(sel_start, m_CursorPosition));
     RepaintRect(m_rtEngine);
   }
 }
@@ -1337,41 +1243,32 @@
 
   wchar_t c = static_cast<wchar_t>(pMsg->m_dwKeyCode);
   switch (c) {
-    case FWL_VKEY_Back:
+    case L'\b':
       if (m_CursorPosition > 0) {
-        SetCursorPosition(m_EdtEngine.GetIndexBefore(m_CursorPosition));
-        m_EdtEngine.Delete(m_CursorPosition, 1);
+        SetCursorPosition(m_CursorPosition - 1);
+        m_pEditEngine->Delete(m_CursorPosition, 1);
+        UpdateCaret();
       }
       break;
-    case FWL_VKEY_NewLine:
-    case FWL_VKEY_Escape:
+    case L'\n':
+    case 27:   // Esc
+    case 127:  // Delete
       break;
-    case FWL_VKEY_Tab:
-      m_EdtEngine.Insert(m_CursorPosition, L"\t");
+    case L'\t':
+      m_pEditEngine->Insert(m_CursorPosition, L"\t");
       SetCursorPosition(m_CursorPosition + 1);
       break;
-    case FWL_VKEY_Return:
+    case L'\r':
       if (m_pProperties->m_dwStyleExes & FWL_STYLEEXT_EDT_WantReturn) {
-        m_EdtEngine.Insert(m_CursorPosition, L"\n");
+        m_pEditEngine->Insert(m_CursorPosition, L"\n");
         SetCursorPosition(m_CursorPosition + 1);
       }
       break;
     default: {
-      if (!m_pWidgetMgr->IsFormDisabled()) {
-        if (m_pProperties->m_dwStyleExes & FWL_STYLEEXT_EDT_Number) {
-          if (((pMsg->m_dwKeyCode < FWL_VKEY_0) &&
-               (pMsg->m_dwKeyCode != 0x2E && pMsg->m_dwKeyCode != 0x2D)) ||
-              pMsg->m_dwKeyCode > FWL_VKEY_9) {
-            break;
-          }
-          if (!ValidateNumberChar(c))
-            break;
-        }
-      }
       if (pMsg->m_dwFlags & kEditingModifier)
         break;
 
-      m_EdtEngine.Insert(m_CursorPosition, WideString(c));
+      m_pEditEngine->Insert(m_CursorPosition, WideString(c));
       SetCursorPosition(m_CursorPosition + 1);
       break;
     }
diff --git a/xfa/fwl/cfwl_edit.h b/xfa/fwl/cfwl_edit.h
index 9c667f5..0242e5c 100644
--- a/xfa/fwl/cfwl_edit.h
+++ b/xfa/fwl/cfwl_edit.h
@@ -9,7 +9,6 @@
 
 #include <memory>
 #include <utility>
-#include <vector>
 
 #include "xfa/fde/cfde_texteditengine.h"
 #include "xfa/fwl/cfwl_event.h"
@@ -66,6 +65,7 @@
                     const CFX_Matrix& matrix) override;
 
   virtual void SetText(const WideString& wsText);
+  virtual void SetTextSkipNotify(const WideString& wsText);
 
   int32_t GetTextLength() const;
   WideString GetText() const;
@@ -93,7 +93,8 @@
   // CFDE_TextEditEngine::Delegate
   void NotifyTextFull() override;
   void OnCaretChanged() override;
-  void OnTextChanged(const WideString& prevText) override;
+  void OnTextWillChange(CFDE_TextEditEngine::TextChange* change) override;
+  void OnTextChanged() override;
   void OnSelChanged() override;
   bool OnValidate(const WideString& wsText) override;
   void SetScrollOffset(float fScrollOffset) override;
@@ -102,7 +103,7 @@
   void ShowCaret(CFX_RectF* pRect);
   void HideCaret(CFX_RectF* pRect);
   const CFX_RectF& GetRTClient() const { return m_rtClient; }
-  CFDE_TextEditEngine* GetTxtEdtEngine() { return &m_EdtEngine; }
+  CFDE_TextEditEngine* GetTxtEdtEngine() { return m_pEditEngine.get(); }
 
  private:
   void RenderText(CFX_RenderDevice* pRenderDev,
@@ -114,7 +115,6 @@
   void DrawContent(CXFA_Graphics* pGraphics,
                    IFWL_ThemeProvider* pTheme,
                    const CFX_Matrix* pMatrix);
-  void DrawSpellCheck(CXFA_Graphics* pGraphics, const CFX_Matrix* pMatrix);
 
   void UpdateEditEngine();
   void UpdateEditParams();
@@ -134,11 +134,6 @@
   bool ValidateNumberChar(wchar_t cNum);
   bool IsShowScrollBar(bool bVert);
   bool IsContentHeightOverflow();
-  void AddSpellCheckObj(CXFA_GEPath& PathData,
-                        int32_t nStart,
-                        int32_t nCount,
-                        float fOffSetX,
-                        float fOffSetY);
   void SetCursorPosition(size_t position);
   void UpdateCursorRect();
 
@@ -158,16 +153,16 @@
   CFX_RectF m_rtEngine;
   CFX_RectF m_rtStatic;
   CFX_RectF m_rtCaret;
-  float m_fVAlignOffset;
-  float m_fScrollOffsetX;
-  float m_fScrollOffsetY;
-  CFDE_TextEditEngine m_EdtEngine;
-  bool m_bLButtonDown;
-  size_t m_CursorPosition;
-  int32_t m_nLimit;
-  float m_fFontSize;
-  bool m_bSetRange;
-  int32_t m_iMax;
+  bool m_bLButtonDown = false;
+  bool m_bSetRange = false;
+  int32_t m_nLimit = -1;
+  int32_t m_iMax = 0xFFFFFFF;
+  float m_fVAlignOffset = 0.0f;
+  float m_fScrollOffsetX = 0.0f;
+  float m_fScrollOffsetY = 0.0f;
+  float m_fFontSize = 0.0f;
+  size_t m_CursorPosition = 0;
+  std::unique_ptr<CFDE_TextEditEngine> const m_pEditEngine;
   std::unique_ptr<CFWL_ScrollBar> m_pVertScrollBar;
   std::unique_ptr<CFWL_ScrollBar> m_pHorzScrollBar;
   std::unique_ptr<CFWL_Caret> m_pCaret;
diff --git a/xfa/fwl/cfwl_edit_embeddertest.cpp b/xfa/fwl/cfwl_edit_embeddertest.cpp
index 59a4ca5..9253293 100644
--- a/xfa/fwl/cfwl_edit_embeddertest.cpp
+++ b/xfa/fwl/cfwl_edit_embeddertest.cpp
@@ -8,13 +8,13 @@
 #include "testing/embedder_test.h"
 #include "testing/embedder_test_timer_handling_delegate.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "testing/xfa_js_embedder_test.h"
 
-class CFWLEditEmbeddertest : public EmbedderTest {
+class CFWLEditEmbedderTest : public XFAJSEmbedderTest {
  protected:
   void SetUp() override {
     EmbedderTest::SetUp();
     SetDelegate(&delegate_);
-    CreateAndInitializeFormPDF();
   }
 
   void TearDown() override {
@@ -22,8 +22,8 @@
     EmbedderTest::TearDown();
   }
 
-  void CreateAndInitializeFormPDF() {
-    EXPECT_TRUE(OpenDocument("xfa/email_recommended.pdf"));
+  void CreateAndInitializeFormPDF(const char* filename) {
+    EXPECT_TRUE(OpenDocument(filename));
     page_ = LoadPage(0);
     ASSERT_TRUE(page_);
   }
@@ -36,15 +36,13 @@
   EmbedderTestTimerHandlingDelegate delegate_;
 };
 
-TEST_F(CFWLEditEmbeddertest, Trivial) {
-  ASSERT_EQ(1u, delegate().GetAlerts().size());
-  auto alert = delegate().GetAlerts()[0];
-  EXPECT_STREQ(L"PDFium", alert.title.c_str());
-  EXPECT_STREQ(L"The value you entered for Text Field is invalid.",
-               alert.message.c_str());
+TEST_F(CFWLEditEmbedderTest, Trivial) {
+  CreateAndInitializeFormPDF("xfa/email_recommended.pdf");
+  ASSERT_EQ(0u, delegate().GetAlerts().size());
 }
 
-TEST_F(CFWLEditEmbeddertest, LeftClickMouseSelection) {
+TEST_F(CFWLEditEmbedderTest, LeftClickMouseSelection) {
+  CreateAndInitializeFormPDF("xfa/email_recommended.pdf");
   FORM_OnLButtonDown(form_handle(), page(), 0, 115, 58);
   for (size_t i = 0; i < 10; ++i)
     FORM_OnChar(form_handle(), page(), 'a' + i, 0);
@@ -61,7 +59,14 @@
   EXPECT_STREQ(L"defgh", WideString::FromUTF16LE(buf, len).c_str());
 }
 
-TEST_F(CFWLEditEmbeddertest, DragMouseSelection) {
+// TODO(crbug.com/pdfium/11): Fix this test and enable.
+#if defined(_SKIA_SUPPORT_) || defined(_SKIA_SUPPORT_PATHS_)
+#define MAYBE_DragMouseSelection DISABLED_DragMouseSelection
+#else
+#define MAYBE_DragMouseSelection DragMouseSelection
+#endif
+TEST_F(CFWLEditEmbedderTest, MAYBE_DragMouseSelection) {
+  CreateAndInitializeFormPDF("xfa/email_recommended.pdf");
   FORM_OnLButtonDown(form_handle(), page(), 0, 115, 58);
   for (size_t i = 0; i < 10; ++i)
     FORM_OnChar(form_handle(), page(), 'a' + i, 0);
@@ -76,4 +81,162 @@
   unsigned short buf[128];
   unsigned long len = FORM_GetSelectedText(form_handle(), page(), &buf, 128);
   EXPECT_STREQ(L"defgh", WideString::FromUTF16LE(buf, len).c_str());
+
+  // TODO(hnakashima): This is incorrect. Visually 'abcdefgh' are selected.
+  const char kDraggedMD5[] = "f131526c8edd04e44de17b2647ec54c8";
+  {
+    ScopedFPDFBitmap page_bitmap =
+        RenderLoadedPageWithFlags(page(), FPDF_ANNOT);
+    CompareBitmap(page_bitmap.get(), 612, 792, kDraggedMD5);
+  }
+}
+
+// TODO(crbug.com/pdfium/11): Fix this test and enable.
+#if defined(_SKIA_SUPPORT_) || defined(_SKIA_SUPPORT_PATHS_)
+#define MAYBE_SimpleFill DISABLED_SimpleFill
+#else
+#define MAYBE_SimpleFill SimpleFill
+#endif
+TEST_F(CFWLEditEmbedderTest, MAYBE_SimpleFill) {
+  CreateAndInitializeFormPDF("xfa/email_recommended.pdf");
+  const char kBlankMD5[] = "8dda78a3afaf9f7b5210eb81cacc4600";
+  {
+    ScopedFPDFBitmap page_bitmap =
+        RenderLoadedPageWithFlags(page(), FPDF_ANNOT);
+    CompareBitmap(page_bitmap.get(), 612, 792, kBlankMD5);
+  }
+
+  FORM_OnLButtonDown(form_handle(), page(), 0, 115, 58);
+  for (size_t i = 0; i < 10; ++i)
+    FORM_OnChar(form_handle(), page(), 'a' + i, 0);
+
+  const char kFilledMD5[] = "211e4e46eb347aa2bc7c425556d600b0";
+  {
+    ScopedFPDFBitmap page_bitmap =
+        RenderLoadedPageWithFlags(page(), FPDF_ANNOT);
+    CompareBitmap(page_bitmap.get(), 612, 792, kFilledMD5);
+  }
+}
+
+// TODO(crbug.com/pdfium/11): Fix this test and enable.
+#if defined(_SKIA_SUPPORT_) || defined(_SKIA_SUPPORT_PATHS_)
+#define MAYBE_FillWithNewLineWithoutMultiline \
+  DISABLED_FillWithNewLineWithoutMultiline
+#else
+#define MAYBE_FillWithNewLineWithoutMultiline FillWithNewLineWithoutMultiline
+#endif
+TEST_F(CFWLEditEmbedderTest, MAYBE_FillWithNewLineWithoutMultiline) {
+  CreateAndInitializeFormPDF("xfa/email_recommended.pdf");
+  FORM_OnLButtonDown(form_handle(), page(), 0, 115, 58);
+  for (size_t i = 0; i < 5; ++i)
+    FORM_OnChar(form_handle(), page(), 'a' + i, 0);
+  FORM_OnChar(form_handle(), page(), '\r', 0);
+  for (size_t i = 5; i < 10; ++i)
+    FORM_OnChar(form_handle(), page(), 'a' + i, 0);
+
+  const char kFilledMD5[] = "211e4e46eb347aa2bc7c425556d600b0";
+  {
+    ScopedFPDFBitmap page_bitmap =
+        RenderLoadedPageWithFlags(page(), FPDF_ANNOT);
+    CompareBitmap(page_bitmap.get(), 612, 792, kFilledMD5);
+  }
+}
+
+// Disabled due to flakiness.
+TEST_F(CFWLEditEmbedderTest, DISABLED_FillWithNewLineWithMultiline) {
+  CreateAndInitializeFormPDF("xfa/xfa_multiline_textfield.pdf");
+  FORM_OnLButtonDown(form_handle(), page(), 0, 115, 58);
+
+  for (size_t i = 0; i < 5; ++i)
+    FORM_OnChar(form_handle(), page(), 'a' + i, 0);
+  FORM_OnChar(form_handle(), page(), '\r', 0);
+  for (size_t i = 5; i < 10; ++i)
+    FORM_OnChar(form_handle(), page(), 'a' + i, 0);
+
+  // Should look like:
+  // abcde
+  // fghij|
+  {
+#if _FX_PLATFORM_ == _FX_PLATFORM_LINUX_
+    const char kFilledMultilineMD5[] = "fc1f4d5fdb2c5755005fc525b0a60ec9";
+#else
+    const char kFilledMultilineMD5[] = "a5654e027d8b1667c20f3b86d1918003";
+#endif  // _FX_PLATFORM_ == _FX_PLATFORM_LINUX_
+    ScopedFPDFBitmap page_bitmap =
+        RenderLoadedPageWithFlags(page(), FPDF_ANNOT);
+    CompareBitmap(page_bitmap.get(), 612, 792, kFilledMultilineMD5);
+  }
+
+  for (size_t i = 0; i < 4; ++i)
+    FORM_OnKeyDown(form_handle(), page(), FWL_VKEY_Left, 0);
+
+  // Should look like:
+  // abcde
+  // f|ghij
+
+  // Two backspaces is a workaround because left arrow does not behave well
+  // in the first character of a line. It skips back to the previous line.
+  for (size_t i = 0; i < 2; ++i)
+    FORM_OnChar(form_handle(), page(), '\b', 0);
+
+  // Should look like:
+  // abcde|ghij
+  {
+#if _FX_PLATFORM_ == _FX_PLATFORM_LINUX_
+    const char kMultilineBackspaceMD5[] = "8bb62a8100ff1e1cc113d4033e0d824e";
+#else
+    const char kMultilineBackspaceMD5[] = "a2f1dcab92bb1fb7c2f9ccc70100c989";
+#endif  // _FX_PLATFORM_ == _FX_PLATFORM_LINUX_
+    ScopedFPDFBitmap page_bitmap =
+        RenderLoadedPageWithFlags(page(), FPDF_ANNOT);
+    CompareBitmap(page_bitmap.get(), 612, 792, kMultilineBackspaceMD5);
+  }
+}
+
+// TODO(crbug.com/pdfium/11): Fix this test and enable.
+#if defined(_SKIA_SUPPORT_) || defined(_SKIA_SUPPORT_PATHS_)
+#define MAYBE_DateTimePickerTest DISABLED_DateTimePickerTest
+#else
+#define MAYBE_DateTimePickerTest DateTimePickerTest
+#endif
+TEST_F(CFWLEditEmbedderTest, MAYBE_DateTimePickerTest) {
+  CreateAndInitializeFormPDF("xfa/xfa_date_time_edit.pdf");
+  FORM_OnLButtonDown(form_handle(), page(), 0, 115, 58);
+
+  const char kFilledMD5[] = "1036b8837a9dba75c6bd8f9347ae2eb2";
+  {
+    ScopedFPDFBitmap page_bitmap =
+        RenderLoadedPageWithFlags(page(), FPDF_ANNOT);
+    CompareBitmap(page_bitmap.get(), 612, 792, kFilledMD5);
+  }
+}
+
+TEST_F(CFWLEditEmbedderTest, ImageEditTest) {
+  CreateAndInitializeFormPDF("xfa/xfa_image_edit.pdf");
+  FORM_OnLButtonDown(form_handle(), page(), 0, 115, 58);
+
+  const char kFilledMD5[] = "1940568c9ba33bac5d0b1ee9558c76b3";
+  {
+    ScopedFPDFBitmap page_bitmap =
+        RenderLoadedPageWithFlags(page(), FPDF_ANNOT);
+    CompareBitmap(page_bitmap.get(), 612, 792, kFilledMD5);
+  }
+}
+
+// TODO(crbug.com/pdfium/11): Fix this test and enable.
+#if defined(_SKIA_SUPPORT_) || defined(_SKIA_SUPPORT_PATHS_)
+#define MAYBE_ComboBoxTest DISABLED_ComboBoxTest
+#else
+#define MAYBE_ComboBoxTest ComboBoxTest
+#endif
+TEST_F(CFWLEditEmbedderTest, MAYBE_ComboBoxTest) {
+  CreateAndInitializeFormPDF("xfa/xfa_combobox.pdf");
+  FORM_OnLButtonDown(form_handle(), page(), 0, 115, 58);
+
+  const char kFilledMD5[] = "dad642ae8a5afce2591ffbcabbfc58dd";
+  {
+    ScopedFPDFBitmap page_bitmap =
+        RenderLoadedPageWithFlags(page(), FPDF_ANNOT);
+    CompareBitmap(page_bitmap.get(), 612, 792, kFilledMD5);
+  }
 }
diff --git a/xfa/fwl/cfwl_event.cpp b/xfa/fwl/cfwl_event.cpp
index 827eccc..5922bc1 100644
--- a/xfa/fwl/cfwl_event.cpp
+++ b/xfa/fwl/cfwl_event.cpp
@@ -6,15 +6,14 @@
 
 #include "xfa/fwl/cfwl_event.h"
 
-CFWL_Event::CFWL_Event(CFWL_Event::Type type)
-    : CFWL_Event(type, nullptr, nullptr) {}
+CFWL_Event::CFWL_Event(CFWL_Event::Type type) : m_type(type) {}
 
 CFWL_Event::CFWL_Event(Type type, CFWL_Widget* pSrcTarget)
-    : CFWL_Event(type, pSrcTarget, nullptr) {}
+    : m_type(type), m_pSrcTarget(pSrcTarget) {}
 
 CFWL_Event::CFWL_Event(Type type,
                        CFWL_Widget* pSrcTarget,
                        CFWL_Widget* pDstTarget)
-    : m_pSrcTarget(pSrcTarget), m_pDstTarget(pDstTarget), m_type(type) {}
+    : m_type(type), m_pSrcTarget(pSrcTarget), m_pDstTarget(pDstTarget) {}
 
-CFWL_Event::~CFWL_Event() {}
+CFWL_Event::~CFWL_Event() = default;
diff --git a/xfa/fwl/cfwl_event.h b/xfa/fwl/cfwl_event.h
index 01e3914..832c01f 100644
--- a/xfa/fwl/cfwl_event.h
+++ b/xfa/fwl/cfwl_event.h
@@ -7,20 +7,13 @@
 #ifndef XFA_FWL_CFWL_EVENT_H_
 #define XFA_FWL_CFWL_EVENT_H_
 
-#include "core/fxcrt/fx_coordinates.h"
-#include "core/fxcrt/fx_string.h"
-#include "core/fxcrt/fx_system.h"
-#include "xfa/fwl/cfwl_messagekey.h"
-#include "xfa/fwl/cfwl_messagemouse.h"
-
-class CXFA_Graphics;
-class CFWL_Widget;
+#include "core/fxcrt/observed_ptr.h"
+#include "xfa/fwl/cfwl_widget.h"
 
 class CFWL_Event {
  public:
   enum class Type {
     CheckStateChanged,
-    CheckWord,
     Click,
     Close,
     EditChanged,
@@ -29,7 +22,7 @@
     PreDropDown,
     Scroll,
     SelectChanged,
-    TextChanged,
+    TextWillChange,
     TextFull,
     Validate
   };
@@ -40,12 +33,13 @@
   virtual ~CFWL_Event();
 
   Type GetType() const { return m_type; }
-
-  CFWL_Widget* m_pSrcTarget;
-  CFWL_Widget* m_pDstTarget;
+  CFWL_Widget* GetSrcTarget() const { return m_pSrcTarget.Get(); }
+  CFWL_Widget* GetDstTarget() const { return m_pDstTarget.Get(); }
 
  private:
-  Type m_type;
+  const Type m_type;
+  ObservedPtr<CFWL_Widget> const m_pSrcTarget;
+  ObservedPtr<CFWL_Widget> const m_pDstTarget;
 };
 
 #endif  // XFA_FWL_CFWL_EVENT_H_
diff --git a/xfa/fwl/cfwl_eventcheckword.cpp b/xfa/fwl/cfwl_eventcheckword.cpp
deleted file mode 100644
index fb0ce6e..0000000
--- a/xfa/fwl/cfwl_eventcheckword.cpp
+++ /dev/null
@@ -1,12 +0,0 @@
-// Copyright 2016 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
-
-#include "xfa/fwl/cfwl_eventcheckword.h"
-
-CFWL_EventCheckWord::CFWL_EventCheckWord(CFWL_Widget* pSrcTarget)
-    : CFWL_Event(CFWL_Event::Type::CheckWord, pSrcTarget) {}
-
-CFWL_EventCheckWord::~CFWL_EventCheckWord() {}
diff --git a/xfa/fwl/cfwl_eventcheckword.h b/xfa/fwl/cfwl_eventcheckword.h
deleted file mode 100644
index fafe3d3..0000000
--- a/xfa/fwl/cfwl_eventcheckword.h
+++ /dev/null
@@ -1,21 +0,0 @@
-// Copyright 2016 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_FWL_CFWL_EVENTCHECKWORD_H_
-#define XFA_FWL_CFWL_EVENTCHECKWORD_H_
-
-#include "xfa/fwl/cfwl_event.h"
-
-class CFWL_EventCheckWord : public CFWL_Event {
- public:
-  explicit CFWL_EventCheckWord(CFWL_Widget* pSrcTarget);
-  ~CFWL_EventCheckWord() override;
-
-  ByteString bsWord;
-  bool bCheckWord;
-};
-
-#endif  // XFA_FWL_CFWL_EVENTCHECKWORD_H_
diff --git a/xfa/fwl/cfwl_eventmouse.h b/xfa/fwl/cfwl_eventmouse.h
index a5caa93..e7982fb 100644
--- a/xfa/fwl/cfwl_eventmouse.h
+++ b/xfa/fwl/cfwl_eventmouse.h
@@ -8,14 +8,15 @@
 #define XFA_FWL_CFWL_EVENTMOUSE_H_
 
 #include "xfa/fwl/cfwl_event.h"
+#include "xfa/fwl/cfwl_messagemouse.h"
 
-class CFWL_EventMouse : public CFWL_Event {
+class CFWL_EventMouse final : public CFWL_Event {
  public:
   explicit CFWL_EventMouse(CFWL_Widget* pSrcTarget);
   CFWL_EventMouse(CFWL_Widget* pSrcTarget, CFWL_Widget* pDstTarget);
   ~CFWL_EventMouse() override;
 
-  FWL_MouseCommand m_dwCmd;
+  FWL_MouseCommand m_dwCmd = FWL_MouseCommand::LeftButtonDown;
 };
 
 #endif  // XFA_FWL_CFWL_EVENTMOUSE_H_
diff --git a/xfa/fwl/cfwl_eventscroll.h b/xfa/fwl/cfwl_eventscroll.h
index a13eeef..78960c8 100644
--- a/xfa/fwl/cfwl_eventscroll.h
+++ b/xfa/fwl/cfwl_eventscroll.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fwl/cfwl_event.h"
 
-class CFWL_EventScroll : public CFWL_Event {
+class CFWL_EventScroll final : public CFWL_Event {
  public:
   enum class Code {
     None = 1,
@@ -27,8 +27,8 @@
   explicit CFWL_EventScroll(CFWL_Widget* pSrcTarget);
   ~CFWL_EventScroll() override;
 
-  Code m_iScrollCode;
-  float m_fPos;
+  Code m_iScrollCode = Code::None;
+  float m_fPos = 0.0f;
 };
 
 #endif  // XFA_FWL_CFWL_EVENTSCROLL_H_
diff --git a/xfa/fwl/cfwl_eventselectchanged.h b/xfa/fwl/cfwl_eventselectchanged.h
index 30f1e2d..d4b68b3 100644
--- a/xfa/fwl/cfwl_eventselectchanged.h
+++ b/xfa/fwl/cfwl_eventselectchanged.h
@@ -9,18 +9,18 @@
 
 #include "xfa/fwl/cfwl_event.h"
 
-class CFWL_EventSelectChanged : public CFWL_Event {
+class CFWL_EventSelectChanged final : public CFWL_Event {
  public:
   explicit CFWL_EventSelectChanged(CFWL_Widget* pSrcTarget);
   ~CFWL_EventSelectChanged() override;
 
   // Used by ComboBox.
-  bool bLButtonUp;
+  bool bLButtonUp = false;
 
   // Used by DateTimePIcker
-  int32_t iYear;
-  int32_t iMonth;
-  int32_t iDay;
+  int32_t iYear = -1;
+  int32_t iMonth = -1;
+  int32_t iDay = -1;
 };
 
 #endif  // XFA_FWL_CFWL_EVENTSELECTCHANGED_H_
diff --git a/xfa/fwl/cfwl_eventtarget.cpp b/xfa/fwl/cfwl_eventtarget.cpp
index 8a3b787..4b3d87c 100644
--- a/xfa/fwl/cfwl_eventtarget.cpp
+++ b/xfa/fwl/cfwl_eventtarget.cpp
@@ -10,7 +10,7 @@
 #include "xfa/fwl/ifwl_widgetdelegate.h"
 
 CFWL_EventTarget::CFWL_EventTarget(CFWL_Widget* pListener)
-    : m_pListener(pListener), m_bValid(true) {}
+    : m_pListener(pListener) {}
 
 CFWL_EventTarget::~CFWL_EventTarget() {}
 
@@ -23,7 +23,7 @@
   IFWL_WidgetDelegate* pDelegate = m_pListener->GetDelegate();
   if (!pDelegate)
     return false;
-  if (!m_widgets.empty() && m_widgets.count(pEvent->m_pSrcTarget) == 0)
+  if (!m_widgets.empty() && m_widgets.count(pEvent->GetSrcTarget()) == 0)
     return false;
 
   pDelegate->OnProcessEvent(pEvent);
diff --git a/xfa/fwl/cfwl_eventtarget.h b/xfa/fwl/cfwl_eventtarget.h
index b5a8bdb..f614319 100644
--- a/xfa/fwl/cfwl_eventtarget.h
+++ b/xfa/fwl/cfwl_eventtarget.h
@@ -26,9 +26,9 @@
   void FlagInvalid() { m_bValid = false; }
 
  private:
+  bool m_bValid = true;
+  CFWL_Widget* const m_pListener;
   std::set<CFWL_Widget*> m_widgets;
-  CFWL_Widget* m_pListener;
-  bool m_bValid;
 };
 
 #endif  // XFA_FWL_CFWL_EVENTTARGET_H_
diff --git a/xfa/fwl/cfwl_eventtextchanged.cpp b/xfa/fwl/cfwl_eventtextchanged.cpp
deleted file mode 100644
index 439d99d..0000000
--- a/xfa/fwl/cfwl_eventtextchanged.cpp
+++ /dev/null
@@ -1,12 +0,0 @@
-// Copyright 2016 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
-
-#include "xfa/fwl/cfwl_eventtextchanged.h"
-
-CFWL_EventTextChanged::CFWL_EventTextChanged(CFWL_Widget* pSrcTarget)
-    : CFWL_Event(CFWL_Event::Type::TextChanged, pSrcTarget) {}
-
-CFWL_EventTextChanged::~CFWL_EventTextChanged() {}
diff --git a/xfa/fwl/cfwl_eventtextchanged.h b/xfa/fwl/cfwl_eventtextchanged.h
deleted file mode 100644
index 4494f08..0000000
--- a/xfa/fwl/cfwl_eventtextchanged.h
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright 2016 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_FWL_CFWL_EVENTTEXTCHANGED_H_
-#define XFA_FWL_CFWL_EVENTTEXTCHANGED_H_
-
-#include "xfa/fwl/cfwl_event.h"
-
-class CFWL_EventTextChanged : public CFWL_Event {
- public:
-  explicit CFWL_EventTextChanged(CFWL_Widget* pSrcTarget);
-  ~CFWL_EventTextChanged() override;
-
-  WideString wsPrevText;
-};
-
-#endif  // XFA_FWL_CFWL_EVENTTEXTCHANGED_H_
diff --git a/xfa/fwl/cfwl_eventtextwillchange.cpp b/xfa/fwl/cfwl_eventtextwillchange.cpp
new file mode 100644
index 0000000..22b1100
--- /dev/null
+++ b/xfa/fwl/cfwl_eventtextwillchange.cpp
@@ -0,0 +1,12 @@
+// Copyright 2016 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
+
+#include "xfa/fwl/cfwl_eventtextwillchange.h"
+
+CFWL_EventTextWillChange::CFWL_EventTextWillChange(CFWL_Widget* pSrcTarget)
+    : CFWL_Event(CFWL_Event::Type::TextWillChange, pSrcTarget) {}
+
+CFWL_EventTextWillChange::~CFWL_EventTextWillChange() = default;
diff --git a/xfa/fwl/cfwl_eventtextwillchange.h b/xfa/fwl/cfwl_eventtextwillchange.h
new file mode 100644
index 0000000..a1bfe8c
--- /dev/null
+++ b/xfa/fwl/cfwl_eventtextwillchange.h
@@ -0,0 +1,24 @@
+// Copyright 2016 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_FWL_CFWL_EVENTTEXTWILLCHANGE_H_
+#define XFA_FWL_CFWL_EVENTTEXTWILLCHANGE_H_
+
+#include "xfa/fwl/cfwl_event.h"
+
+class CFWL_EventTextWillChange final : public CFWL_Event {
+ public:
+  explicit CFWL_EventTextWillChange(CFWL_Widget* pSrcTarget);
+  ~CFWL_EventTextWillChange() override;
+
+  WideString change_text;
+  WideString previous_text;
+  bool cancelled = false;
+  size_t selection_start = 0;
+  size_t selection_end = 0;
+};
+
+#endif  // XFA_FWL_CFWL_EVENTTEXTWILLCHANGE_H_
diff --git a/xfa/fwl/cfwl_eventvalidate.h b/xfa/fwl/cfwl_eventvalidate.h
index b8feff1..26e3c7f 100644
--- a/xfa/fwl/cfwl_eventvalidate.h
+++ b/xfa/fwl/cfwl_eventvalidate.h
@@ -9,13 +9,13 @@
 
 #include "xfa/fwl/cfwl_event.h"
 
-class CFWL_EventValidate : public CFWL_Event {
+class CFWL_EventValidate final : public CFWL_Event {
  public:
   explicit CFWL_EventValidate(CFWL_Widget* pSrcTarget);
   ~CFWL_EventValidate() override;
 
+  bool bValidate = false;
   WideString wsInsert;
-  bool bValidate;
 };
 
 #endif  // XFA_FWL_CFWL_EVENTVALIDATE_H_
diff --git a/xfa/fwl/cfwl_form.cpp b/xfa/fwl/cfwl_form.cpp
deleted file mode 100644
index d1c1783..0000000
--- a/xfa/fwl/cfwl_form.cpp
+++ /dev/null
@@ -1,250 +0,0 @@
-// Copyright 2014 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
-
-#include "xfa/fwl/cfwl_form.h"
-
-#include <utility>
-
-#include "third_party/base/ptr_util.h"
-#include "xfa/fde/cfde_textout.h"
-#include "xfa/fwl/cfwl_app.h"
-#include "xfa/fwl/cfwl_event.h"
-#include "xfa/fwl/cfwl_formproxy.h"
-#include "xfa/fwl/cfwl_messagemouse.h"
-#include "xfa/fwl/cfwl_notedriver.h"
-#include "xfa/fwl/cfwl_noteloop.h"
-#include "xfa/fwl/cfwl_themebackground.h"
-#include "xfa/fwl/cfwl_themepart.h"
-#include "xfa/fwl/cfwl_themetext.h"
-#include "xfa/fwl/cfwl_widgetmgr.h"
-#include "xfa/fwl/ifwl_themeprovider.h"
-
-CFWL_Form::CFWL_Form(const CFWL_App* app,
-                     std::unique_ptr<CFWL_WidgetProperties> properties,
-                     CFWL_Widget* pOuter)
-    : CFWL_Widget(app, std::move(properties), pOuter),
-      m_pSubFocus(nullptr),
-      m_fCXBorder(0),
-      m_fCYBorder(0) {
-  m_rtRelative.Reset();
-  m_rtRestore.Reset();
-
-  RegisterForm();
-  RegisterEventTarget(nullptr);
-}
-
-CFWL_Form::~CFWL_Form() {
-  UnregisterEventTarget();
-  UnRegisterForm();
-}
-
-FWL_Type CFWL_Form::GetClassID() const {
-  return FWL_Type::Form;
-}
-
-bool CFWL_Form::IsInstance(const WideStringView& wsClass) const {
-  if (wsClass == WideStringView(FWL_CLASS_Form))
-    return true;
-  return CFWL_Widget::IsInstance(wsClass);
-}
-
-CFX_RectF CFWL_Form::GetClientRect() {
-  CFX_RectF rect = m_pProperties->m_rtWidget;
-  rect.Offset(-rect.left, -rect.top);
-  return rect;
-}
-
-void CFWL_Form::Update() {
-  if (m_iLock > 0)
-    return;
-  if (!m_pProperties->m_pThemeProvider)
-    m_pProperties->m_pThemeProvider = GetAvailableTheme();
-
-  Layout();
-}
-
-FWL_WidgetHit CFWL_Form::HitTest(const CFX_PointF& point) {
-  GetAvailableTheme();
-
-  CFX_RectF rtCap(m_fCYBorder, m_fCXBorder, -2 * m_fCYBorder, 0 - m_fCXBorder);
-  return rtCap.Contains(point) ? FWL_WidgetHit::Titlebar
-                               : FWL_WidgetHit::Client;
-}
-
-void CFWL_Form::DrawWidget(CXFA_Graphics* pGraphics, const CFX_Matrix& matrix) {
-  if (!pGraphics)
-    return;
-  if (!m_pProperties->m_pThemeProvider)
-    return;
-
-  IFWL_ThemeProvider* pTheme = m_pProperties->m_pThemeProvider;
-  DrawBackground(pGraphics, pTheme);
-
-#if _FX_OS_ == _FX_OS_MACOSX_
-  return;
-#endif
-  CFWL_ThemeBackground param;
-  param.m_pWidget = this;
-  param.m_dwStates = CFWL_PartState_Normal;
-  param.m_pGraphics = pGraphics;
-  param.m_rtPart = m_rtRelative;
-  param.m_matrix.Concat(matrix);
-  if (m_pProperties->m_dwStyles & FWL_WGTSTYLE_Border) {
-    param.m_iPart = CFWL_Part::Border;
-    pTheme->DrawBackground(&param);
-  }
-}
-
-CFWL_Widget* CFWL_Form::DoModal() {
-  const CFWL_App* pApp = GetOwnerApp();
-  if (!pApp)
-    return nullptr;
-
-  CFWL_NoteDriver* pDriver = pApp->GetNoteDriver();
-  if (!pDriver)
-    return nullptr;
-
-  m_pNoteLoop = pdfium::MakeUnique<CFWL_NoteLoop>();
-  m_pNoteLoop->SetMainForm(this);
-
-  pDriver->PushNoteLoop(m_pNoteLoop.get());
-  RemoveStates(FWL_WGTSTATE_Invisible);
-  pDriver->Run();
-
-#if _FX_OS_ != _FX_OS_MACOSX_
-  pDriver->PopNoteLoop();
-#endif
-
-  m_pNoteLoop.reset();
-  return nullptr;
-}
-
-void CFWL_Form::EndDoModal() {
-  if (!m_pNoteLoop)
-    return;
-
-#if (_FX_OS_ == _FX_OS_MACOSX_)
-  m_pNoteLoop->EndModalLoop();
-  const CFWL_App* pApp = GetOwnerApp();
-  if (!pApp)
-    return;
-
-  CFWL_NoteDriver* pDriver =
-      static_cast<CFWL_NoteDriver*>(pApp->GetNoteDriver());
-  if (!pDriver)
-    return;
-
-  pDriver->PopNoteLoop();
-  SetStates(FWL_WGTSTATE_Invisible);
-#else
-  SetStates(FWL_WGTSTATE_Invisible);
-  m_pNoteLoop->EndModalLoop();
-#endif
-}
-
-void CFWL_Form::DrawBackground(CXFA_Graphics* pGraphics,
-                               IFWL_ThemeProvider* pTheme) {
-  CFWL_ThemeBackground param;
-  param.m_pWidget = this;
-  param.m_iPart = CFWL_Part::Background;
-  param.m_pGraphics = pGraphics;
-  param.m_rtPart = m_rtRelative;
-  param.m_rtPart.Deflate(m_fCYBorder, m_fCXBorder, m_fCYBorder, m_fCXBorder);
-  pTheme->DrawBackground(&param);
-}
-
-CFX_RectF CFWL_Form::GetEdgeRect() {
-  CFX_RectF rtEdge = m_rtRelative;
-  if (m_pProperties->m_dwStyles & FWL_WGTSTYLE_Border) {
-    float fCX = GetBorderSize(true);
-    float fCY = GetBorderSize(false);
-    rtEdge.Deflate(fCX, fCY, fCX, fCY);
-  }
-  return rtEdge;
-}
-
-void CFWL_Form::SetWorkAreaRect() {
-  m_rtRestore = m_pProperties->m_rtWidget;
-  CFWL_WidgetMgr* pWidgetMgr = GetOwnerApp()->GetWidgetMgr();
-  if (!pWidgetMgr)
-    return;
-  RepaintRect(m_rtRelative);
-}
-
-void CFWL_Form::Layout() {
-  m_rtRelative = GetRelativeRect();
-
-#if _FX_OS_ == _FX_OS_MACOSX_
-  IFWL_ThemeProvider* theme = GetAvailableTheme();
-  m_fCXBorder = theme ? theme->GetCXBorderSize() : 0.0f;
-  m_fCYBorder = theme ? theme->GetCYBorderSize() : 0.0f;
-#endif
-}
-
-void CFWL_Form::RegisterForm() {
-  const CFWL_App* pApp = GetOwnerApp();
-  if (!pApp)
-    return;
-
-  CFWL_NoteDriver* pDriver =
-      static_cast<CFWL_NoteDriver*>(pApp->GetNoteDriver());
-  if (!pDriver)
-    return;
-
-  pDriver->RegisterForm(this);
-}
-
-void CFWL_Form::UnRegisterForm() {
-  const CFWL_App* pApp = GetOwnerApp();
-  if (!pApp)
-    return;
-
-  CFWL_NoteDriver* pDriver =
-      static_cast<CFWL_NoteDriver*>(pApp->GetNoteDriver());
-  if (!pDriver)
-    return;
-
-  pDriver->UnRegisterForm(this);
-}
-
-void CFWL_Form::OnProcessMessage(CFWL_Message* pMessage) {
-#if _FX_OS_ == _FX_OS_MACOSX_
-  if (!pMessage)
-    return;
-
-  switch (pMessage->GetType()) {
-    case CFWL_Message::Type::Mouse: {
-      CFWL_MessageMouse* pMsg = static_cast<CFWL_MessageMouse*>(pMessage);
-      switch (pMsg->m_dwCmd) {
-        case FWL_MouseCommand::LeftButtonDown:
-          OnLButtonDown(pMsg);
-          break;
-        case FWL_MouseCommand::LeftButtonUp:
-          OnLButtonUp(pMsg);
-          break;
-        default:
-          break;
-      }
-      break;
-    }
-    default:
-      break;
-  }
-#endif  // _FX_OS_ == _FX_OS_MACOSX_
-}
-
-void CFWL_Form::OnDrawWidget(CXFA_Graphics* pGraphics,
-                             const CFX_Matrix& matrix) {
-  DrawWidget(pGraphics, matrix);
-}
-
-void CFWL_Form::OnLButtonDown(CFWL_MessageMouse* pMsg) {
-  SetGrab(true);
-}
-
-void CFWL_Form::OnLButtonUp(CFWL_MessageMouse* pMsg) {
-  SetGrab(false);
-}
diff --git a/xfa/fwl/cfwl_form.h b/xfa/fwl/cfwl_form.h
deleted file mode 100644
index cac1747..0000000
--- a/xfa/fwl/cfwl_form.h
+++ /dev/null
@@ -1,66 +0,0 @@
-// Copyright 2014 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_FWL_CFWL_FORM_H_
-#define XFA_FWL_CFWL_FORM_H_
-
-#include <memory>
-
-#include "core/fxcrt/fx_system.h"
-#include "xfa/fwl/cfwl_widget.h"
-#include "xfa/fwl/cfwl_widgetproperties.h"
-
-#define FWL_CLASS_Form L"FWL_FORM"
-#define FWL_CLASS_FormProxy L"FWL_FORMPROXY"
-
-class CFWL_MessageMouse;
-class CFWL_NoteLoop;
-class CFWL_Widget;
-class IFWL_ThemeProvider;
-
-class CFWL_Form : public CFWL_Widget {
- public:
-  CFWL_Form(const CFWL_App* app,
-            std::unique_ptr<CFWL_WidgetProperties> properties,
-            CFWL_Widget* pOuter);
-  ~CFWL_Form() override;
-
-  // CFWL_Widget
-  FWL_Type GetClassID() const override;
-  bool IsInstance(const WideStringView& wsClass) const override;
-  CFX_RectF GetClientRect() override;
-  void Update() override;
-  FWL_WidgetHit HitTest(const CFX_PointF& point) override;
-  void DrawWidget(CXFA_Graphics* pGraphics, const CFX_Matrix& matrix) override;
-  void OnProcessMessage(CFWL_Message* pMessage) override;
-  void OnDrawWidget(CXFA_Graphics* pGraphics,
-                    const CFX_Matrix& matrix) override;
-
-  CFWL_Widget* DoModal();
-  void EndDoModal();
-
-  CFWL_Widget* GetSubFocus() const { return m_pSubFocus; }
-  void SetSubFocus(CFWL_Widget* pWidget) { m_pSubFocus = pWidget; }
-
- private:
-  void DrawBackground(CXFA_Graphics* pGraphics, IFWL_ThemeProvider* pTheme);
-  CFX_RectF GetEdgeRect();
-  void SetWorkAreaRect();
-  void Layout();
-  void RegisterForm();
-  void UnRegisterForm();
-  void OnLButtonDown(CFWL_MessageMouse* pMsg);
-  void OnLButtonUp(CFWL_MessageMouse* pMsg);
-
-  CFX_RectF m_rtRestore;
-  CFX_RectF m_rtRelative;
-  std::unique_ptr<CFWL_NoteLoop> m_pNoteLoop;
-  CFWL_Widget* m_pSubFocus;
-  float m_fCXBorder;
-  float m_fCYBorder;
-};
-
-#endif  // XFA_FWL_CFWL_FORM_H_
diff --git a/xfa/fwl/cfwl_formproxy.cpp b/xfa/fwl/cfwl_formproxy.cpp
deleted file mode 100644
index d03c148..0000000
--- a/xfa/fwl/cfwl_formproxy.cpp
+++ /dev/null
@@ -1,40 +0,0 @@
-// Copyright 2014 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
-
-#include "xfa/fwl/cfwl_formproxy.h"
-
-#include <memory>
-#include <utility>
-
-#include "third_party/base/ptr_util.h"
-#include "xfa/fwl/cfwl_notedriver.h"
-
-CFWL_FormProxy::CFWL_FormProxy(
-    const CFWL_App* app,
-    std::unique_ptr<CFWL_WidgetProperties> properties,
-    CFWL_Widget* pOuter)
-    : CFWL_Form(app, std::move(properties), pOuter) {}
-
-CFWL_FormProxy::~CFWL_FormProxy() {}
-
-FWL_Type CFWL_FormProxy::GetClassID() const {
-  return FWL_Type::FormProxy;
-}
-
-bool CFWL_FormProxy::IsInstance(const WideStringView& wsClass) const {
-  if (wsClass == WideStringView(FWL_CLASS_FormProxy))
-    return true;
-  return CFWL_Form::IsInstance(wsClass);
-}
-
-void CFWL_FormProxy::Update() {}
-
-void CFWL_FormProxy::DrawWidget(CXFA_Graphics* pGraphics,
-                                const CFX_Matrix& matrix) {}
-
-void CFWL_FormProxy::OnProcessMessage(CFWL_Message* pMessage) {
-  m_pOuter->GetDelegate()->OnProcessMessage(pMessage);
-}
diff --git a/xfa/fwl/cfwl_formproxy.h b/xfa/fwl/cfwl_formproxy.h
deleted file mode 100644
index 498ff42..0000000
--- a/xfa/fwl/cfwl_formproxy.h
+++ /dev/null
@@ -1,31 +0,0 @@
-// Copyright 2014 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_FWL_CFWL_FORMPROXY_H_
-#define XFA_FWL_CFWL_FORMPROXY_H_
-
-#include <memory>
-
-#include "xfa/fwl/cfwl_form.h"
-
-class CFWL_WidgetProperties;
-
-class CFWL_FormProxy : public CFWL_Form {
- public:
-  CFWL_FormProxy(const CFWL_App* app,
-                 std::unique_ptr<CFWL_WidgetProperties> properties,
-                 CFWL_Widget* pOuter);
-  ~CFWL_FormProxy() override;
-
-  // CFWL_Widget
-  FWL_Type GetClassID() const override;
-  bool IsInstance(const WideStringView& wsClass) const override;
-  void Update() override;
-  void DrawWidget(CXFA_Graphics* pGraphics, const CFX_Matrix& matrix) override;
-  void OnProcessMessage(CFWL_Message* pMessage) override;
-};
-
-#endif  // XFA_FWL_CFWL_FORMPROXY_H_
diff --git a/xfa/fwl/cfwl_listbox.cpp b/xfa/fwl/cfwl_listbox.cpp
index 0ddb65b..b2b0f2e 100644
--- a/xfa/fwl/cfwl_listbox.cpp
+++ b/xfa/fwl/cfwl_listbox.cpp
@@ -20,6 +20,7 @@
 #include "xfa/fwl/cfwl_themebackground.h"
 #include "xfa/fwl/cfwl_themepart.h"
 #include "xfa/fwl/cfwl_themetext.h"
+#include "xfa/fwl/fwl_widgetdef.h"
 #include "xfa/fwl/ifwl_themeprovider.h"
 
 namespace {
@@ -31,16 +32,7 @@
 CFWL_ListBox::CFWL_ListBox(const CFWL_App* app,
                            std::unique_ptr<CFWL_WidgetProperties> properties,
                            CFWL_Widget* pOuter)
-    : CFWL_Widget(app, std::move(properties), pOuter),
-      m_iTTOAligns(FDE_TextAlignment::kTopLeft),
-      m_hAnchor(nullptr),
-      m_fScorllBarWidth(0),
-      m_bLButtonDown(false),
-      m_pScrollBarTP(nullptr) {
-  m_rtClient.Reset();
-  m_rtConent.Reset();
-  m_rtStatic.Reset();
-}
+    : CFWL_Widget(app, std::move(properties), pOuter) {}
 
 CFWL_ListBox::~CFWL_ListBox() {}
 
@@ -69,7 +61,7 @@
       break;
     }
   }
-  m_dwTTOStyles.single_line_ = true;
+  m_TTOStyles.single_line_ = true;
   m_fScorllBarWidth = GetScrollWidth();
   CalcSize(false);
 }
@@ -94,10 +86,11 @@
                               const CFX_Matrix& matrix) {
   if (!pGraphics)
     return;
-  if (!m_pProperties->m_pThemeProvider)
+
+  IFWL_ThemeProvider* pTheme = m_pProperties->m_pThemeProvider.Get();
+  if (!pTheme)
     return;
 
-  IFWL_ThemeProvider* pTheme = m_pProperties->m_pThemeProvider;
   pGraphics->SaveGraphState();
   if (HasBorder())
     DrawBorder(pGraphics, CFWL_Part::Border, pTheme, matrix);
@@ -177,17 +170,17 @@
                                          uint32_t dwKeyCode) {
   CFWL_ListItem* hRet = nullptr;
   switch (dwKeyCode) {
-    case FWL_VKEY_Up:
-    case FWL_VKEY_Down:
-    case FWL_VKEY_Home:
-    case FWL_VKEY_End: {
-      const bool bUp = dwKeyCode == FWL_VKEY_Up;
-      const bool bDown = dwKeyCode == FWL_VKEY_Down;
-      const bool bHome = dwKeyCode == FWL_VKEY_Home;
+    case XFA_FWL_VKEY_Up:
+    case XFA_FWL_VKEY_Down:
+    case XFA_FWL_VKEY_Home:
+    case XFA_FWL_VKEY_End: {
+      const bool bUp = dwKeyCode == XFA_FWL_VKEY_Up;
+      const bool bDown = dwKeyCode == XFA_FWL_VKEY_Down;
+      const bool bHome = dwKeyCode == XFA_FWL_VKEY_Home;
       int32_t iDstItem = -1;
       if (bUp || bDown) {
         int32_t index = GetItemIndex(this, pItem);
-        iDstItem = dwKeyCode == FWL_VKEY_Up ? index - 1 : index + 1;
+        iDstItem = dwKeyCode == XFA_FWL_VKEY_Up ? index - 1 : index + 1;
       } else if (bHome) {
         iDstItem = 0;
       } else {
@@ -365,11 +358,11 @@
   param.m_matrix.Concat(*pMatrix);
   param.m_rtPart = m_rtClient;
   if (IsShowScrollBar(false) && IsShowScrollBar(true))
-    param.m_pData = &m_rtStatic;
+    param.m_pRtData = &m_rtStatic;
   if (!IsEnabled())
     param.m_dwStates = CFWL_PartState_Disabled;
 
-  pTheme->DrawBackground(&param);
+  pTheme->DrawBackground(param);
 }
 
 void CFWL_ListBox::DrawItems(CXFA_Graphics* pGraphics,
@@ -432,14 +425,14 @@
   bg_param.m_rtPart = rtItem;
   bg_param.m_bMaximize = true;
   CFX_RectF rtFocus(rtItem);
-  bg_param.m_pData = &rtFocus;
+  bg_param.m_pRtData = &rtFocus;
   if (m_pVertScrollBar && !m_pHorzScrollBar &&
       (dwPartStates & CFWL_PartState_Focused)) {
     bg_param.m_rtPart.left += 1;
     bg_param.m_rtPart.width -= (m_fScorllBarWidth + 1);
     rtFocus.Deflate(0.5, 0.5, 1 + m_fScorllBarWidth, 1);
   }
-  pTheme->DrawBackground(&bg_param);
+  pTheme->DrawBackground(bg_param);
 
   if (!pItem)
     return;
@@ -458,11 +451,11 @@
   textParam.m_pGraphics = pGraphics;
   textParam.m_matrix.Concat(*pMatrix);
   textParam.m_rtPart = rtText;
-  textParam.m_wsText = wsText;
-  textParam.m_dwTTOStyles = m_dwTTOStyles;
+  textParam.m_wsText = std::move(wsText);
+  textParam.m_dwTTOStyles = m_TTOStyles;
   textParam.m_iTTOAlign = m_iTTOAligns;
   textParam.m_bMaximize = true;
-  pTheme->DrawText(&textParam);
+  pTheme->DrawText(textParam);
 }
 
 CFX_SizeF CFWL_ListBox::CalcSize(bool bAutoSize) {
@@ -476,7 +469,7 @@
     CFWL_ThemePart part;
     part.m_pWidget = this;
     IFWL_ThemeProvider* theme = GetAvailableTheme();
-    CFX_RectF pUIMargin = theme ? theme->GetUIMargin(&part) : CFX_RectF();
+    CFX_RectF pUIMargin = theme ? theme->GetUIMargin(part) : CFX_RectF();
     m_rtConent.Deflate(pUIMargin.left, pUIMargin.top, pUIMargin.width,
                        pUIMargin.height);
   }
@@ -599,8 +592,8 @@
     if (!pItem)
       continue;
 
-    CFX_SizeF sz =
-        CalcTextSize(pItem->GetText(), m_pProperties->m_pThemeProvider, false);
+    CFX_SizeF sz = CalcTextSize(pItem->GetText(),
+                                m_pProperties->m_pThemeProvider.Get(), false);
     fRet = std::max(fRet, sz.width);
   }
   return fRet;
@@ -615,7 +608,7 @@
   IFWL_ThemeProvider* theme = GetAvailableTheme();
   CFWL_ThemePart part;
   part.m_pWidget = this;
-  return (theme ? theme->GetFontSize(&part) : 20.0f) + 2 * kItemTextMargin;
+  return (theme ? theme->GetFontSize(part) : 20.0f) + 2 * kItemTextMargin;
 }
 
 void CFWL_ListBox::InitVerticalScrollBar() {
@@ -647,8 +640,9 @@
 bool CFWL_ListBox::IsShowScrollBar(bool bVert) {
   CFWL_ScrollBar* pScrollbar =
       bVert ? m_pVertScrollBar.get() : m_pHorzScrollBar.get();
-  if (!pScrollbar || (pScrollbar->GetStates() & FWL_WGTSTATE_Invisible))
+  if (!pScrollbar || !pScrollbar->IsVisible())
     return false;
+
   return !(m_pProperties->m_dwStyleExes &
            FWL_STYLEEXT_LTB_ShowScrollBarFocus) ||
          (m_pProperties->m_dwStates & FWL_WGTSTATE_Focused);
@@ -693,7 +687,9 @@
     default:
       break;
   }
-  CFWL_Widget::OnProcessMessage(pMessage);
+  // Dst target could be |this|, continue only if not destroyed by above.
+  if (pMessage->GetDstTarget())
+    CFWL_Widget::OnProcessMessage(pMessage);
 }
 
 void CFWL_ListBox::OnProcessEvent(CFWL_Event* pEvent) {
@@ -702,7 +698,7 @@
   if (pEvent->GetType() != CFWL_Event::Type::Scroll)
     return;
 
-  CFWL_Widget* pSrcTarget = pEvent->m_pSrcTarget;
+  CFWL_Widget* pSrcTarget = pEvent->GetSrcTarget();
   if ((pSrcTarget == m_pVertScrollBar.get() && m_pVertScrollBar) ||
       (pSrcTarget == m_pHorzScrollBar.get() && m_pHorzScrollBar)) {
     CFWL_EventScroll* pScrollEvent = static_cast<CFWL_EventScroll*>(pEvent);
@@ -741,8 +737,6 @@
 
 void CFWL_ListBox::OnLButtonDown(CFWL_MessageMouse* pMsg) {
   m_bLButtonDown = true;
-  if ((m_pProperties->m_dwStates & FWL_WGTSTATE_Focused) == 0)
-    SetFocus(true);
 
   CFWL_ListItem* pItem = GetItemAtPoint(pMsg->m_pos);
   if (!pItem)
@@ -788,11 +782,11 @@
 void CFWL_ListBox::OnKeyDown(CFWL_MessageKey* pMsg) {
   uint32_t dwKeyCode = pMsg->m_dwKeyCode;
   switch (dwKeyCode) {
-    case FWL_VKEY_Tab:
-    case FWL_VKEY_Up:
-    case FWL_VKEY_Down:
-    case FWL_VKEY_Home:
-    case FWL_VKEY_End: {
+    case XFA_FWL_VKEY_Tab:
+    case XFA_FWL_VKEY_Up:
+    case XFA_FWL_VKEY_Down:
+    case XFA_FWL_VKEY_Home:
+    case XFA_FWL_VKEY_End: {
       CFWL_ListItem* pItem = GetFocusedItem();
       pItem = GetListItem(pItem, dwKeyCode);
       bool bShift = !!(pMsg->m_dwFlags & FWL_KEYFLAG_Shift);
@@ -907,9 +901,8 @@
   return it != m_ItemArray.end() ? it - m_ItemArray.begin() : -1;
 }
 
-CFWL_ListItem* CFWL_ListBox::AddString(const WideStringView& wsAdd) {
-  m_ItemArray.emplace_back(
-      pdfium::MakeUnique<CFWL_ListItem>(WideString(wsAdd)));
+CFWL_ListItem* CFWL_ListBox::AddString(const WideString& wsAdd) {
+  m_ItemArray.emplace_back(pdfium::MakeUnique<CFWL_ListItem>(wsAdd));
   return m_ItemArray.back().get();
 }
 
diff --git a/xfa/fwl/cfwl_listbox.h b/xfa/fwl/cfwl_listbox.h
index 4a7818c..178e49a 100644
--- a/xfa/fwl/cfwl_listbox.h
+++ b/xfa/fwl/cfwl_listbox.h
@@ -53,7 +53,7 @@
   CFWL_ListItem* GetItem(const CFWL_Widget* pWidget, int32_t nIndex) const;
   int32_t GetItemIndex(CFWL_Widget* pWidget, CFWL_ListItem* pItem);
 
-  CFWL_ListItem* AddString(const WideStringView& wsAdd);
+  CFWL_ListItem* AddString(const WideString& wsAdd);
   void RemoveAt(int32_t iIndex);
   void DeleteString(CFWL_ListItem* pItem);
   void DeleteAll();
@@ -122,13 +122,13 @@
   CFX_RectF m_rtConent;
   std::unique_ptr<CFWL_ScrollBar> m_pHorzScrollBar;
   std::unique_ptr<CFWL_ScrollBar> m_pVertScrollBar;
-  FDE_TextStyle m_dwTTOStyles;
-  FDE_TextAlignment m_iTTOAligns;
-  CFWL_ListItem* m_hAnchor;
-  float m_fItemHeight;
-  float m_fScorllBarWidth;
-  bool m_bLButtonDown;
-  IFWL_ThemeProvider* m_pScrollBarTP;
+  FDE_TextStyle m_TTOStyles;
+  FDE_TextAlignment m_iTTOAligns = FDE_TextAlignment::kTopLeft;
+  bool m_bLButtonDown = false;
+  float m_fItemHeight = 0.0f;
+  float m_fScorllBarWidth = 0.0f;
+  CFWL_ListItem* m_hAnchor = nullptr;
+  IFWL_ThemeProvider* m_pScrollBarTP = nullptr;
   std::vector<std::unique_ptr<CFWL_ListItem>> m_ItemArray;
 };
 
diff --git a/xfa/fwl/cfwl_listitem.cpp b/xfa/fwl/cfwl_listitem.cpp
index f8a7b75..edf1be3 100644
--- a/xfa/fwl/cfwl_listitem.cpp
+++ b/xfa/fwl/cfwl_listitem.cpp
@@ -6,9 +6,6 @@
 
 #include "xfa/fwl/cfwl_listitem.h"
 
-CFWL_ListItem::CFWL_ListItem(const WideString& text)
-    : m_dwStates(0), m_wsText(text) {
-  m_rtItem.Reset();
-}
+CFWL_ListItem::CFWL_ListItem(const WideString& text) : m_wsText(text) {}
 
 CFWL_ListItem::~CFWL_ListItem() {}
diff --git a/xfa/fwl/cfwl_listitem.h b/xfa/fwl/cfwl_listitem.h
index 62c3a98..a6afb22 100644
--- a/xfa/fwl/cfwl_listitem.h
+++ b/xfa/fwl/cfwl_listitem.h
@@ -24,8 +24,8 @@
   WideString GetText() const { return m_wsText; }
 
  private:
+  uint32_t m_dwStates = 0;
   CFX_RectF m_rtItem;
-  uint32_t m_dwStates;
   WideString m_wsText;
 };
 
diff --git a/xfa/fwl/cfwl_message.cpp b/xfa/fwl/cfwl_message.cpp
index 258fe62..f330a08 100644
--- a/xfa/fwl/cfwl_message.cpp
+++ b/xfa/fwl/cfwl_message.cpp
@@ -6,19 +6,9 @@
 
 #include "xfa/fwl/cfwl_message.h"
 
-CFWL_Message::CFWL_Message(CFWL_Message::Type type)
-    : CFWL_Message(type, nullptr, nullptr) {}
-
-CFWL_Message::CFWL_Message(Type type, CFWL_Widget* pSrcTarget)
-    : CFWL_Message(type, pSrcTarget, nullptr) {}
-
 CFWL_Message::CFWL_Message(Type type,
                            CFWL_Widget* pSrcTarget,
                            CFWL_Widget* pDstTarget)
-    : m_pSrcTarget(pSrcTarget), m_pDstTarget(pDstTarget), m_type(type) {}
+    : m_type(type), m_pSrcTarget(pSrcTarget), m_pDstTarget(pDstTarget) {}
 
-CFWL_Message::~CFWL_Message() {}
-
-std::unique_ptr<CFWL_Message> CFWL_Message::Clone() {
-  return nullptr;
-}
+CFWL_Message::~CFWL_Message() = default;
diff --git a/xfa/fwl/cfwl_message.h b/xfa/fwl/cfwl_message.h
index 99cf01b..69f7bf5 100644
--- a/xfa/fwl/cfwl_message.h
+++ b/xfa/fwl/cfwl_message.h
@@ -11,26 +11,30 @@
 
 #include "core/fxcrt/fx_string.h"
 #include "core/fxcrt/fx_system.h"
-
-class CFWL_Widget;
+#include "core/fxcrt/observed_ptr.h"
+#include "xfa/fwl/cfwl_widget.h"
 
 class CFWL_Message {
  public:
   enum class Type { Key, KillFocus, Mouse, MouseWheel, SetFocus };
 
-  explicit CFWL_Message(Type type);
-  CFWL_Message(Type type, CFWL_Widget* pSrcTarget);
-  CFWL_Message(Type type, CFWL_Widget* pSrcTarget, CFWL_Widget* pDstTarget);
   virtual ~CFWL_Message();
 
-  virtual std::unique_ptr<CFWL_Message> Clone();
   Type GetType() const { return m_type; }
+  CFWL_Widget* GetSrcTarget() const { return m_pSrcTarget.Get(); }
+  CFWL_Widget* GetDstTarget() const { return m_pDstTarget.Get(); }
+  void SetSrcTarget(CFWL_Widget* pWidget) { m_pSrcTarget.Reset(pWidget); }
+  void SetDstTarget(CFWL_Widget* pWidget) { m_pDstTarget.Reset(pWidget); }
 
-  CFWL_Widget* m_pSrcTarget;
-  CFWL_Widget* m_pDstTarget;
+ protected:
+  CFWL_Message(Type type, CFWL_Widget* pSrcTarget, CFWL_Widget* pDstTarget);
+  CFWL_Message(const CFWL_Message& that) = delete;
+  CFWL_Message& operator=(const CFWL_Message& that) = delete;
 
  private:
-  Type m_type;
+  const Type m_type;
+  ObservedPtr<CFWL_Widget> m_pSrcTarget;
+  ObservedPtr<CFWL_Widget> m_pDstTarget;
 };
 
 #endif  // XFA_FWL_CFWL_MESSAGE_H_
diff --git a/xfa/fwl/cfwl_messagekey.cpp b/xfa/fwl/cfwl_messagekey.cpp
index 38d4ea0..9abb0c1 100644
--- a/xfa/fwl/cfwl_messagekey.cpp
+++ b/xfa/fwl/cfwl_messagekey.cpp
@@ -10,12 +10,13 @@
 
 #include "third_party/base/ptr_util.h"
 
-CFWL_MessageKey::CFWL_MessageKey(CFWL_Widget* pSrcTarget,
-                                 CFWL_Widget* pDstTarget)
-    : CFWL_Message(CFWL_Message::Type::Key, pSrcTarget, pDstTarget) {}
+CFWL_MessageKey::CFWL_MessageKey(CFWL_Widget* pDstTarget,
+                                 FWL_KeyCommand cmd,
+                                 uint32_t flags,
+                                 uint32_t keycode)
+    : CFWL_Message(CFWL_Message::Type::Key, nullptr, pDstTarget),
+      m_dwCmd(cmd),
+      m_dwFlags(flags),
+      m_dwKeyCode(keycode) {}
 
-CFWL_MessageKey::~CFWL_MessageKey() {}
-
-std::unique_ptr<CFWL_Message> CFWL_MessageKey::Clone() {
-  return pdfium::MakeUnique<CFWL_MessageKey>(*this);
-}
+CFWL_MessageKey::~CFWL_MessageKey() = default;
diff --git a/xfa/fwl/cfwl_messagekey.h b/xfa/fwl/cfwl_messagekey.h
index bf430d3..b122647 100644
--- a/xfa/fwl/cfwl_messagekey.h
+++ b/xfa/fwl/cfwl_messagekey.h
@@ -13,17 +13,17 @@
 
 enum class FWL_KeyCommand { KeyDown, KeyUp, Char };
 
-class CFWL_MessageKey : public CFWL_Message {
+class CFWL_MessageKey final : public CFWL_Message {
  public:
-  CFWL_MessageKey(CFWL_Widget* pSrcTarget, CFWL_Widget* pDstTarget);
+  CFWL_MessageKey(CFWL_Widget* pDstTarget,
+                  FWL_KeyCommand cmd,
+                  uint32_t flags,
+                  uint32_t keycode);
   ~CFWL_MessageKey() override;
 
-  // CFWL_Message
-  std::unique_ptr<CFWL_Message> Clone() override;
-
-  uint32_t m_dwKeyCode;
-  uint32_t m_dwFlags;
-  FWL_KeyCommand m_dwCmd;
+  const FWL_KeyCommand m_dwCmd;
+  const uint32_t m_dwFlags;
+  const uint32_t m_dwKeyCode;
 };
 
 #endif  // XFA_FWL_CFWL_MESSAGEKEY_H_
diff --git a/xfa/fwl/cfwl_messagekillfocus.cpp b/xfa/fwl/cfwl_messagekillfocus.cpp
index 55247d1..15fe562 100644
--- a/xfa/fwl/cfwl_messagekillfocus.cpp
+++ b/xfa/fwl/cfwl_messagekillfocus.cpp
@@ -17,8 +17,4 @@
                                              CFWL_Widget* pDstTarget)
     : CFWL_Message(CFWL_Message::Type::KillFocus, pSrcTarget, pDstTarget) {}
 
-CFWL_MessageKillFocus::~CFWL_MessageKillFocus() {}
-
-std::unique_ptr<CFWL_Message> CFWL_MessageKillFocus::Clone() {
-  return pdfium::MakeUnique<CFWL_MessageKillFocus>(*this);
-}
+CFWL_MessageKillFocus::~CFWL_MessageKillFocus() = default;
diff --git a/xfa/fwl/cfwl_messagekillfocus.h b/xfa/fwl/cfwl_messagekillfocus.h
index d6ca799..18e64f9 100644
--- a/xfa/fwl/cfwl_messagekillfocus.h
+++ b/xfa/fwl/cfwl_messagekillfocus.h
@@ -9,18 +9,21 @@
 
 #include <memory>
 
+#include "core/fxcrt/unowned_ptr.h"
 #include "xfa/fwl/cfwl_message.h"
 
-class CFWL_MessageKillFocus : public CFWL_Message {
+class CFWL_MessageKillFocus final : public CFWL_Message {
  public:
   explicit CFWL_MessageKillFocus(CFWL_Widget* pSrcTarget);
   CFWL_MessageKillFocus(CFWL_Widget* pSrcTarget, CFWL_Widget* pDstTarget);
   ~CFWL_MessageKillFocus() override;
 
-  // CFWL_Message
-  std::unique_ptr<CFWL_Message> Clone() override;
+  bool IsFocusedOnWidget(const CFWL_Widget* pWidget) const {
+    return pWidget == m_pSetFocus;
+  }
 
-  CFWL_Widget* m_pSetFocus;
+ private:
+  UnownedPtr<CFWL_Widget> m_pSetFocus;
 };
 
 #endif  // XFA_FWL_CFWL_MESSAGEKILLFOCUS_H_
diff --git a/xfa/fwl/cfwl_messagemouse.cpp b/xfa/fwl/cfwl_messagemouse.cpp
index 1d56b0f..395c9e6 100644
--- a/xfa/fwl/cfwl_messagemouse.cpp
+++ b/xfa/fwl/cfwl_messagemouse.cpp
@@ -10,14 +10,18 @@
 
 #include "third_party/base/ptr_util.h"
 
-CFWL_MessageMouse::CFWL_MessageMouse(CFWL_Widget* pSrcTarget,
-                                     CFWL_Widget* pDstTarget)
-    : CFWL_Message(CFWL_Message::Type::Mouse, pSrcTarget, pDstTarget) {}
+CFWL_MessageMouse::CFWL_MessageMouse(CFWL_Widget* pDstTarget,
+                                     FWL_MouseCommand cmd)
+    : CFWL_Message(CFWL_Message::Type::Mouse, nullptr, pDstTarget),
+      m_dwCmd(cmd) {}
 
-CFWL_MessageMouse::CFWL_MessageMouse(const CFWL_MessageMouse& other) = default;
+CFWL_MessageMouse::CFWL_MessageMouse(CFWL_Widget* pDstTarget,
+                                     FWL_MouseCommand cmd,
+                                     uint32_t flags,
+                                     CFX_PointF pos)
+    : CFWL_Message(CFWL_Message::Type::Mouse, nullptr, pDstTarget),
+      m_dwCmd(cmd),
+      m_dwFlags(flags),
+      m_pos(pos) {}
 
-CFWL_MessageMouse::~CFWL_MessageMouse() {}
-
-std::unique_ptr<CFWL_Message> CFWL_MessageMouse::Clone() {
-  return pdfium::MakeUnique<CFWL_MessageMouse>(*this);
-}
+CFWL_MessageMouse::~CFWL_MessageMouse() = default;
diff --git a/xfa/fwl/cfwl_messagemouse.h b/xfa/fwl/cfwl_messagemouse.h
index a2b0d39..10c298a 100644
--- a/xfa/fwl/cfwl_messagemouse.h
+++ b/xfa/fwl/cfwl_messagemouse.h
@@ -25,18 +25,18 @@
   Hover
 };
 
-class CFWL_MessageMouse : public CFWL_Message {
+class CFWL_MessageMouse final : public CFWL_Message {
  public:
-  CFWL_MessageMouse(CFWL_Widget* pSrcTarget, CFWL_Widget* pDstTarget);
-  CFWL_MessageMouse(const CFWL_MessageMouse& other);
+  CFWL_MessageMouse(CFWL_Widget* pDstTarget, FWL_MouseCommand cmd);
+  CFWL_MessageMouse(CFWL_Widget* pDstTarget,
+                    FWL_MouseCommand cmd,
+                    uint32_t flags,
+                    CFX_PointF pos);
   ~CFWL_MessageMouse() override;
 
-  // CFWL_Message
-  std::unique_ptr<CFWL_Message> Clone() override;
-
+  const FWL_MouseCommand m_dwCmd;
+  uint32_t m_dwFlags = 0;
   CFX_PointF m_pos;
-  uint32_t m_dwFlags;
-  FWL_MouseCommand m_dwCmd;
 };
 
 #endif  // XFA_FWL_CFWL_MESSAGEMOUSE_H_
diff --git a/xfa/fwl/cfwl_messagemousewheel.cpp b/xfa/fwl/cfwl_messagemousewheel.cpp
index 8996f65..3331179 100644
--- a/xfa/fwl/cfwl_messagemousewheel.cpp
+++ b/xfa/fwl/cfwl_messagemousewheel.cpp
@@ -10,15 +10,13 @@
 
 #include "third_party/base/ptr_util.h"
 
-CFWL_MessageMouseWheel::CFWL_MessageMouseWheel(CFWL_Widget* pSrcTarget,
-                                               CFWL_Widget* pDstTarget)
-    : CFWL_Message(CFWL_Message::Type::MouseWheel, pSrcTarget, pDstTarget) {}
+CFWL_MessageMouseWheel::CFWL_MessageMouseWheel(CFWL_Widget* pDstTarget,
+                                               uint32_t flags,
+                                               CFX_PointF pos,
+                                               CFX_PointF delta)
+    : CFWL_Message(CFWL_Message::Type::MouseWheel, nullptr, pDstTarget),
+      m_dwFlags(flags),
+      m_pos(pos),
+      m_delta(delta) {}
 
-CFWL_MessageMouseWheel::CFWL_MessageMouseWheel(const CFWL_MessageMouseWheel&) =
-    default;
-
-CFWL_MessageMouseWheel::~CFWL_MessageMouseWheel() {}
-
-std::unique_ptr<CFWL_Message> CFWL_MessageMouseWheel::Clone() {
-  return pdfium::MakeUnique<CFWL_MessageMouseWheel>(*this);
-}
+CFWL_MessageMouseWheel::~CFWL_MessageMouseWheel() = default;
diff --git a/xfa/fwl/cfwl_messagemousewheel.h b/xfa/fwl/cfwl_messagemousewheel.h
index f969b9a..9908951 100644
--- a/xfa/fwl/cfwl_messagemousewheel.h
+++ b/xfa/fwl/cfwl_messagemousewheel.h
@@ -12,18 +12,17 @@
 #include "core/fxcrt/fx_coordinates.h"
 #include "xfa/fwl/cfwl_message.h"
 
-class CFWL_MessageMouseWheel : public CFWL_Message {
+class CFWL_MessageMouseWheel final : public CFWL_Message {
  public:
-  CFWL_MessageMouseWheel(CFWL_Widget* pSrcTarget, CFWL_Widget* pDstTarget);
-  CFWL_MessageMouseWheel(const CFWL_MessageMouseWheel&);
+  CFWL_MessageMouseWheel(CFWL_Widget* pDstTarget,
+                         uint32_t flags,
+                         CFX_PointF pos,
+                         CFX_PointF delta);
   ~CFWL_MessageMouseWheel() override;
 
-  // CFWL_Message
-  std::unique_ptr<CFWL_Message> Clone() override;
-
+  const uint32_t m_dwFlags;
   CFX_PointF m_pos;
   CFX_PointF m_delta;
-  uint32_t m_dwFlags;
 };
 
 #endif  // XFA_FWL_CFWL_MESSAGEMOUSEWHEEL_H_
diff --git a/xfa/fwl/cfwl_messagesetfocus.cpp b/xfa/fwl/cfwl_messagesetfocus.cpp
index f7653c9..ec0c27a 100644
--- a/xfa/fwl/cfwl_messagesetfocus.cpp
+++ b/xfa/fwl/cfwl_messagesetfocus.cpp
@@ -14,8 +14,5 @@
                                            CFWL_Widget* pDstTarget)
     : CFWL_Message(CFWL_Message::Type::SetFocus, pSrcTarget, pDstTarget) {}
 
-CFWL_MessageSetFocus::~CFWL_MessageSetFocus() {}
+CFWL_MessageSetFocus::~CFWL_MessageSetFocus() = default;
 
-std::unique_ptr<CFWL_Message> CFWL_MessageSetFocus::Clone() {
-  return pdfium::MakeUnique<CFWL_MessageSetFocus>(*this);
-}
diff --git a/xfa/fwl/cfwl_messagesetfocus.h b/xfa/fwl/cfwl_messagesetfocus.h
index 05616fb..67e0035 100644
--- a/xfa/fwl/cfwl_messagesetfocus.h
+++ b/xfa/fwl/cfwl_messagesetfocus.h
@@ -11,13 +11,10 @@
 
 #include "xfa/fwl/cfwl_message.h"
 
-class CFWL_MessageSetFocus : public CFWL_Message {
+class CFWL_MessageSetFocus final : public CFWL_Message {
  public:
   CFWL_MessageSetFocus(CFWL_Widget* pSrcTarget, CFWL_Widget* pDstTarget);
   ~CFWL_MessageSetFocus() override;
-
-  // CFWL_Message
-  std::unique_ptr<CFWL_Message> Clone() override;
 };
 
 #endif  // XFA_FWL_CFWL_MESSAGESETFOCUS_H_
diff --git a/xfa/fwl/cfwl_monthcalendar.cpp b/xfa/fwl/cfwl_monthcalendar.cpp
index 08ed83f..76d9156 100644
--- a/xfa/fwl/cfwl_monthcalendar.cpp
+++ b/xfa/fwl/cfwl_monthcalendar.cpp
@@ -14,7 +14,6 @@
 #include "third_party/base/stl_util.h"
 #include "xfa/fde/cfde_textout.h"
 #include "xfa/fwl/cfwl_datetimepicker.h"
-#include "xfa/fwl/cfwl_formproxy.h"
 #include "xfa/fwl/cfwl_messagemouse.h"
 #include "xfa/fwl/cfwl_notedriver.h"
 #include "xfa/fwl/cfwl_themebackground.h"
@@ -22,7 +21,6 @@
 #include "xfa/fwl/ifwl_themeprovider.h"
 
 #define MONTHCAL_HSEP_HEIGHT 1
-#define MONTHCAL_VSEP_WIDTH 1
 #define MONTHCAL_HMARGIN 3
 #define MONTHCAL_VMARGIN 2
 #define MONTHCAL_ROWS 9
@@ -32,54 +30,58 @@
 
 namespace {
 
-WideString GetCapacityForDay(IFWL_ThemeProvider* pTheme,
-                             CFWL_ThemePart& params,
-                             uint32_t day) {
-  ASSERT(day < 7);
-
-  if (day == 0)
-    return L"Sun";
-  if (day == 1)
-    return L"Mon";
-  if (day == 2)
-    return L"Tue";
-  if (day == 3)
-    return L"Wed";
-  if (day == 4)
-    return L"Thu";
-  if (day == 5)
-    return L"Fri";
-  return L"Sat";
+WideString GetAbbreviatedDayOfWeek(int day) {
+  switch (day) {
+    case 0:
+      return L"Sun";
+    case 1:
+      return L"Mon";
+    case 2:
+      return L"Tue";
+    case 3:
+      return L"Wed";
+    case 4:
+      return L"Thu";
+    case 5:
+      return L"Fri";
+    case 6:
+      return L"Sat";
+    default:
+      NOTREACHED();
+      return L"";
+  }
 }
 
-WideString GetCapacityForMonth(IFWL_ThemeProvider* pTheme,
-                               CFWL_ThemePart& params,
-                               uint32_t month) {
-  ASSERT(month < 12);
-
-  if (month == 0)
-    return L"January";
-  if (month == 1)
-    return L"February";
-  if (month == 2)
-    return L"March";
-  if (month == 3)
-    return L"April";
-  if (month == 4)
-    return L"May";
-  if (month == 5)
-    return L"June";
-  if (month == 6)
-    return L"July";
-  if (month == 7)
-    return L"August";
-  if (month == 8)
-    return L"September";
-  if (month == 9)
-    return L"October";
-  if (month == 10)
-    return L"November";
-  return L"December";
+WideString GetMonth(int month) {
+  switch (month) {
+    case 0:
+      return L"January";
+    case 1:
+      return L"February";
+    case 2:
+      return L"March";
+    case 3:
+      return L"April";
+    case 4:
+      return L"May";
+    case 5:
+      return L"June";
+    case 6:
+      return L"July";
+    case 7:
+      return L"August";
+    case 8:
+      return L"September";
+    case 9:
+      return L"October";
+    case 10:
+      return L"November";
+    case 11:
+      return L"December";
+    default:
+      NOTREACHED();
+      return L"";
+  }
 }
 
 }  // namespace
@@ -88,35 +90,9 @@
     const CFWL_App* app,
     std::unique_ptr<CFWL_WidgetProperties> properties,
     CFWL_Widget* pOuter)
-    : CFWL_Widget(app, std::move(properties), pOuter),
-      m_bInitialized(false),
-      m_iCurYear(2011),
-      m_iCurMonth(1),
-      m_iYear(2011),
-      m_iMonth(1),
-      m_iDay(1),
-      m_iHovered(-1),
-      m_iLBtnPartStates(CFWL_PartState_Normal),
-      m_iRBtnPartStates(CFWL_PartState_Normal),
-      m_bFlag(false) {
-  m_rtHead.Reset();
-  m_rtWeek.Reset();
-  m_rtLBtn.Reset();
-  m_rtRBtn.Reset();
-  m_rtDates.Reset();
-  m_rtHSep.Reset();
-  m_rtHeadText.Reset();
-  m_rtToday.Reset();
-  m_rtTodayFlag.Reset();
-  m_rtClient.Reset();
-  m_rtWeekNum.Reset();
-  m_rtWeekNumSep.Reset();
-}
+    : CFWL_Widget(app, std::move(properties), pOuter) {}
 
-CFWL_MonthCalendar::~CFWL_MonthCalendar() {
-  ClearDateItem();
-  m_arrSelDays.clear();
-}
+CFWL_MonthCalendar::~CFWL_MonthCalendar() = default;
 
 FWL_Type CFWL_MonthCalendar::GetClassID() const {
   return FWL_Type::MonthCalendar;
@@ -150,10 +126,11 @@
                                     const CFX_Matrix& matrix) {
   if (!pGraphics)
     return;
+
   if (!m_pProperties->m_pThemeProvider)
     m_pProperties->m_pThemeProvider = GetAvailableTheme();
 
-  IFWL_ThemeProvider* pTheme = m_pProperties->m_pThemeProvider;
+  IFWL_ThemeProvider* pTheme = m_pProperties->m_pThemeProvider.Get();
   if (HasBorder())
     DrawBorder(pGraphics, CFWL_Part::Border, pTheme, matrix);
 
@@ -161,7 +138,7 @@
   DrawHeadBK(pGraphics, pTheme, &matrix);
   DrawLButton(pGraphics, pTheme, &matrix);
   DrawRButton(pGraphics, pTheme, &matrix);
-  DrawSeperator(pGraphics, pTheme, &matrix);
+  DrawSeparator(pGraphics, pTheme, &matrix);
   DrawDatesInBK(pGraphics, pTheme, &matrix);
   DrawDatesInCircle(pGraphics, pTheme, &matrix);
   DrawCaption(pGraphics, pTheme, &matrix);
@@ -189,7 +166,7 @@
   params.m_rtPart = m_rtClient;
   if (pMatrix)
     params.m_matrix.Concat(*pMatrix);
-  pTheme->DrawBackground(&params);
+  pTheme->DrawBackground(params);
 }
 
 void CFWL_MonthCalendar::DrawHeadBK(CXFA_Graphics* pGraphics,
@@ -203,7 +180,7 @@
   params.m_rtPart = m_rtHead;
   if (pMatrix)
     params.m_matrix.Concat(*pMatrix);
-  pTheme->DrawBackground(&params);
+  pTheme->DrawBackground(params);
 }
 
 void CFWL_MonthCalendar::DrawLButton(CXFA_Graphics* pGraphics,
@@ -217,7 +194,7 @@
   params.m_rtPart = m_rtLBtn;
   if (pMatrix)
     params.m_matrix.Concat(*pMatrix);
-  pTheme->DrawBackground(&params);
+  pTheme->DrawBackground(params);
 }
 
 void CFWL_MonthCalendar::DrawRButton(CXFA_Graphics* pGraphics,
@@ -231,7 +208,7 @@
   params.m_rtPart = m_rtRBtn;
   if (pMatrix)
     params.m_matrix.Concat(*pMatrix);
-  pTheme->DrawBackground(&params);
+  pTheme->DrawBackground(params);
 }
 
 void CFWL_MonthCalendar::DrawCaption(CXFA_Graphics* pGraphics,
@@ -243,18 +220,18 @@
   textParam.m_dwStates = CFWL_PartState_Normal;
   textParam.m_pGraphics = pGraphics;
   textParam.m_wsText = GetHeadText(m_iCurYear, m_iCurMonth);
-  m_szHead =
-      CalcTextSize(textParam.m_wsText, m_pProperties->m_pThemeProvider, false);
+  m_szHead = CalcTextSize(textParam.m_wsText,
+                          m_pProperties->m_pThemeProvider.Get(), false);
   CalcHeadSize();
   textParam.m_rtPart = m_rtHeadText;
   textParam.m_dwTTOStyles.single_line_ = true;
   textParam.m_iTTOAlign = FDE_TextAlignment::kCenter;
   if (pMatrix)
     textParam.m_matrix.Concat(*pMatrix);
-  pTheme->DrawText(&textParam);
+  pTheme->DrawText(textParam);
 }
 
-void CFWL_MonthCalendar::DrawSeperator(CXFA_Graphics* pGraphics,
+void CFWL_MonthCalendar::DrawSeparator(CXFA_Graphics* pGraphics,
                                        IFWL_ThemeProvider* pTheme,
                                        const CFX_Matrix* pMatrix) {
   CFWL_ThemeBackground params;
@@ -265,7 +242,7 @@
   params.m_rtPart = m_rtHSep;
   if (pMatrix)
     params.m_matrix.Concat(*pMatrix);
-  pTheme->DrawBackground(&params);
+  pTheme->DrawBackground(params);
 }
 
 void CFWL_MonthCalendar::DrawDatesInBK(CXFA_Graphics* pGraphics,
@@ -290,10 +267,10 @@
       params.m_dwStates |= CFWL_PartState_Hovered;
     } else if (pDataInfo->dwStates & FWL_ITEMSTATE_MCD_Flag) {
       params.m_dwStates = CFWL_PartState_Flagged;
-      pTheme->DrawBackground(&params);
+      pTheme->DrawBackground(params);
     }
     params.m_rtPart = pDataInfo->rect;
-    pTheme->DrawBackground(&params);
+    pTheme->DrawBackground(params);
     params.m_dwStates = 0;
   }
 }
@@ -313,14 +290,14 @@
   if (pMatrix)
     params.m_matrix.Concat(*pMatrix);
 
-  for (int32_t i = 0; i < 7; i++) {
+  for (int32_t i = 0; i < 7; ++i) {
     rtDayOfWeek =
         CFX_RectF(m_rtWeek.left + i * (m_szCell.width + MONTHCAL_HMARGIN * 2),
                   m_rtWeek.top, m_szCell);
 
     params.m_rtPart = rtDayOfWeek;
-    params.m_wsText = GetCapacityForDay(pTheme, params, i);
-    pTheme->DrawText(&params);
+    params.m_wsText = GetAbbreviatedDayOfWeek(i);
+    pTheme->DrawText(params);
   }
 }
 
@@ -333,17 +310,17 @@
   params.m_pGraphics = pGraphics;
   params.m_dwStates = CFWL_PartState_Normal;
   params.m_iTTOAlign = FDE_TextAlignment::kCenterLeft;
-  params.m_wsText = L"Today" + GetTodayText(m_iYear, m_iMonth, m_iDay);
+  params.m_wsText = GetTodayText(m_iYear, m_iMonth, m_iDay);
 
-  m_szToday =
-      CalcTextSize(params.m_wsText, m_pProperties->m_pThemeProvider, false);
+  m_szToday = CalcTextSize(params.m_wsText,
+                           m_pProperties->m_pThemeProvider.Get(), false);
   CalcTodaySize();
   params.m_rtPart = m_rtToday;
   params.m_dwTTOStyles.single_line_ = true;
 
   if (pMatrix)
     params.m_matrix.Concat(*pMatrix);
-  pTheme->DrawText(&params);
+  pTheme->DrawText(params);
 }
 
 void CFWL_MonthCalendar::DrawDatesIn(CXFA_Graphics* pGraphics,
@@ -368,7 +345,7 @@
       params.m_dwStates |= CFWL_PartState_Hovered;
 
     params.m_dwTTOStyles.single_line_ = true;
-    pTheme->DrawText(&params);
+    pTheme->DrawText(params);
   }
 }
 
@@ -383,7 +360,7 @@
   params.m_iTTOAlign = FDE_TextAlignment::kCenter;
   if (pMatrix)
     params.m_matrix.Concat(*pMatrix);
-  pTheme->DrawText(&params);
+  pTheme->DrawText(params);
 }
 
 void CFWL_MonthCalendar::DrawDatesInCircle(CXFA_Graphics* pGraphics,
@@ -407,22 +384,18 @@
   params.m_dwStates = CFWL_PartState_Normal;
   if (pMatrix)
     params.m_matrix.Concat(*pMatrix);
-  pTheme->DrawBackground(&params);
+  pTheme->DrawBackground(params);
 }
 
 CFX_SizeF CFWL_MonthCalendar::CalcSize() {
-  if (!m_pProperties->m_pThemeProvider)
+  IFWL_ThemeProvider* pTheme = m_pProperties->m_pThemeProvider.Get();
+  if (!pTheme)
     return CFX_SizeF();
 
-  CFWL_ThemePart params;
-  params.m_pWidget = this;
-  IFWL_ThemeProvider* pTheme = m_pProperties->m_pThemeProvider;
   float fMaxWeekW = 0.0f;
   float fMaxWeekH = 0.0f;
-
-  for (uint32_t i = 0; i < 7; ++i) {
-    CFX_SizeF sz = CalcTextSize(GetCapacityForDay(pTheme, params, i),
-                                m_pProperties->m_pThemeProvider, false);
+  for (int i = 0; i < 7; ++i) {
+    CFX_SizeF sz = CalcTextSize(GetAbbreviatedDayOfWeek(i), pTheme, false);
     fMaxWeekW = (fMaxWeekW >= sz.width) ? fMaxWeekW : sz.width;
     fMaxWeekH = (fMaxWeekH >= sz.height) ? fMaxWeekH : sz.height;
   }
@@ -430,40 +403,37 @@
   float fDayMaxW = 0.0f;
   float fDayMaxH = 0.0f;
   for (int day = 10; day <= 31; day++) {
-    CFX_SizeF sz = CalcTextSize(WideString::Format(L"%d", day),
-                                m_pProperties->m_pThemeProvider, false);
+    CFX_SizeF sz = CalcTextSize(WideString::Format(L"%d", day), pTheme, false);
     fDayMaxW = (fDayMaxW >= sz.width) ? fDayMaxW : sz.width;
     fDayMaxH = (fDayMaxH >= sz.height) ? fDayMaxH : sz.height;
   }
-  m_szCell.width = float((fMaxWeekW >= fDayMaxW) ? (int)(fMaxWeekW + 0.5)
-                                                 : (int)(fDayMaxW + 0.5));
-  m_szCell.height = (fMaxWeekH >= fDayMaxH) ? fMaxWeekH : fDayMaxH;
+  m_szCell.width =
+      static_cast<int>(0.5 + (fMaxWeekW >= fDayMaxW ? fMaxWeekW : fDayMaxW));
+  m_szCell.height = fMaxWeekH >= fDayMaxH ? fMaxWeekH : fDayMaxH;
 
   CFX_SizeF fs;
   fs.width = m_szCell.width * MONTHCAL_COLUMNS +
              MONTHCAL_HMARGIN * MONTHCAL_COLUMNS * 2 +
              MONTHCAL_HEADER_BTN_HMARGIN * 2;
+
   float fMonthMaxW = 0.0f;
   float fMonthMaxH = 0.0f;
-
-  for (uint32_t i = 0; i < 12; ++i) {
-    CFX_SizeF sz = CalcTextSize(GetCapacityForMonth(pTheme, params, i),
-                                m_pProperties->m_pThemeProvider, false);
+  for (int i = 0; i < 12; ++i) {
+    CFX_SizeF sz = CalcTextSize(GetMonth(i), pTheme, false);
     fMonthMaxW = (fMonthMaxW >= sz.width) ? fMonthMaxW : sz.width;
     fMonthMaxH = (fMonthMaxH >= sz.height) ? fMonthMaxH : sz.height;
   }
 
-  CFX_SizeF szYear = CalcTextSize(GetHeadText(m_iYear, m_iMonth),
-                                  m_pProperties->m_pThemeProvider, false);
+  CFX_SizeF szYear =
+      CalcTextSize(GetHeadText(m_iYear, m_iMonth), pTheme, false);
   fMonthMaxH = std::max(fMonthMaxH, szYear.height);
   m_szHead = CFX_SizeF(fMonthMaxW + szYear.width, fMonthMaxH);
   fMonthMaxW =
       m_szHead.width + MONTHCAL_HEADER_BTN_HMARGIN * 2 + m_szCell.width * 2;
   fs.width = std::max(fs.width, fMonthMaxW);
 
-  WideString wsToday = GetTodayText(m_iYear, m_iMonth, m_iDay);
-  m_wsToday = L"Today" + wsToday;
-  m_szToday = CalcTextSize(wsToday, m_pProperties->m_pThemeProvider, false);
+  m_wsToday = GetTodayText(m_iYear, m_iMonth, m_iDay);
+  m_szToday = CalcTextSize(m_wsToday, pTheme, false);
   m_szToday.height = (m_szToday.height >= m_szCell.height) ? m_szToday.height
                                                            : m_szCell.height;
   fs.height = m_szCell.width + m_szCell.height * (MONTHCAL_ROWS - 2) +
@@ -552,11 +522,11 @@
 }
 
 void CFWL_MonthCalendar::InitDate() {
-  // TODO(dsinclair): These should pull the real today values instead of
-  // pretending it's 2011-01-01.
-  m_iYear = 2011;
-  m_iMonth = 1;
-  m_iDay = 1;
+  CFX_DateTime now = CFX_DateTime::Now();
+
+  m_iYear = now.GetYear();
+  m_iMonth = now.GetMonth();
+  m_iDay = now.GetDay();
   m_iCurYear = m_iYear;
   m_iCurMonth = m_iMonth;
 
@@ -672,7 +642,9 @@
 }
 
 WideString CFWL_MonthCalendar::GetHeadText(int32_t iYear, int32_t iMonth) {
-  ASSERT(iMonth > 0 && iMonth < 13);
+  ASSERT(iMonth > 0);
+  ASSERT(iMonth < 13);
+
   static const wchar_t* const pMonth[] = {L"January", L"February", L"March",
                                           L"April",   L"May",      L"June",
                                           L"July",    L"August",   L"September",
@@ -683,7 +655,7 @@
 WideString CFWL_MonthCalendar::GetTodayText(int32_t iYear,
                                             int32_t iMonth,
                                             int32_t iDay) {
-  return WideString::Format(L", %d/%d/%d", iDay, iMonth, iYear);
+  return WideString::Format(L"Today, %d/%d/%d", iDay, iMonth, iYear);
 }
 
 int32_t CFWL_MonthCalendar::GetDayAtPoint(const CFX_PointF& point) const {
@@ -738,7 +710,9 @@
     default:
       break;
   }
-  CFWL_Widget::OnProcessMessage(pMessage);
+  // Dst target could be |this|, continue only if not destroyed by above.
+  if (pMessage->GetDstTarget())
+    CFWL_Widget::OnProcessMessage(pMessage);
 }
 
 void CFWL_MonthCalendar::OnDrawWidget(CXFA_Graphics* pGraphics,
@@ -758,58 +732,10 @@
   } else if (m_rtToday.Contains(pMsg->m_pos)) {
     JumpToToday();
     RepaintRect(m_rtClient);
-  } else {
-    CFWL_DateTimePicker* pIPicker = static_cast<CFWL_DateTimePicker*>(m_pOuter);
-    if (pIPicker->IsMonthCalendarVisible())
-      m_bFlag = true;
   }
 }
 
 void CFWL_MonthCalendar::OnLButtonUp(CFWL_MessageMouse* pMsg) {
-  if (m_pWidgetMgr->IsFormDisabled())
-    return DisForm_OnLButtonUp(pMsg);
-
-  if (m_rtLBtn.Contains(pMsg->m_pos)) {
-    m_iLBtnPartStates = 0;
-    RepaintRect(m_rtLBtn);
-    return;
-  }
-  if (m_rtRBtn.Contains(pMsg->m_pos)) {
-    m_iRBtnPartStates = 0;
-    RepaintRect(m_rtRBtn);
-    return;
-  }
-  if (m_rtToday.Contains(pMsg->m_pos))
-    return;
-
-  int32_t iOldSel = 0;
-  if (!m_arrSelDays.empty())
-    iOldSel = m_arrSelDays[0];
-
-  int32_t iCurSel = GetDayAtPoint(pMsg->m_pos);
-  CFWL_DateTimePicker* pIPicker = static_cast<CFWL_DateTimePicker*>(m_pOuter);
-  if (iCurSel > 0) {
-    DATEINFO* lpDatesInfo = m_arrDates[iCurSel - 1].get();
-    CFX_RectF rtInvalidate(lpDatesInfo->rect);
-    if (iOldSel > 0 && iOldSel <= pdfium::CollectionSize<int32_t>(m_arrDates)) {
-      lpDatesInfo = m_arrDates[iOldSel - 1].get();
-      rtInvalidate.Union(lpDatesInfo->rect);
-    }
-    AddSelDay(iCurSel);
-    if (!m_pOuter)
-      return;
-
-    pIPicker->ProcessSelChanged(m_iCurYear, m_iCurMonth, iCurSel);
-    pIPicker->ShowMonthCalendar(false);
-  } else if (m_bFlag &&
-             (!CFX_RectF(0, 0, pIPicker->GetFormProxy()->GetWidgetRect().Size())
-                   .Contains(pMsg->m_pos))) {
-    pIPicker->ShowMonthCalendar(false);
-  }
-  m_bFlag = false;
-}
-
-void CFWL_MonthCalendar::DisForm_OnLButtonUp(CFWL_MessageMouse* pMsg) {
   if (m_rtLBtn.Contains(pMsg->m_pos)) {
     m_iLBtnPartStates = 0;
     RepaintRect(m_rtLBtn);
diff --git a/xfa/fwl/cfwl_monthcalendar.h b/xfa/fwl/cfwl_monthcalendar.h
index 7b68600..a00ea0f 100644
--- a/xfa/fwl/cfwl_monthcalendar.h
+++ b/xfa/fwl/cfwl_monthcalendar.h
@@ -19,9 +19,8 @@
 #define FWL_ITEMSTATE_MCD_Selected (1L << 1)
 
 class CFWL_MessageMouse;
-class CFWL_Widget;
 
-class CFWL_MonthCalendar : public CFWL_Widget {
+class CFWL_MonthCalendar final : public CFWL_Widget {
  public:
   CFWL_MonthCalendar(const CFWL_App* app,
                      std::unique_ptr<CFWL_WidgetProperties> properties,
@@ -104,7 +103,7 @@
   void DrawCaption(CXFA_Graphics* pGraphics,
                    IFWL_ThemeProvider* pTheme,
                    const CFX_Matrix* pMatrix);
-  void DrawSeperator(CXFA_Graphics* pGraphics,
+  void DrawSeparator(CXFA_Graphics* pGraphics,
                      IFWL_ThemeProvider* pTheme,
                      const CFX_Matrix* pMatrix);
   void DrawDatesInBK(CXFA_Graphics* pGraphics,
@@ -146,11 +145,10 @@
   CFX_RectF GetDayRect(int32_t iDay);
   void OnLButtonDown(CFWL_MessageMouse* pMsg);
   void OnLButtonUp(CFWL_MessageMouse* pMsg);
-  void DisForm_OnLButtonUp(CFWL_MessageMouse* pMsg);
   void OnMouseMove(CFWL_MessageMouse* pMsg);
   void OnMouseLeave(CFWL_MessageMouse* pMsg);
 
-  bool m_bInitialized;
+  bool m_bInitialized = false;
   CFX_RectF m_rtHead;
   CFX_RectF m_rtWeek;
   CFX_RectF m_rtLBtn;
@@ -160,19 +158,17 @@
   CFX_RectF m_rtHeadText;
   CFX_RectF m_rtToday;
   CFX_RectF m_rtTodayFlag;
-  CFX_RectF m_rtWeekNum;
-  CFX_RectF m_rtWeekNumSep;
   WideString m_wsHead;
   WideString m_wsToday;
   std::vector<std::unique_ptr<DATEINFO>> m_arrDates;
-  int32_t m_iCurYear;
-  int32_t m_iCurMonth;
-  int32_t m_iYear;
-  int32_t m_iMonth;
-  int32_t m_iDay;
-  int32_t m_iHovered;
-  int32_t m_iLBtnPartStates;
-  int32_t m_iRBtnPartStates;
+  int32_t m_iCurYear = 2011;
+  int32_t m_iCurMonth = 1;
+  int32_t m_iYear = 2011;
+  int32_t m_iMonth = 1;
+  int32_t m_iDay = 1;
+  int32_t m_iHovered = -1;
+  int32_t m_iLBtnPartStates = CFWL_PartState_Normal;
+  int32_t m_iRBtnPartStates = CFWL_PartState_Normal;
   DATE m_dtMin;
   DATE m_dtMax;
   CFX_SizeF m_szHead;
@@ -180,7 +176,6 @@
   CFX_SizeF m_szToday;
   std::vector<int32_t> m_arrSelDays;
   CFX_RectF m_rtClient;
-  bool m_bFlag;
 };
 
 #endif  // XFA_FWL_CFWL_MONTHCALENDAR_H_
diff --git a/xfa/fwl/cfwl_notedriver.cpp b/xfa/fwl/cfwl_notedriver.cpp
index 9a19f4b..821dd5c 100644
--- a/xfa/fwl/cfwl_notedriver.cpp
+++ b/xfa/fwl/cfwl_notedriver.cpp
@@ -9,29 +9,23 @@
 #include <algorithm>
 #include <utility>
 
+#include "build/build_config.h"
 #include "core/fxcrt/fx_extension.h"
 #include "third_party/base/ptr_util.h"
 #include "third_party/base/stl_util.h"
 #include "xfa/fwl/cfwl_app.h"
 #include "xfa/fwl/cfwl_eventtarget.h"
-#include "xfa/fwl/cfwl_form.h"
 #include "xfa/fwl/cfwl_messagekey.h"
 #include "xfa/fwl/cfwl_messagekillfocus.h"
 #include "xfa/fwl/cfwl_messagemouse.h"
 #include "xfa/fwl/cfwl_messagemousewheel.h"
 #include "xfa/fwl/cfwl_messagesetfocus.h"
-#include "xfa/fwl/cfwl_noteloop.h"
 #include "xfa/fwl/cfwl_widgetmgr.h"
+#include "xfa/fwl/fwl_widgetdef.h"
 
-CFWL_NoteDriver::CFWL_NoteDriver()
-    : m_pHover(nullptr),
-      m_pFocus(nullptr),
-      m_pGrab(nullptr),
-      m_pNoteLoop(pdfium::MakeUnique<CFWL_NoteLoop>()) {
-  PushNoteLoop(m_pNoteLoop.get());
-}
+CFWL_NoteDriver::CFWL_NoteDriver() = default;
 
-CFWL_NoteDriver::~CFWL_NoteDriver() {}
+CFWL_NoteDriver::~CFWL_NoteDriver() = default;
 
 void CFWL_NoteDriver::SendEvent(CFWL_Event* pNote) {
   for (const auto& pair : m_eventTargets) {
@@ -65,24 +59,11 @@
     it->second->FlagInvalid();
 }
 
-void CFWL_NoteDriver::PushNoteLoop(CFWL_NoteLoop* pNoteLoop) {
-  m_NoteLoopQueue.push_back(pNoteLoop);
-}
-
-CFWL_NoteLoop* CFWL_NoteDriver::PopNoteLoop() {
-  if (m_NoteLoopQueue.empty())
-    return nullptr;
-
-  CFWL_NoteLoop* p = m_NoteLoopQueue.back();
-  m_NoteLoopQueue.pop_back();
-  return p;
-}
-
 bool CFWL_NoteDriver::SetFocus(CFWL_Widget* pFocus) {
   if (m_pFocus == pFocus)
     return true;
 
-  CFWL_Widget* pPrev = m_pFocus;
+  CFWL_Widget* pPrev = m_pFocus.Get();
   m_pFocus = pFocus;
   if (pPrev) {
     if (IFWL_WidgetDelegate* pDelegate = pPrev->GetDelegate()) {
@@ -91,12 +72,6 @@
     }
   }
   if (pFocus) {
-    CFWL_Widget* pWidget =
-        pFocus->GetOwnerApp()->GetWidgetMgr()->GetSystemFormWidget(pFocus);
-    CFWL_Form* pForm = static_cast<CFWL_Form*>(pWidget);
-    if (pForm)
-      pForm->SetSubFocus(pFocus);
-
     if (IFWL_WidgetDelegate* pDelegate = pFocus->GetDelegate()) {
       CFWL_MessageSetFocus ms(nullptr, pFocus);
       pDelegate->OnProcessMessage(&ms);
@@ -105,17 +80,6 @@
   return true;
 }
 
-void CFWL_NoteDriver::Run() {
-#if _FX_OS_ == _FX_OS_LINUX_ || _FX_PLATFORM_ == _FX_PLATFORM_WINDOWS_
-  for (;;) {
-    CFWL_NoteLoop* pTopLoop = GetTopLoop();
-    if (!pTopLoop || !pTopLoop->ContinueModal())
-      break;
-    UnqueueMessageAndProcess(pTopLoop);
-  }
-#endif  // _FX_OS_ == _FX_OS_LINUX_ || _FX_PLATFORM_ == _FX_PLATFORM_WINDOWS_
-}
-
 void CFWL_NoteDriver::NotifyTargetHide(CFWL_Widget* pNoteTarget) {
   if (m_pFocus == pNoteTarget)
     m_pFocus = nullptr;
@@ -134,62 +98,10 @@
     m_pGrab = nullptr;
 
   UnregisterEventTarget(pNoteTarget);
-
-  for (CFWL_Widget* pWidget : m_Forms) {
-    CFWL_Form* pForm = static_cast<CFWL_Form*>(pWidget);
-    if (!pForm)
-      continue;
-
-    CFWL_Widget* pSubFocus = pForm->GetSubFocus();
-    if (!pSubFocus)
-      return;
-
-    if (pSubFocus == pNoteTarget)
-      pForm->SetSubFocus(nullptr);
-  }
-}
-
-void CFWL_NoteDriver::RegisterForm(CFWL_Widget* pForm) {
-  if (!pForm || pdfium::ContainsValue(m_Forms, pForm))
-    return;
-
-  m_Forms.push_back(pForm);
-  if (m_Forms.size() == 1 && !m_NoteLoopQueue.empty() && m_NoteLoopQueue[0])
-    m_NoteLoopQueue[0]->SetMainForm(pForm);
-}
-
-void CFWL_NoteDriver::UnRegisterForm(CFWL_Widget* pForm) {
-  auto iter = std::find(m_Forms.begin(), m_Forms.end(), pForm);
-  if (iter != m_Forms.end())
-    m_Forms.erase(iter);
-}
-
-void CFWL_NoteDriver::QueueMessage(std::unique_ptr<CFWL_Message> pMessage) {
-  m_NoteQueue.push_back(std::move(pMessage));
-}
-
-void CFWL_NoteDriver::UnqueueMessageAndProcess(CFWL_NoteLoop* pNoteLoop) {
-  if (m_NoteQueue.empty())
-    return;
-
-  std::unique_ptr<CFWL_Message> pMessage = std::move(m_NoteQueue.front());
-  m_NoteQueue.pop_front();
-  if (!IsValidMessage(pMessage.get()))
-    return;
-
-  ProcessMessage(std::move(pMessage));
-}
-
-CFWL_NoteLoop* CFWL_NoteDriver::GetTopLoop() const {
-  return !m_NoteLoopQueue.empty() ? m_NoteLoopQueue.back() : nullptr;
 }
 
 void CFWL_NoteDriver::ProcessMessage(std::unique_ptr<CFWL_Message> pMessage) {
-  CFWL_WidgetMgr* pWidgetMgr =
-      pMessage->m_pDstTarget->GetOwnerApp()->GetWidgetMgr();
-  CFWL_Widget* pMessageForm = pWidgetMgr->IsFormDisabled()
-                                  ? pMessage->m_pDstTarget
-                                  : GetMessageForm(pMessage->m_pDstTarget);
+  CFWL_Widget* pMessageForm = pMessage->GetDstTarget();
   if (!pMessageForm)
     return;
 
@@ -231,7 +143,8 @@
     default:
       break;
   }
-  if (IFWL_WidgetDelegate* pDelegate = pMessage->m_pDstTarget->GetDelegate())
+  IFWL_WidgetDelegate* pDelegate = pMessage->GetDstTarget()->GetDelegate();
+  if (pDelegate)
     pDelegate->OnProcessMessage(pMessage);
 
   return true;
@@ -239,68 +152,33 @@
 
 bool CFWL_NoteDriver::DoSetFocus(CFWL_Message* pMessage,
                                  CFWL_Widget* pMessageForm) {
-  CFWL_WidgetMgr* pWidgetMgr = pMessageForm->GetOwnerApp()->GetWidgetMgr();
-  if (pWidgetMgr->IsFormDisabled()) {
-    m_pFocus = pMessage->m_pDstTarget;
-    return true;
-  }
-
-  CFWL_Widget* pWidget = pMessage->m_pDstTarget;
-  if (!pWidget)
-    return false;
-
-  CFWL_Form* pForm = static_cast<CFWL_Form*>(pWidget);
-  CFWL_Widget* pSubFocus = pForm->GetSubFocus();
-  if (pSubFocus && ((pSubFocus->GetStates() & FWL_WGTSTATE_Focused) == 0)) {
-    pMessage->m_pDstTarget = pSubFocus;
-    if (m_pFocus != pMessage->m_pDstTarget) {
-      m_pFocus = pMessage->m_pDstTarget;
-      return true;
-    }
-  }
-  return false;
+  m_pFocus = pMessage->GetDstTarget();
+  return true;
 }
 
 bool CFWL_NoteDriver::DoKillFocus(CFWL_Message* pMessage,
                                   CFWL_Widget* pMessageForm) {
-  CFWL_WidgetMgr* pWidgetMgr = pMessageForm->GetOwnerApp()->GetWidgetMgr();
-  if (pWidgetMgr->IsFormDisabled()) {
-    if (m_pFocus == pMessage->m_pDstTarget)
-      m_pFocus = nullptr;
-    return true;
-  }
-
-  CFWL_Form* pForm = static_cast<CFWL_Form*>(pMessage->m_pDstTarget);
-  if (!pForm)
-    return false;
-
-  CFWL_Widget* pSubFocus = pForm->GetSubFocus();
-  if (pSubFocus && (pSubFocus->GetStates() & FWL_WGTSTATE_Focused)) {
-    pMessage->m_pDstTarget = pSubFocus;
-    if (m_pFocus == pMessage->m_pDstTarget) {
-      m_pFocus = nullptr;
-      return true;
-    }
-  }
-  return false;
+  if (m_pFocus == pMessage->GetDstTarget())
+    m_pFocus = nullptr;
+  return true;
 }
 
 bool CFWL_NoteDriver::DoKey(CFWL_Message* pMessage, CFWL_Widget* pMessageForm) {
   CFWL_MessageKey* pMsg = static_cast<CFWL_MessageKey*>(pMessage);
-#if (_FX_OS_ != _FX_OS_MACOSX_)
+#if !defined(OS_MACOSX)
   if (pMsg->m_dwCmd == FWL_KeyCommand::KeyDown &&
-      pMsg->m_dwKeyCode == FWL_VKEY_Tab) {
+      pMsg->m_dwKeyCode == XFA_FWL_VKEY_Tab) {
     CFWL_WidgetMgr* pWidgetMgr = pMessageForm->GetOwnerApp()->GetWidgetMgr();
-    CFWL_Widget* pForm = GetMessageForm(pMsg->m_pDstTarget);
-    CFWL_Widget* pFocus = m_pFocus;
-    if (m_pFocus && pWidgetMgr->GetSystemFormWidget(m_pFocus) != pForm)
+    CFWL_Widget* pForm = GetMessageForm(pMsg->GetDstTarget());
+    CFWL_Widget* pFocus = m_pFocus.Get();
+    if (m_pFocus && pWidgetMgr->GetSystemFormWidget(m_pFocus.Get()) != pForm)
       pFocus = nullptr;
 
-    bool bFind = false;
-    CFWL_Widget* pNextTabStop = pWidgetMgr->NextTab(pForm, pFocus, bFind);
-    if (!pNextTabStop) {
-      bFind = false;
-      pNextTabStop = pWidgetMgr->NextTab(pForm, nullptr, bFind);
+    CFWL_Widget* pNextTabStop = nullptr;
+    if (pForm) {
+      pNextTabStop = CFWL_WidgetMgr::NextTab(pForm, pFocus);
+      if (!pNextTabStop)
+        pNextTabStop = CFWL_WidgetMgr::NextTab(pForm, nullptr);
     }
     if (pNextTabStop == pFocus)
       return true;
@@ -310,20 +188,21 @@
   }
 #endif
 
-  if (!m_pFocus) {
-    if (pMsg->m_dwCmd == FWL_KeyCommand::KeyDown &&
-        pMsg->m_dwKeyCode == FWL_VKEY_Return) {
-      CFWL_WidgetMgr* pWidgetMgr = pMessageForm->GetOwnerApp()->GetWidgetMgr();
-      CFWL_Widget* defButton = pWidgetMgr->GetDefaultButton(pMessageForm);
-      if (defButton) {
-        pMsg->m_pDstTarget = defButton;
-        return true;
-      }
-    }
-    return false;
+  if (m_pFocus) {
+    pMsg->SetDstTarget(m_pFocus.Get());
+    return true;
   }
-  pMsg->m_pDstTarget = m_pFocus;
-  return true;
+
+  if (pMsg->m_dwCmd == FWL_KeyCommand::KeyDown &&
+      pMsg->m_dwKeyCode == XFA_FWL_VKEY_Return) {
+    CFWL_WidgetMgr* pWidgetMgr = pMessageForm->GetOwnerApp()->GetWidgetMgr();
+    CFWL_Widget* pDefButton = pWidgetMgr->GetDefaultButton(pMessageForm);
+    if (pDefButton) {
+      pMsg->SetDstTarget(pDefButton);
+      return true;
+    }
+  }
+  return false;
 }
 
 bool CFWL_NoteDriver::DoMouse(CFWL_Message* pMessage,
@@ -332,39 +211,34 @@
   if (pMsg->m_dwCmd == FWL_MouseCommand::Leave ||
       pMsg->m_dwCmd == FWL_MouseCommand::Hover ||
       pMsg->m_dwCmd == FWL_MouseCommand::Enter) {
-    return !!pMsg->m_pDstTarget;
+    return !!pMsg->GetDstTarget();
   }
-  if (pMsg->m_pDstTarget != pMessageForm)
-    pMsg->m_pos = pMsg->m_pDstTarget->TransformTo(pMessageForm, pMsg->m_pos);
+  if (pMsg->GetDstTarget() != pMessageForm)
+    pMsg->m_pos = pMsg->GetDstTarget()->TransformTo(pMessageForm, pMsg->m_pos);
   if (!DoMouseEx(pMsg, pMessageForm))
-    pMsg->m_pDstTarget = pMessageForm;
+    pMsg->SetDstTarget(pMessageForm);
   return true;
 }
 
 bool CFWL_NoteDriver::DoWheel(CFWL_Message* pMessage,
                               CFWL_Widget* pMessageForm) {
   CFWL_WidgetMgr* pWidgetMgr = pMessageForm->GetOwnerApp()->GetWidgetMgr();
-  if (!pWidgetMgr)
-    return false;
-
   CFWL_MessageMouseWheel* pMsg = static_cast<CFWL_MessageMouseWheel*>(pMessage);
   CFWL_Widget* pDst = pWidgetMgr->GetWidgetAtPoint(pMessageForm, pMsg->m_pos);
   if (!pDst)
     return false;
 
   pMsg->m_pos = pMessageForm->TransformTo(pDst, pMsg->m_pos);
-  pMsg->m_pDstTarget = pDst;
+  pMsg->SetDstTarget(pDst);
   return true;
 }
 
 bool CFWL_NoteDriver::DoMouseEx(CFWL_Message* pMessage,
                                 CFWL_Widget* pMessageForm) {
   CFWL_WidgetMgr* pWidgetMgr = pMessageForm->GetOwnerApp()->GetWidgetMgr();
-  if (!pWidgetMgr)
-    return false;
   CFWL_Widget* pTarget = nullptr;
   if (m_pGrab)
-    pTarget = m_pGrab;
+    pTarget = m_pGrab.Get();
 
   CFWL_MessageMouse* pMsg = static_cast<CFWL_MessageMouse*>(pMessage);
   if (!pTarget)
@@ -374,21 +248,20 @@
   if (pTarget && pMessageForm != pTarget)
     pMsg->m_pos = pMessageForm->TransformTo(pTarget, pMsg->m_pos);
 
-  pMsg->m_pDstTarget = pTarget;
+  pMsg->SetDstTarget(pTarget);
   return true;
 }
 
 void CFWL_NoteDriver::MouseSecondary(CFWL_Message* pMessage) {
-  CFWL_Widget* pTarget = pMessage->m_pDstTarget;
+  CFWL_Widget* pTarget = pMessage->GetDstTarget();
   if (pTarget == m_pHover)
     return;
 
   CFWL_MessageMouse* pMsg = static_cast<CFWL_MessageMouse*>(pMessage);
   if (m_pHover) {
-    CFWL_MessageMouse msLeave(nullptr, m_pHover);
-    msLeave.m_pos = pTarget->TransformTo(m_pHover, pMsg->m_pos);
-    msLeave.m_dwFlags = 0;
-    msLeave.m_dwCmd = FWL_MouseCommand::Leave;
+    CFWL_MessageMouse msLeave(
+        m_pHover.Get(), FWL_MouseCommand::Leave, 0,
+        pTarget->TransformTo(m_pHover.Get(), pMsg->m_pos));
     DispatchMessage(&msLeave, nullptr);
   }
   if (pTarget->GetClassID() == FWL_Type::Form) {
@@ -397,45 +270,16 @@
   }
   m_pHover = pTarget;
 
-  CFWL_MessageMouse msHover(nullptr, pTarget);
-  msHover.m_pos = pMsg->m_pos;
-  msHover.m_dwFlags = 0;
-  msHover.m_dwCmd = FWL_MouseCommand::Hover;
+  CFWL_MessageMouse msHover(pTarget, FWL_MouseCommand::Hover, 0, pMsg->m_pos);
   DispatchMessage(&msHover, nullptr);
 }
 
-bool CFWL_NoteDriver::IsValidMessage(CFWL_Message* pMessage) {
-  for (CFWL_NoteLoop* pNoteLoop : m_NoteLoopQueue) {
-    CFWL_Widget* pForm = pNoteLoop->GetForm();
-    if (pForm && pForm == pMessage->m_pDstTarget)
-      return true;
-  }
-  for (CFWL_Widget* pWidget : m_Forms) {
-    CFWL_Form* pForm = static_cast<CFWL_Form*>(pWidget);
-    if (pForm == pMessage->m_pDstTarget)
-      return true;
-  }
-  return false;
-}
-
 CFWL_Widget* CFWL_NoteDriver::GetMessageForm(CFWL_Widget* pDstTarget) {
-  if (m_NoteLoopQueue.empty())
+  if (!pDstTarget)
     return nullptr;
 
-  CFWL_Widget* pMessageForm = nullptr;
-  if (m_NoteLoopQueue.size() > 1)
-    pMessageForm = m_NoteLoopQueue.back()->GetForm();
-  else if (!pdfium::ContainsValue(m_Forms, pDstTarget))
-    pMessageForm = pDstTarget;
-
-  if (!pMessageForm && pDstTarget) {
-    CFWL_WidgetMgr* pWidgetMgr = pDstTarget->GetOwnerApp()->GetWidgetMgr();
-    if (!pWidgetMgr)
-      return nullptr;
-
-    pMessageForm = pWidgetMgr->GetSystemFormWidget(pDstTarget);
-  }
-  return pMessageForm;
+  CFWL_WidgetMgr* pWidgetMgr = pDstTarget->GetOwnerApp()->GetWidgetMgr();
+  return pWidgetMgr->GetSystemFormWidget(pDstTarget);
 }
 
 void CFWL_NoteDriver::ClearEventTargets() {
diff --git a/xfa/fwl/cfwl_notedriver.h b/xfa/fwl/cfwl_notedriver.h
index 0db482e..1de761b 100644
--- a/xfa/fwl/cfwl_notedriver.h
+++ b/xfa/fwl/cfwl_notedriver.h
@@ -7,17 +7,16 @@
 #ifndef XFA_FWL_CFWL_NOTEDRIVER_H_
 #define XFA_FWL_CFWL_NOTEDRIVER_H_
 
-#include <deque>
 #include <map>
 #include <memory>
 #include <vector>
 
+#include "core/fxcrt/unowned_ptr.h"
 #include "xfa/fwl/cfwl_event.h"
 #include "xfa/fwl/cfwl_widget.h"
 #include "xfa/fxgraphics/cxfa_graphics.h"
 
 class CFWL_EventTarget;
-class CFWL_NoteLoop;
 class CFWL_TargetImp;
 class CFWL_Widget;
 
@@ -32,27 +31,15 @@
   void UnregisterEventTarget(CFWL_Widget* pListener);
   void ClearEventTargets();
 
-  CFWL_NoteLoop* GetTopLoop() const;
-  void PushNoteLoop(CFWL_NoteLoop* pNoteLoop);
-  CFWL_NoteLoop* PopNoteLoop();
-
-  CFWL_Widget* GetFocus() const { return m_pFocus; }
+  CFWL_Widget* GetFocus() const { return m_pFocus.Get(); }
   bool SetFocus(CFWL_Widget* pFocus);
   void SetGrab(CFWL_Widget* pGrab, bool bSet) {
     m_pGrab = bSet ? pGrab : nullptr;
   }
 
-  void Run();
-
   void NotifyTargetHide(CFWL_Widget* pNoteTarget);
   void NotifyTargetDestroy(CFWL_Widget* pNoteTarget);
-
-  void RegisterForm(CFWL_Widget* pForm);
-  void UnRegisterForm(CFWL_Widget* pForm);
-
   void ProcessMessage(std::unique_ptr<CFWL_Message> pMessage);
-  void QueueMessage(std::unique_ptr<CFWL_Message> pMessage);
-  void UnqueueMessageAndProcess(CFWL_NoteLoop* pNoteLoop);
 
  private:
   bool DispatchMessage(CFWL_Message* pMessage, CFWL_Widget* pMessageForm);
@@ -63,17 +50,12 @@
   bool DoWheel(CFWL_Message* pMsg, CFWL_Widget* pMessageForm);
   bool DoMouseEx(CFWL_Message* pMsg, CFWL_Widget* pMessageForm);
   void MouseSecondary(CFWL_Message* pMsg);
-  bool IsValidMessage(CFWL_Message* pMessage);
   CFWL_Widget* GetMessageForm(CFWL_Widget* pDstTarget);
 
-  std::vector<CFWL_Widget*> m_Forms;
-  std::deque<std::unique_ptr<CFWL_Message>> m_NoteQueue;
-  std::vector<CFWL_NoteLoop*> m_NoteLoopQueue;
   std::map<uint32_t, std::unique_ptr<CFWL_EventTarget>> m_eventTargets;
-  CFWL_Widget* m_pHover;
-  CFWL_Widget* m_pFocus;
-  CFWL_Widget* m_pGrab;
-  std::unique_ptr<CFWL_NoteLoop> m_pNoteLoop;
+  UnownedPtr<CFWL_Widget> m_pHover;
+  UnownedPtr<CFWL_Widget> m_pFocus;
+  UnownedPtr<CFWL_Widget> m_pGrab;
 };
 
 #endif  // XFA_FWL_CFWL_NOTEDRIVER_H_
diff --git a/xfa/fwl/cfwl_noteloop.cpp b/xfa/fwl/cfwl_noteloop.cpp
deleted file mode 100644
index ff35a1a..0000000
--- a/xfa/fwl/cfwl_noteloop.cpp
+++ /dev/null
@@ -1,9 +0,0 @@
-// Copyright 2016 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
-
-#include "xfa/fwl/cfwl_noteloop.h"
-
-CFWL_NoteLoop::CFWL_NoteLoop() : m_bContinueModal(true) {}
diff --git a/xfa/fwl/cfwl_noteloop.h b/xfa/fwl/cfwl_noteloop.h
deleted file mode 100644
index 57e1a14..0000000
--- a/xfa/fwl/cfwl_noteloop.h
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright 2016 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_FWL_CFWL_NOTELOOP_H_
-#define XFA_FWL_CFWL_NOTELOOP_H_
-
-class CFWL_Widget;
-
-class CFWL_NoteLoop {
- public:
-  CFWL_NoteLoop();
-  ~CFWL_NoteLoop() {}
-
-  CFWL_Widget* GetForm() const { return m_pForm; }
-  bool ContinueModal() const { return m_bContinueModal; }
-  void EndModalLoop() { m_bContinueModal = false; }
-  void SetMainForm(CFWL_Widget* pForm) { m_pForm = pForm; }
-
- private:
-  CFWL_Widget* m_pForm;
-  bool m_bContinueModal;
-};
-
-#endif  // XFA_FWL_CFWL_NOTELOOP_H_
diff --git a/xfa/fwl/cfwl_picturebox.cpp b/xfa/fwl/cfwl_picturebox.cpp
index 637de94..6e90765 100644
--- a/xfa/fwl/cfwl_picturebox.cpp
+++ b/xfa/fwl/cfwl_picturebox.cpp
@@ -12,9 +12,6 @@
 
 CFWL_PictureBox::CFWL_PictureBox(const CFWL_App* app)
     : CFWL_Widget(app, pdfium::MakeUnique<CFWL_WidgetProperties>(), nullptr) {
-  m_rtClient.Reset();
-  m_rtImage.Reset();
-  m_matrix.SetIdentity();
 }
 
 CFWL_PictureBox::~CFWL_PictureBox() {}
diff --git a/xfa/fwl/cfwl_picturebox.h b/xfa/fwl/cfwl_picturebox.h
index 363db8a..11689d2 100644
--- a/xfa/fwl/cfwl_picturebox.h
+++ b/xfa/fwl/cfwl_picturebox.h
@@ -7,15 +7,13 @@
 #ifndef XFA_FWL_CFWL_PICTUREBOX_H_
 #define XFA_FWL_CFWL_PICTUREBOX_H_
 
-#include <memory>
-
 #include "xfa/fwl/cfwl_widget.h"
 #include "xfa/fwl/cfwl_widgetproperties.h"
 
 class CFX_DIBitmap;
 class CFWL_Widget;
 
-class CFWL_PictureBox : public CFWL_Widget {
+class CFWL_PictureBox final : public CFWL_Widget {
  public:
   explicit CFWL_PictureBox(const CFWL_App* pApp);
   ~CFWL_PictureBox() override;
diff --git a/xfa/fwl/cfwl_pushbutton.cpp b/xfa/fwl/cfwl_pushbutton.cpp
index a912108..7806399 100644
--- a/xfa/fwl/cfwl_pushbutton.cpp
+++ b/xfa/fwl/cfwl_pushbutton.cpp
@@ -18,11 +18,11 @@
 #include "xfa/fwl/cfwl_notedriver.h"
 #include "xfa/fwl/cfwl_themebackground.h"
 #include "xfa/fwl/cfwl_themetext.h"
+#include "xfa/fwl/fwl_widgetdef.h"
 #include "xfa/fwl/ifwl_themeprovider.h"
 
 CFWL_PushButton::CFWL_PushButton(const CFWL_App* app)
-    : CFWL_Widget(app, pdfium::MakeUnique<CFWL_WidgetProperties>(), nullptr),
-      m_bBtnDown(false) {}
+    : CFWL_Widget(app, pdfium::MakeUnique<CFWL_WidgetProperties>(), nullptr) {}
 
 CFWL_PushButton::~CFWL_PushButton() {}
 
@@ -52,14 +52,14 @@
                                  const CFX_Matrix& matrix) {
   if (!pGraphics)
     return;
-  if (!m_pProperties->m_pThemeProvider)
+
+  IFWL_ThemeProvider* pTheme = m_pProperties->m_pThemeProvider.Get();
+  if (!pTheme)
     return;
 
-  if (HasBorder()) {
-    DrawBorder(pGraphics, CFWL_Part::Border, m_pProperties->m_pThemeProvider,
-               matrix);
-  }
-  DrawBkground(pGraphics, m_pProperties->m_pThemeProvider, &matrix);
+  if (HasBorder())
+    DrawBorder(pGraphics, CFWL_Part::Border, pTheme, matrix);
+  DrawBkground(pGraphics, pTheme, &matrix);
 }
 
 void CFWL_PushButton::DrawBkground(CXFA_Graphics* pGraphics,
@@ -74,8 +74,8 @@
     param.m_matrix.Concat(*pMatrix);
   param.m_rtPart = m_rtClient;
   if (m_pProperties->m_dwStates & FWL_WGTSTATE_Focused)
-    param.m_pData = &m_rtCaption;
-  pTheme->DrawBackground(&param);
+    param.m_pRtData = &m_rtCaption;
+  pTheme->DrawBackground(param);
 }
 
 uint32_t CFWL_PushButton::GetPartStates() {
@@ -133,7 +133,9 @@
     default:
       break;
   }
-  CFWL_Widget::OnProcessMessage(pMessage);
+  // Dst target could be |this|, continue only if not destroyed by above.
+  if (pMessage->GetDstTarget())
+    CFWL_Widget::OnProcessMessage(pMessage);
 }
 
 void CFWL_PushButton::OnDrawWidget(CXFA_Graphics* pGraphics,
@@ -151,9 +153,6 @@
 }
 
 void CFWL_PushButton::OnLButtonDown(CFWL_MessageMouse* pMsg) {
-  if ((m_pProperties->m_dwStates & FWL_WGTSTATE_Focused) == 0)
-    SetFocus(true);
-
   m_bBtnDown = true;
   m_pProperties->m_dwStates |= FWL_STATE_PSB_Hovered;
   m_pProperties->m_dwStates |= FWL_STATE_PSB_Pressed;
@@ -218,12 +217,14 @@
 }
 
 void CFWL_PushButton::OnKeyDown(CFWL_MessageKey* pMsg) {
-  if (pMsg->m_dwKeyCode != FWL_VKEY_Return)
+  if (pMsg->m_dwKeyCode != XFA_FWL_VKEY_Return)
     return;
 
   CFWL_EventMouse wmMouse(this);
   wmMouse.m_dwCmd = FWL_MouseCommand::LeftButtonUp;
   DispatchEvent(&wmMouse);
+  if (!wmMouse.GetSrcTarget())
+    return;
 
   CFWL_Event wmClick(CFWL_Event::Type::Click, this);
   DispatchEvent(&wmClick);
diff --git a/xfa/fwl/cfwl_pushbutton.h b/xfa/fwl/cfwl_pushbutton.h
index 5c509fb..925dbb6 100644
--- a/xfa/fwl/cfwl_pushbutton.h
+++ b/xfa/fwl/cfwl_pushbutton.h
@@ -7,8 +7,6 @@
 #ifndef XFA_FWL_CFWL_PUSHBUTTON_H_
 #define XFA_FWL_CFWL_PUSHBUTTON_H_
 
-#include <memory>
-
 #include "xfa/fwl/cfwl_widget.h"
 #include "xfa/fwl/cfwl_widgetproperties.h"
 
@@ -19,7 +17,7 @@
 class CFX_DIBitmap;
 class CFWL_Widget;
 
-class CFWL_PushButton : public CFWL_Widget {
+class CFWL_PushButton final : public CFWL_Widget {
  public:
   explicit CFWL_PushButton(const CFWL_App*);
   ~CFWL_PushButton() override;
@@ -46,9 +44,9 @@
   void OnMouseLeave(CFWL_MessageMouse* pMsg);
   void OnKeyDown(CFWL_MessageKey* pMsg);
 
+  bool m_bBtnDown = false;
   CFX_RectF m_rtClient;
   CFX_RectF m_rtCaption;
-  bool m_bBtnDown;
 };
 
 #endif  // XFA_FWL_CFWL_PUSHBUTTON_H_
diff --git a/xfa/fwl/cfwl_scrollbar.cpp b/xfa/fwl/cfwl_scrollbar.cpp
index f723124..acc144f 100644
--- a/xfa/fwl/cfwl_scrollbar.cpp
+++ b/xfa/fwl/cfwl_scrollbar.cpp
@@ -12,12 +12,12 @@
 
 #include "third_party/base/ptr_util.h"
 #include "third_party/base/stl_util.h"
+#include "xfa/fwl/cfwl_app.h"
 #include "xfa/fwl/cfwl_messagemouse.h"
 #include "xfa/fwl/cfwl_messagemousewheel.h"
 #include "xfa/fwl/cfwl_notedriver.h"
 #include "xfa/fwl/cfwl_themebackground.h"
 #include "xfa/fwl/cfwl_themepart.h"
-#include "xfa/fwl/cfwl_timerinfo.h"
 #include "xfa/fwl/ifwl_themeprovider.h"
 
 #define FWL_SCROLLBAR_Elapse 500
@@ -32,34 +32,9 @@
     const CFWL_App* app,
     std::unique_ptr<CFWL_WidgetProperties> properties,
     CFWL_Widget* pOuter)
-    : CFWL_Widget(app, std::move(properties), pOuter),
-      m_pTimerInfo(nullptr),
-      m_fRangeMin(0),
-      m_fRangeMax(-1),
-      m_fPageSize(0),
-      m_fStepSize(0),
-      m_fPos(0),
-      m_fTrackPos(0),
-      m_iMinButtonState(CFWL_PartState_Normal),
-      m_iMaxButtonState(CFWL_PartState_Normal),
-      m_iThumbButtonState(CFWL_PartState_Normal),
-      m_iMinTrackState(CFWL_PartState_Normal),
-      m_iMaxTrackState(CFWL_PartState_Normal),
-      m_fLastTrackPos(0),
-      m_iMouseWheel(0),
-      m_bMouseDown(false),
-      m_fButtonLen(0),
-      m_bMinSize(false),
-      m_Timer(this) {
-  m_rtClient.Reset();
-  m_rtThumb.Reset();
-  m_rtMinBtn.Reset();
-  m_rtMaxBtn.Reset();
-  m_rtMinTrack.Reset();
-  m_rtMaxTrack.Reset();
-}
+    : CFWL_Widget(app, std::move(properties), pOuter) {}
 
-CFWL_ScrollBar::~CFWL_ScrollBar() {}
+CFWL_ScrollBar::~CFWL_ScrollBar() = default;
 
 FWL_Type CFWL_ScrollBar::GetClassID() const {
   return FWL_Type::ScrollBar;
@@ -81,7 +56,7 @@
   if (!m_pProperties->m_pThemeProvider)
     return;
 
-  IFWL_ThemeProvider* pTheme = m_pProperties->m_pThemeProvider;
+  IFWL_ThemeProvider* pTheme = m_pProperties->m_pThemeProvider.Get();
   if (HasBorder())
     DrawBorder(pGraphics, CFWL_Part::Border, pTheme, matrix);
   DrawTrack(pGraphics, pTheme, true, &matrix);
@@ -117,7 +92,7 @@
   param.m_pGraphics = pGraphics;
   param.m_matrix.Concat(*pMatrix);
   param.m_rtPart = bLower ? m_rtMinTrack : m_rtMaxTrack;
-  pTheme->DrawBackground(&param);
+  pTheme->DrawBackground(param);
 }
 
 void CFWL_ScrollBar::DrawArrowBtn(CXFA_Graphics* pGraphics,
@@ -134,7 +109,7 @@
   param.m_matrix.Concat(*pMatrix);
   param.m_rtPart = bMinBtn ? m_rtMinBtn : m_rtMaxBtn;
   if (param.m_rtPart.height > 0 && param.m_rtPart.width > 0)
-    pTheme->DrawBackground(&param);
+    pTheme->DrawBackground(param);
 }
 
 void CFWL_ScrollBar::DrawThumb(CXFA_Graphics* pGraphics,
@@ -149,7 +124,7 @@
   param.m_pGraphics = pGraphics;
   param.m_matrix.Concat(*pMatrix);
   param.m_rtPart = m_rtThumb;
-  pTheme->DrawBackground(&param);
+  pTheme->DrawBackground(param);
 }
 
 void CFWL_ScrollBar::Layout() {
@@ -380,12 +355,15 @@
   else
     DoMouseDown(4, m_rtMaxTrack, m_iMaxTrackState, point);
 
-  if (!SendEvent())
-    m_pTimerInfo = m_Timer.StartTimer(FWL_SCROLLBAR_Elapse, true);
+  if (!SendEvent()) {
+    m_pTimer = pdfium::MakeUnique<CFX_Timer>(
+        GetOwnerApp()->GetAdapterNative()->GetTimerHandler(), this,
+        FWL_SCROLLBAR_Elapse);
+  }
 }
 
 void CFWL_ScrollBar::OnLButtonUp(const CFX_PointF& point) {
-  m_pTimerInfo->StopTimer();
+  m_pTimer.reset();
   m_bMouseDown = false;
   DoMouseUp(0, m_rtMinBtn, m_iMinButtonState, point);
   DoMouseUp(1, m_rtThumb, m_iThumbButtonState, point);
@@ -482,13 +460,10 @@
   RepaintRect(rtItem);
 }
 
-CFWL_ScrollBar::Timer::Timer(CFWL_ScrollBar* pToolTip) : CFWL_Timer(pToolTip) {}
-
-void CFWL_ScrollBar::Timer::Run(CFWL_TimerInfo* pTimerInfo) {
-  CFWL_ScrollBar* pButton = static_cast<CFWL_ScrollBar*>(m_pWidget.Get());
-  if (pButton->m_pTimerInfo)
-    pButton->m_pTimerInfo->StopTimer();
-
-  if (!pButton->SendEvent())
-    pButton->m_pTimerInfo = StartTimer(0, true);
+void CFWL_ScrollBar::OnTimerFired() {
+  m_pTimer.reset();
+  if (!SendEvent()) {
+    m_pTimer = pdfium::MakeUnique<CFX_Timer>(
+        GetOwnerApp()->GetAdapterNative()->GetTimerHandler(), this, 0);
+  }
 }
diff --git a/xfa/fwl/cfwl_scrollbar.h b/xfa/fwl/cfwl_scrollbar.h
index b2523a6..c98479d 100644
--- a/xfa/fwl/cfwl_scrollbar.h
+++ b/xfa/fwl/cfwl_scrollbar.h
@@ -9,9 +9,10 @@
 
 #include <memory>
 
+#include "core/fxcrt/cfx_timer.h"
 #include "core/fxcrt/fx_system.h"
+#include "core/fxcrt/unowned_ptr.h"
 #include "xfa/fwl/cfwl_eventscroll.h"
-#include "xfa/fwl/cfwl_timer.h"
 #include "xfa/fwl/cfwl_widget.h"
 #include "xfa/fwl/cfwl_widgetproperties.h"
 
@@ -20,14 +21,15 @@
 #define FWL_STYLEEXT_SCB_Horz (0L << 0)
 #define FWL_STYLEEXT_SCB_Vert (1L << 0)
 
-class CFWL_ScrollBar : public CFWL_Widget {
+class CFWL_ScrollBar final : public CFWL_Widget,
+                             public CFX_Timer::CallbackIface {
  public:
   CFWL_ScrollBar(const CFWL_App* app,
                  std::unique_ptr<CFWL_WidgetProperties> properties,
                  CFWL_Widget* pOuter);
   ~CFWL_ScrollBar() override;
 
-  // CFWL_Widget
+  // CFWL_Widget:
   FWL_Type GetClassID() const override;
   void Update() override;
   void DrawWidget(CXFA_Graphics* pGraphics, const CFX_Matrix& matrix) override;
@@ -35,6 +37,9 @@
   void OnDrawWidget(CXFA_Graphics* pGraphics,
                     const CFX_Matrix& matrix) override;
 
+  // CFX_Timer::CallbackIface:
+  void OnTimerFired() override;
+
   void GetRange(float* fMin, float* fMax) const {
     ASSERT(fMin);
     ASSERT(fMax);
@@ -54,15 +59,6 @@
   void SetTrackPos(float fTrackPos);
 
  private:
-  class Timer : public CFWL_Timer {
-   public:
-    explicit Timer(CFWL_ScrollBar* pToolTip);
-    ~Timer() override {}
-
-    void Run(CFWL_TimerInfo* pTimerInfo) override;
-  };
-  friend class CFWL_ScrollBar::Timer;
-
   bool IsVertical() const {
     return !!(m_pProperties->m_dwStyleExes & FWL_STYLEEXT_SCB_Vert);
   }
@@ -109,31 +105,30 @@
   void DoMouseLeave(int32_t iItem, const CFX_RectF& rtItem, int32_t& iState);
   void DoMouseHover(int32_t iItem, const CFX_RectF& rtItem, int32_t& iState);
 
-  CFWL_TimerInfo* m_pTimerInfo;
-  float m_fRangeMin;
-  float m_fRangeMax;
-  float m_fPageSize;
-  float m_fStepSize;
-  float m_fPos;
-  float m_fTrackPos;
-  int32_t m_iMinButtonState;
-  int32_t m_iMaxButtonState;
-  int32_t m_iThumbButtonState;
-  int32_t m_iMinTrackState;
-  int32_t m_iMaxTrackState;
-  float m_fLastTrackPos;
+  float m_fRangeMin = 0.0f;
+  float m_fRangeMax = -1.0f;
+  float m_fPageSize = 0.0f;
+  float m_fStepSize = 0.0f;
+  float m_fPos = 0.0f;
+  float m_fTrackPos = 0.0f;
+  int32_t m_iMinButtonState = CFWL_PartState_Normal;
+  int32_t m_iMaxButtonState = CFWL_PartState_Normal;
+  int32_t m_iThumbButtonState = CFWL_PartState_Normal;
+  int32_t m_iMinTrackState = CFWL_PartState_Normal;
+  int32_t m_iMaxTrackState = CFWL_PartState_Normal;
+  float m_fLastTrackPos = 0.0f;
   CFX_PointF m_cpTrackPoint;
-  int32_t m_iMouseWheel;
-  bool m_bMouseDown;
-  float m_fButtonLen;
-  bool m_bMinSize;
+  int32_t m_iMouseWheel = 0;
+  float m_fButtonLen = 0.0f;
+  bool m_bMouseDown = false;
+  bool m_bMinSize = false;
   CFX_RectF m_rtClient;
   CFX_RectF m_rtThumb;
   CFX_RectF m_rtMinBtn;
   CFX_RectF m_rtMaxBtn;
   CFX_RectF m_rtMinTrack;
   CFX_RectF m_rtMaxTrack;
-  CFWL_ScrollBar::Timer m_Timer;
+  std::unique_ptr<CFX_Timer> m_pTimer;
 };
 
 #endif  // XFA_FWL_CFWL_SCROLLBAR_H_
diff --git a/xfa/fwl/cfwl_themebackground.h b/xfa/fwl/cfwl_themebackground.h
index 85435aa..46df73c 100644
--- a/xfa/fwl/cfwl_themebackground.h
+++ b/xfa/fwl/cfwl_themebackground.h
@@ -7,23 +7,23 @@
 #ifndef XFA_FWL_CFWL_THEMEBACKGROUND_H_
 #define XFA_FWL_CFWL_THEMEBACKGROUND_H_
 
+#include "core/fxcrt/unowned_ptr.h"
 #include "xfa/fwl/cfwl_themepart.h"
 
 class CXFA_Graphics;
 class CXFA_GEPath;
 
-class CFWL_ThemeBackground : public CFWL_ThemePart {
+class CFWL_ThemeBackground final : public CFWL_ThemePart {
  public:
   CFWL_ThemeBackground();
   ~CFWL_ThemeBackground();
 
-  CXFA_Graphics* m_pGraphics;
-  CXFA_GEPath* m_pPath;
+  UnownedPtr<CXFA_Graphics> m_pGraphics;
+  UnownedPtr<CXFA_GEPath> m_pPath;
 };
 
-inline CFWL_ThemeBackground::CFWL_ThemeBackground()
-    : m_pGraphics(nullptr), m_pPath(nullptr) {}
+inline CFWL_ThemeBackground::CFWL_ThemeBackground() = default;
 
-inline CFWL_ThemeBackground::~CFWL_ThemeBackground() {}
+inline CFWL_ThemeBackground::~CFWL_ThemeBackground() = default;
 
 #endif  // XFA_FWL_CFWL_THEMEBACKGROUND_H_
diff --git a/xfa/fwl/cfwl_themepart.cpp b/xfa/fwl/cfwl_themepart.cpp
index 25592f3..831e494 100644
--- a/xfa/fwl/cfwl_themepart.cpp
+++ b/xfa/fwl/cfwl_themepart.cpp
@@ -12,7 +12,4 @@
       m_dwStates(CFWL_PartState_Normal),
       m_bMaximize(false),
       m_bStaticBackground(false),
-      m_pData(nullptr) {
-  m_rtPart.Reset();
-  m_matrix.SetIdentity();
-}
+      m_pRtData(nullptr) {}
diff --git a/xfa/fwl/cfwl_themepart.h b/xfa/fwl/cfwl_themepart.h
index 1bb87e9..46be205 100644
--- a/xfa/fwl/cfwl_themepart.h
+++ b/xfa/fwl/cfwl_themepart.h
@@ -40,7 +40,6 @@
   MaximizeBox,
   NarrowCaption,
   RBtn,
-  StretchHandler,
   Thumb,
   ThumbBackArrow,
   ThumbForeArrow,
@@ -88,7 +87,7 @@
   uint32_t m_dwStates;
   bool m_bMaximize;
   bool m_bStaticBackground;
-  void* m_pData;
+  CFX_RectF* m_pRtData;
 };
 
 #endif  // XFA_FWL_CFWL_THEMEPART_H_
diff --git a/xfa/fwl/cfwl_themetext.h b/xfa/fwl/cfwl_themetext.h
index 91a3f38..f0cfaa7 100644
--- a/xfa/fwl/cfwl_themetext.h
+++ b/xfa/fwl/cfwl_themetext.h
@@ -11,14 +11,14 @@
 #include "core/fxcrt/fx_system.h"
 #include "xfa/fwl/cfwl_themepart.h"
 
-class CFWL_ThemeText : public CFWL_ThemePart {
+class CFWL_ThemeText final : public CFWL_ThemePart {
  public:
-  CFWL_ThemeText() : m_pGraphics(nullptr) {}
+  CFWL_ThemeText() = default;
 
+  FDE_TextAlignment m_iTTOAlign = FDE_TextAlignment::kTopLeft;
+  CXFA_Graphics* m_pGraphics = nullptr;
   WideString m_wsText;
   FDE_TextStyle m_dwTTOStyles;
-  FDE_TextAlignment m_iTTOAlign;
-  CXFA_Graphics* m_pGraphics;
 };
 
 #endif  // XFA_FWL_CFWL_THEMETEXT_H_
diff --git a/xfa/fwl/cfwl_timer.cpp b/xfa/fwl/cfwl_timer.cpp
deleted file mode 100644
index 2734e49..0000000
--- a/xfa/fwl/cfwl_timer.cpp
+++ /dev/null
@@ -1,35 +0,0 @@
-// Copyright 2014 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
-
-#include "xfa/fwl/cfwl_timer.h"
-
-#include "xfa/fwl/cfwl_app.h"
-#include "xfa/fwl/cfwl_timerinfo.h"
-#include "xfa/fwl/cfwl_widget.h"
-#include "xfa/fwl/ifwl_adaptertimermgr.h"
-#include "xfa/fxfa/cxfa_ffapp.h"
-
-CFWL_Timer::CFWL_Timer(CFWL_Widget* parent) : m_pWidget(parent) {}
-
-CFWL_Timer::~CFWL_Timer() {}
-
-CFWL_TimerInfo* CFWL_Timer::StartTimer(uint32_t dwElapse, bool bImmediately) {
-  const CFWL_App* pApp = m_pWidget->GetOwnerApp();
-  if (!pApp)
-    return nullptr;
-
-  CXFA_FFApp* pAdapterNative = pApp->GetAdapterNative();
-  if (!pAdapterNative)
-    return nullptr;
-
-  IFWL_AdapterTimerMgr* pAdapterTimerMgr = pAdapterNative->GetTimerMgr();
-  if (!pAdapterTimerMgr)
-    return nullptr;
-
-  CFWL_TimerInfo* pTimerInfo = nullptr;
-  pAdapterTimerMgr->Start(this, dwElapse, bImmediately, &pTimerInfo);
-  return pTimerInfo;
-}
diff --git a/xfa/fwl/cfwl_timer.h b/xfa/fwl/cfwl_timer.h
deleted file mode 100644
index da1b443..0000000
--- a/xfa/fwl/cfwl_timer.h
+++ /dev/null
@@ -1,28 +0,0 @@
-// Copyright 2014 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_FWL_CFWL_TIMER_H_
-#define XFA_FWL_CFWL_TIMER_H_
-
-#include "core/fxcrt/fx_system.h"
-#include "core/fxcrt/unowned_ptr.h"
-
-class CFWL_TimerInfo;
-class CFWL_Widget;
-
-class CFWL_Timer {
- public:
-  explicit CFWL_Timer(CFWL_Widget* parent);
-  virtual ~CFWL_Timer();
-
-  virtual void Run(CFWL_TimerInfo* hTimer) = 0;
-  CFWL_TimerInfo* StartTimer(uint32_t dwElapse, bool bImmediately);
-
- protected:
-  UnownedPtr<CFWL_Widget> m_pWidget;
-};
-
-#endif  // XFA_FWL_CFWL_TIMER_H_
diff --git a/xfa/fwl/cfwl_timerinfo.cpp b/xfa/fwl/cfwl_timerinfo.cpp
deleted file mode 100644
index ee4746a..0000000
--- a/xfa/fwl/cfwl_timerinfo.cpp
+++ /dev/null
@@ -1,19 +0,0 @@
-// Copyright 2016 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
-
-#include "xfa/fwl/cfwl_timerinfo.h"
-
-#include "xfa/fwl/ifwl_adaptertimermgr.h"
-
-CFWL_TimerInfo::CFWL_TimerInfo(IFWL_AdapterTimerMgr* mgr) : m_pMgr(mgr) {
-  ASSERT(mgr);
-}
-
-CFWL_TimerInfo::~CFWL_TimerInfo() {}
-
-void CFWL_TimerInfo::StopTimer() {
-  m_pMgr->Stop(this);
-}
diff --git a/xfa/fwl/cfwl_timerinfo.h b/xfa/fwl/cfwl_timerinfo.h
deleted file mode 100644
index c58bcff..0000000
--- a/xfa/fwl/cfwl_timerinfo.h
+++ /dev/null
@@ -1,26 +0,0 @@
-// Copyright 2016 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_FWL_CFWL_TIMERINFO_H_
-#define XFA_FWL_CFWL_TIMERINFO_H_
-
-#include "core/fxcrt/fx_system.h"
-#include "core/fxcrt/unowned_ptr.h"
-
-class IFWL_AdapterTimerMgr;
-
-class CFWL_TimerInfo {
- public:
-  explicit CFWL_TimerInfo(IFWL_AdapterTimerMgr* mgr);
-  virtual ~CFWL_TimerInfo();
-
-  void StopTimer();
-
- private:
-  UnownedPtr<IFWL_AdapterTimerMgr> m_pMgr;
-};
-
-#endif  // XFA_FWL_CFWL_TIMERINFO_H_
diff --git a/xfa/fwl/cfwl_widget.cpp b/xfa/fwl/cfwl_widget.cpp
index b9b04cf..39b706b 100644
--- a/xfa/fwl/cfwl_widget.cpp
+++ b/xfa/fwl/cfwl_widget.cpp
@@ -16,7 +16,6 @@
 #include "xfa/fwl/cfwl_combobox.h"
 #include "xfa/fwl/cfwl_event.h"
 #include "xfa/fwl/cfwl_eventmouse.h"
-#include "xfa/fwl/cfwl_form.h"
 #include "xfa/fwl/cfwl_messagekey.h"
 #include "xfa/fwl/cfwl_messagekillfocus.h"
 #include "xfa/fwl/cfwl_messagemouse.h"
@@ -28,9 +27,7 @@
 #include "xfa/fwl/cfwl_themetext.h"
 #include "xfa/fwl/cfwl_widgetmgr.h"
 #include "xfa/fwl/ifwl_themeprovider.h"
-#include "xfa/fxfa/cxfa_ffapp.h"
 
-#define FWL_STYLEEXT_MNU_Vert (1L << 0)
 #define FWL_WGT_CalcHeight 2048
 #define FWL_WGT_CalcWidth 2048
 #define FWL_WGT_CalcMultiLineDefWidth 120.0f
@@ -41,29 +38,19 @@
     : m_pOwnerApp(app),
       m_pWidgetMgr(app->GetWidgetMgr()),
       m_pProperties(std::move(properties)),
-      m_pOuter(pOuter),
-      m_iLock(0),
-      m_pLayoutItem(nullptr),
-      m_nEventKey(0),
-      m_pDelegate(nullptr) {
+      m_pOuter(pOuter) {
   ASSERT(m_pWidgetMgr);
-
-  CFWL_Widget* pParent = m_pProperties->m_pParent;
-  m_pWidgetMgr->InsertWidget(pParent, this);
-  if (IsChild())
-    return;
-
-  CFWL_Widget* pOwner = m_pProperties->m_pOwner;
-  if (pOwner)
-    m_pWidgetMgr->SetOwner(pOwner, this);
+  ASSERT(m_pProperties);
+  m_pWidgetMgr->InsertWidget(m_pProperties->m_pParent, this);
 }
 
 CFWL_Widget::~CFWL_Widget() {
+  CHECK(!IsLocked());  // Prefer hard stop to UaF.
   NotifyDriver();
   m_pWidgetMgr->RemoveWidget(this);
 }
 
-bool CFWL_Widget::IsInstance(const WideStringView& wsClass) const {
+bool CFWL_Widget::IsForm() const {
   return false;
 }
 
@@ -76,10 +63,11 @@
 }
 
 void CFWL_Widget::InflateWidgetRect(CFX_RectF& rect) {
-  if (HasBorder()) {
-    float fBorder = GetBorderSize(true);
-    rect.Inflate(fBorder, fBorder);
-  }
+  if (!HasBorder())
+    return;
+
+  float fBorder = GetCXBorderSize();
+  rect.Inflate(fBorder, fBorder);
 }
 
 void CFWL_Widget::SetWidgetRect(const CFX_RectF& rect) {
@@ -95,10 +83,6 @@
   m_pWidgetMgr->SetParent(pParent, this);
 }
 
-uint32_t CFWL_Widget::GetStyles() const {
-  return m_pProperties->m_dwStyles;
-}
-
 void CFWL_Widget::ModifyStyles(uint32_t dwStylesAdded,
                                uint32_t dwStylesRemoved) {
   m_pProperties->m_dwStyles =
@@ -131,13 +115,13 @@
 
 void CFWL_Widget::SetStates(uint32_t dwStates) {
   m_pProperties->m_dwStates |= dwStates;
-  if (!(dwStates & FWL_WGTSTATE_Invisible))
+  if (IsVisible())
     return;
 
-  CFWL_NoteDriver* noteDriver =
-      static_cast<CFWL_NoteDriver*>(GetOwnerApp()->GetNoteDriver());
-  CFWL_WidgetMgr* widgetMgr = GetOwnerApp()->GetWidgetMgr();
+  CFWL_NoteDriver* noteDriver = GetOwnerApp()->GetNoteDriver();
   noteDriver->NotifyTargetHide(this);
+
+  CFWL_WidgetMgr* widgetMgr = GetOwnerApp()->GetWidgetMgr();
   CFWL_Widget* child = widgetMgr->GetFirstChildWidget(this);
   while (child) {
     noteDriver->NotifyTargetHide(child);
@@ -161,50 +145,18 @@
 
 CFX_PointF CFWL_Widget::TransformTo(CFWL_Widget* pWidget,
                                     const CFX_PointF& point) {
-  if (m_pWidgetMgr->IsFormDisabled()) {
-    CFX_SizeF szOffset;
-    if (IsParent(pWidget)) {
-      szOffset = GetOffsetFromParent(pWidget);
-    } else {
-      szOffset = pWidget->GetOffsetFromParent(this);
-      szOffset.width = -szOffset.width;
-      szOffset.height = -szOffset.height;
-    }
-    return point + CFX_PointF(szOffset.width, szOffset.height);
+  CFX_SizeF szOffset;
+  if (IsParent(pWidget)) {
+    szOffset = GetOffsetFromParent(pWidget);
+  } else {
+    szOffset = pWidget->GetOffsetFromParent(this);
+    szOffset.width = -szOffset.width;
+    szOffset.height = -szOffset.height;
   }
-
-  CFX_PointF ret = point;
-  CFWL_Widget* parent = GetParent();
-  if (parent)
-    ret = GetMatrix().Transform(ret + GetWidgetRect().TopLeft());
-
-  CFWL_Widget* form1 = m_pWidgetMgr->GetSystemFormWidget(this);
-  if (!form1)
-    return ret;
-
-  if (!pWidget)
-    return ret + form1->GetWidgetRect().TopLeft();
-
-  CFWL_Widget* form2 = m_pWidgetMgr->GetSystemFormWidget(pWidget);
-  if (!form2)
-    return ret;
-  if (form1 != form2) {
-    ret += form1->GetWidgetRect().TopLeft();
-    ret -= form2->GetWidgetRect().TopLeft();
-  }
-
-  parent = pWidget->GetParent();
-  if (!parent)
-    return ret;
-
-  return pWidget->GetMatrix().GetInverse().Transform(ret) -
-         pWidget->GetWidgetRect().TopLeft();
+  return point + CFX_PointF(szOffset.width, szOffset.height);
 }
 
-CFX_Matrix CFWL_Widget::GetMatrix() {
-  if (!m_pProperties)
-    return CFX_Matrix();
-
+CFX_Matrix CFWL_Widget::GetMatrix() const {
   CFWL_Widget* parent = GetParent();
   std::vector<CFWL_Widget*> parents;
   while (parent) {
@@ -213,28 +165,13 @@
   }
 
   CFX_Matrix matrix;
-  CFX_Matrix ctmOnParent;
-  CFX_RectF rect;
-  int32_t count = pdfium::CollectionSize<int32_t>(parents);
-  for (int32_t i = count - 2; i >= 0; i--) {
-    parent = parents[i];
-    if (parent->m_pProperties)
-      ctmOnParent.SetIdentity();
-    rect = parent->GetWidgetRect();
-    matrix.Concat(ctmOnParent, true);
-    matrix.Translate(rect.left, rect.top, true);
+  for (size_t i = parents.size(); i >= 2; i--) {
+    CFX_RectF rect = parents[i - 2]->GetWidgetRect();
+    matrix.TranslatePrepend(rect.left, rect.top);
   }
-  CFX_Matrix m;
-  m.SetIdentity();
-  matrix.Concat(m, true);
-  parents.clear();
   return matrix;
 }
 
-IFWL_ThemeProvider* CFWL_Widget::GetThemeProvider() const {
-  return m_pProperties->m_pThemeProvider;
-}
-
 void CFWL_Widget::SetThemeProvider(IFWL_ThemeProvider* pThemeProvider) {
   m_pProperties->m_pThemeProvider = pThemeProvider;
 }
@@ -248,7 +185,7 @@
 }
 
 bool CFWL_Widget::IsVisible() const {
-  return (m_pProperties->m_dwStates & FWL_WGTSTATE_Invisible) == 0;
+  return !(m_pProperties->m_dwStates & FWL_WGTSTATE_Invisible);
 }
 
 bool CFWL_Widget::IsOverLapper() const {
@@ -264,38 +201,44 @@
   return !!(m_pProperties->m_dwStyles & FWL_WGTSTYLE_Child);
 }
 
-CFX_RectF CFWL_Widget::GetEdgeRect() {
+CFWL_Widget* CFWL_Widget::GetOutmost() const {
+  CFWL_Widget* pOuter = const_cast<CFWL_Widget*>(this);
+  while (pOuter->GetOuter())
+    pOuter = pOuter->GetOuter();
+  return pOuter;
+}
+
+CFX_RectF CFWL_Widget::GetEdgeRect() const {
   CFX_RectF rtEdge(0, 0, m_pProperties->m_rtWidget.width,
                    m_pProperties->m_rtWidget.height);
-  if (HasBorder()) {
-    float fCX = GetBorderSize(true);
-    float fCY = GetBorderSize(false);
-    rtEdge.Deflate(fCX, fCY);
-  }
+  if (HasBorder())
+    rtEdge.Deflate(GetCXBorderSize(), GetCYBorderSize());
   return rtEdge;
 }
 
-float CFWL_Widget::GetBorderSize(bool bCX) {
+float CFWL_Widget::GetCXBorderSize() const {
   IFWL_ThemeProvider* theme = GetAvailableTheme();
-  if (!theme)
-    return 0.0f;
-  return bCX ? theme->GetCXBorderSize() : theme->GetCYBorderSize();
+  return theme ? theme->GetCXBorderSize() : 0.0f;
 }
 
-CFX_RectF CFWL_Widget::GetRelativeRect() {
+float CFWL_Widget::GetCYBorderSize() const {
+  IFWL_ThemeProvider* theme = GetAvailableTheme();
+  return theme ? theme->GetCYBorderSize() : 0.0f;
+}
+
+CFX_RectF CFWL_Widget::GetRelativeRect() const {
   return CFX_RectF(0, 0, m_pProperties->m_rtWidget.width,
                    m_pProperties->m_rtWidget.height);
 }
 
-IFWL_ThemeProvider* CFWL_Widget::GetAvailableTheme() {
+IFWL_ThemeProvider* CFWL_Widget::GetAvailableTheme() const {
   if (m_pProperties->m_pThemeProvider)
-    return m_pProperties->m_pThemeProvider;
+    return m_pProperties->m_pThemeProvider.Get();
 
-  CFWL_Widget* pUp = this;
+  const CFWL_Widget* pUp = this;
   do {
-    pUp = (pUp->GetStyles() & FWL_WGTSTYLE_Popup)
-              ? m_pWidgetMgr->GetOwnerWidget(pUp)
-              : m_pWidgetMgr->GetParentWidget(pUp);
+    pUp = pUp->IsPopup() ? m_pWidgetMgr->GetOwnerWidget(pUp)
+                         : m_pWidgetMgr->GetParentWidget(pUp);
     if (pUp) {
       IFWL_ThemeProvider* pRet = pUp->GetThemeProvider();
       if (pRet)
@@ -305,16 +248,6 @@
   return nullptr;
 }
 
-CFWL_Widget* CFWL_Widget::GetRootOuter() {
-  CFWL_Widget* pRet = m_pOuter;
-  if (!pRet)
-    return nullptr;
-
-  while (CFWL_Widget* pOuter = pRet->GetOuter())
-    pRet = pOuter;
-  return pRet;
-}
-
 CFX_SizeF CFWL_Widget::CalcTextSize(const WideString& wsText,
                                     IFWL_ThemeProvider* pTheme,
                                     bool bMultiLine) {
@@ -332,7 +265,7 @@
   calPart.m_iTTOAlign = FDE_TextAlignment::kTopLeft;
   float fWidth = bMultiLine ? FWL_WGT_CalcMultiLineDefWidth : FWL_WGT_CalcWidth;
   CFX_RectF rect(0, 0, fWidth, FWL_WGT_CalcHeight);
-  pTheme->CalcTextRect(&calPart, rect);
+  pTheme->CalcTextRect(calPart, &rect);
   return CFX_SizeF(rect.width, rect.height);
 }
 
@@ -340,160 +273,27 @@
                                IFWL_ThemeProvider* pTheme,
                                const FDE_TextStyle& dwTTOStyles,
                                FDE_TextAlignment iTTOAlign,
-                               CFX_RectF& rect) {
+                               CFX_RectF* pRect) {
   CFWL_ThemeText calPart;
   calPart.m_pWidget = this;
   calPart.m_wsText = wsText;
   calPart.m_dwTTOStyles = dwTTOStyles;
   calPart.m_iTTOAlign = iTTOAlign;
-  pTheme->CalcTextRect(&calPart, rect);
-}
-
-void CFWL_Widget::SetFocus(bool bFocus) {
-  if (m_pWidgetMgr->IsFormDisabled())
-    return;
-
-  const CFWL_App* pApp = GetOwnerApp();
-  if (!pApp)
-    return;
-
-  CFWL_NoteDriver* pDriver =
-      static_cast<CFWL_NoteDriver*>(pApp->GetNoteDriver());
-  if (!pDriver)
-    return;
-
-  CFWL_Widget* curFocus = pDriver->GetFocus();
-  if (bFocus && curFocus != this)
-    pDriver->SetFocus(this);
-  else if (!bFocus && curFocus == this)
-    pDriver->SetFocus(nullptr);
+  pTheme->CalcTextRect(calPart, pRect);
 }
 
 void CFWL_Widget::SetGrab(bool bSet) {
-  const CFWL_App* pApp = GetOwnerApp();
-  if (!pApp)
-    return;
-
-  CFWL_NoteDriver* pDriver =
-      static_cast<CFWL_NoteDriver*>(pApp->GetNoteDriver());
+  CFWL_NoteDriver* pDriver = GetOwnerApp()->GetNoteDriver();
   pDriver->SetGrab(this, bSet);
 }
 
-void CFWL_Widget::GetPopupPos(float fMinHeight,
-                              float fMaxHeight,
-                              const CFX_RectF& rtAnchor,
-                              CFX_RectF& rtPopup) {
-  if (GetClassID() == FWL_Type::ComboBox) {
-    if (m_pWidgetMgr->IsFormDisabled()) {
-      m_pWidgetMgr->GetAdapterPopupPos(this, fMinHeight, fMaxHeight, rtAnchor,
-                                       rtPopup);
-      return;
-    }
-    GetPopupPosComboBox(fMinHeight, fMaxHeight, rtAnchor, rtPopup);
-    return;
-  }
-  if (GetClassID() == FWL_Type::DateTimePicker &&
-      m_pWidgetMgr->IsFormDisabled()) {
-    m_pWidgetMgr->GetAdapterPopupPos(this, fMinHeight, fMaxHeight, rtAnchor,
-                                     rtPopup);
-    return;
-  }
-  GetPopupPosGeneral(fMinHeight, fMaxHeight, rtAnchor, rtPopup);
-}
-
-bool CFWL_Widget::GetPopupPosMenu(float fMinHeight,
-                                  float fMaxHeight,
-                                  const CFX_RectF& rtAnchor,
-                                  CFX_RectF& rtPopup) {
-  if (GetStylesEx() & FWL_STYLEEXT_MNU_Vert) {
-    bool bLeft = m_pProperties->m_rtWidget.left < 0;
-    float fRight = rtAnchor.right() + rtPopup.width;
-    CFX_PointF point = TransformTo(nullptr, CFX_PointF());
-    if (fRight + point.x > 0.0f || bLeft) {
-      rtPopup = CFX_RectF(rtAnchor.left - rtPopup.width, rtAnchor.top,
-                          rtPopup.width, rtPopup.height);
-    } else {
-      rtPopup = CFX_RectF(rtAnchor.right(), rtAnchor.top, rtPopup.width,
-                          rtPopup.height);
-    }
-    rtPopup.Offset(point.x, point.y);
-    return true;
-  }
-
-  float fBottom = rtAnchor.bottom() + rtPopup.height;
-  CFX_PointF point = TransformTo(nullptr, point);
-  if (fBottom + point.y > 0.0f) {
-    rtPopup = CFX_RectF(rtAnchor.left, rtAnchor.top - rtPopup.height,
-                        rtPopup.width, rtPopup.height);
-  } else {
-    rtPopup = CFX_RectF(rtAnchor.left, rtAnchor.bottom(), rtPopup.width,
-                        rtPopup.height);
-  }
-  rtPopup.Offset(point.x, point.y);
-  return true;
-}
-
-bool CFWL_Widget::GetPopupPosComboBox(float fMinHeight,
-                                      float fMaxHeight,
-                                      const CFX_RectF& rtAnchor,
-                                      CFX_RectF& rtPopup) {
-  float fPopHeight = rtPopup.height;
-  if (rtPopup.height > fMaxHeight)
-    fPopHeight = fMaxHeight;
-  else if (rtPopup.height < fMinHeight)
-    fPopHeight = fMinHeight;
-
-  float fWidth = std::max(rtAnchor.width, rtPopup.width);
-  float fBottom = rtAnchor.bottom() + fPopHeight;
-  CFX_PointF point = TransformTo(nullptr, CFX_PointF());
-  if (fBottom + point.y > 0.0f) {
-    rtPopup =
-        CFX_RectF(rtAnchor.left, rtAnchor.top - fPopHeight, fWidth, fPopHeight);
-  } else {
-    rtPopup = CFX_RectF(rtAnchor.left, rtAnchor.bottom(), fWidth, fPopHeight);
-  }
-
-  rtPopup.Offset(point.x, point.y);
-  return true;
-}
-
-bool CFWL_Widget::GetPopupPosGeneral(float fMinHeight,
-                                     float fMaxHeight,
-                                     const CFX_RectF& rtAnchor,
-                                     CFX_RectF& rtPopup) {
-  CFX_PointF point = TransformTo(nullptr, CFX_PointF());
-  if (rtAnchor.bottom() + point.y > 0.0f) {
-    rtPopup = CFX_RectF(rtAnchor.left, rtAnchor.top - rtPopup.height,
-                        rtPopup.width, rtPopup.height);
-  } else {
-    rtPopup = CFX_RectF(rtAnchor.left, rtAnchor.bottom(), rtPopup.width,
-                        rtPopup.height);
-  }
-  rtPopup.Offset(point.x, point.y);
-  return true;
-}
-
 void CFWL_Widget::RegisterEventTarget(CFWL_Widget* pEventSource) {
-  const CFWL_App* pApp = GetOwnerApp();
-  if (!pApp)
-    return;
-
-  CFWL_NoteDriver* pNoteDriver = pApp->GetNoteDriver();
-  if (!pNoteDriver)
-    return;
-
+  CFWL_NoteDriver* pNoteDriver = GetOwnerApp()->GetNoteDriver();
   pNoteDriver->RegisterEventTarget(this, pEventSource);
 }
 
 void CFWL_Widget::UnregisterEventTarget() {
-  const CFWL_App* pApp = GetOwnerApp();
-  if (!pApp)
-    return;
-
-  CFWL_NoteDriver* pNoteDriver = pApp->GetNoteDriver();
-  if (!pNoteDriver)
-    return;
-
+  CFWL_NoteDriver* pNoteDriver = GetOwnerApp()->GetNoteDriver();
   pNoteDriver->UnregisterEventTarget(this);
 }
 
@@ -502,21 +302,10 @@
     m_pOuter->GetDelegate()->OnProcessEvent(pEvent);
     return;
   }
-  const CFWL_App* pApp = GetOwnerApp();
-  if (!pApp)
-    return;
-
-  CFWL_NoteDriver* pNoteDriver = pApp->GetNoteDriver();
-  if (!pNoteDriver)
-    return;
+  CFWL_NoteDriver* pNoteDriver = GetOwnerApp()->GetNoteDriver();
   pNoteDriver->SendEvent(pEvent);
 }
 
-void CFWL_Widget::Repaint() {
-  RepaintRect(CFX_RectF(0, 0, m_pProperties->m_rtWidget.width,
-                        m_pProperties->m_rtWidget.height));
-}
-
 void CFWL_Widget::RepaintRect(const CFX_RectF& pRect) {
   m_pWidgetMgr->RepaintWidget(this, pRect);
 }
@@ -530,9 +319,9 @@
   param.m_iPart = iPartBk;
   param.m_pGraphics = pGraphics;
   if (pMatrix)
-    param.m_matrix.Concat(*pMatrix, true);
+    param.m_matrix = *pMatrix;
   param.m_rtPart = GetRelativeRect();
-  pTheme->DrawBackground(&param);
+  pTheme->DrawBackground(param);
 }
 
 void CFWL_Widget::DrawBorder(CXFA_Graphics* pGraphics,
@@ -543,21 +332,13 @@
   param.m_pWidget = this;
   param.m_iPart = iPartBorder;
   param.m_pGraphics = pGraphics;
-  param.m_matrix.Concat(matrix, true);
+  param.m_matrix = matrix;
   param.m_rtPart = GetRelativeRect();
-  pTheme->DrawBackground(&param);
+  pTheme->DrawBackground(param);
 }
 
 void CFWL_Widget::NotifyDriver() {
-  const CFWL_App* pApp = GetOwnerApp();
-  if (!pApp)
-    return;
-
-  CFWL_NoteDriver* pDriver =
-      static_cast<CFWL_NoteDriver*>(pApp->GetNoteDriver());
-  if (!pDriver)
-    return;
-
+  CFWL_NoteDriver* pDriver = GetOwnerApp()->GetNoteDriver();
   pDriver->NotifyTargetDestroy(this);
 }
 
@@ -566,9 +347,6 @@
     return CFX_SizeF();
 
   CFWL_WidgetMgr* pWidgetMgr = GetOwnerApp()->GetWidgetMgr();
-  if (!pWidgetMgr)
-    return CFX_SizeF();
-
   CFX_SizeF szRet(m_pProperties->m_rtWidget.left,
                   m_pProperties->m_rtWidget.top);
 
@@ -592,14 +370,13 @@
 }
 
 void CFWL_Widget::OnProcessMessage(CFWL_Message* pMessage) {
-  if (!pMessage->m_pDstTarget)
+  CFWL_Widget* pWidget = pMessage->GetDstTarget();
+  if (!pWidget)
     return;
 
-  CFWL_Widget* pWidget = pMessage->m_pDstTarget;
   switch (pMessage->GetType()) {
     case CFWL_Message::Type::Mouse: {
       CFWL_MessageMouse* pMsgMouse = static_cast<CFWL_MessageMouse*>(pMessage);
-
       CFWL_EventMouse evt(pWidget, pWidget);
       evt.m_dwCmd = pMsgMouse->m_dwCmd;
       pWidget->DispatchEvent(&evt);
@@ -614,3 +391,12 @@
 
 void CFWL_Widget::OnDrawWidget(CXFA_Graphics* pGraphics,
                                const CFX_Matrix& matrix) {}
+
+CFWL_Widget::ScopedUpdateLock::ScopedUpdateLock(CFWL_Widget* widget)
+    : widget_(widget) {
+  widget_->LockUpdate();
+}
+
+CFWL_Widget::ScopedUpdateLock::~ScopedUpdateLock() {
+  widget_->UnlockUpdate();
+}
diff --git a/xfa/fwl/cfwl_widget.h b/xfa/fwl/cfwl_widget.h
index 27cb458..a8112e8 100644
--- a/xfa/fwl/cfwl_widget.h
+++ b/xfa/fwl/cfwl_widget.h
@@ -11,14 +11,23 @@
 
 #include "core/fxcrt/fx_coordinates.h"
 #include "core/fxcrt/fx_system.h"
+#include "core/fxcrt/observed_ptr.h"
 #include "core/fxcrt/unowned_ptr.h"
 #include "xfa/fde/cfde_data.h"
-#include "xfa/fwl/cfwl_event.h"
 #include "xfa/fwl/cfwl_themepart.h"
 #include "xfa/fwl/cfwl_widgetmgr.h"
+#include "xfa/fwl/cfwl_widgetproperties.h"
 #include "xfa/fwl/fwl_widgethit.h"
 #include "xfa/fwl/ifwl_widgetdelegate.h"
 
+class CFWL_App;
+class CFWL_AppImp;
+class CFWL_Event;
+class CFWL_MessageKey;
+class CFWL_Widget;
+class CFWL_WidgetMgr;
+class IFWL_ThemeProvider;
+
 enum class FWL_Type {
   Unknown = 0,
 
@@ -39,21 +48,30 @@
   ToolTip
 };
 
-class CFWL_App;
-class CFWL_AppImp;
-class CFWL_MessageKey;
-class CFWL_Widget;
-class CFWL_WidgetMgr;
-class CFWL_WidgetProperties;
-class CXFA_FFWidget;
-class IFWL_ThemeProvider;
-
-class CFWL_Widget : public IFWL_WidgetDelegate {
+// NOTE: CFWL_Widget serves as its own delegate until replaced at runtime.
+class CFWL_Widget : public Observable, public IFWL_WidgetDelegate {
  public:
+  class AdapterIface {
+   public:
+    virtual ~AdapterIface() {}
+    virtual CFX_Matrix GetRotateMatrix() = 0;
+    virtual void DisplayCaret(bool bVisible, const CFX_RectF* pRtAnchor) = 0;
+    virtual void GetBorderColorAndThickness(FX_ARGB* cr, float* fWidth) = 0;
+  };
+
+  class ScopedUpdateLock {
+   public:
+    explicit ScopedUpdateLock(CFWL_Widget* widget);
+    ~ScopedUpdateLock();
+
+   private:
+    UnownedPtr<CFWL_Widget> const widget_;
+  };
+
   ~CFWL_Widget() override;
 
   virtual FWL_Type GetClassID() const = 0;
-  virtual bool IsInstance(const WideStringView& wsClass) const;
+  virtual bool IsForm() const;
   virtual CFX_RectF GetAutosizedWidgetRect();
   virtual CFX_RectF GetWidgetRect();
   virtual CFX_RectF GetClientRect();
@@ -78,23 +96,24 @@
 
   void SetParent(CFWL_Widget* pParent);
 
+  bool IsVisible() const;
+  bool IsOverLapper() const;
+  bool IsPopup() const;
+  bool IsChild() const;
+
   CFWL_Widget* GetOwner() { return m_pWidgetMgr->GetOwnerWidget(this); }
   CFWL_Widget* GetOuter() const { return m_pOuter; }
+  CFWL_Widget* GetOutmost() const;
 
-  uint32_t GetStyles() const;
   void ModifyStyles(uint32_t dwStylesAdded, uint32_t dwStylesRemoved);
   uint32_t GetStylesEx() const;
   uint32_t GetStates() const;
 
-  void LockUpdate() { m_iLock++; }
-  void UnlockUpdate() {
-    if (IsLocked())
-      m_iLock--;
-  }
-
   CFX_PointF TransformTo(CFWL_Widget* pWidget, const CFX_PointF& point);
-  CFX_Matrix GetMatrix();
-  IFWL_ThemeProvider* GetThemeProvider() const;
+  CFX_Matrix GetMatrix() const;
+  IFWL_ThemeProvider* GetThemeProvider() const {
+    return m_pProperties->m_pThemeProvider.Get();
+  }
 
   void SetDelegate(IFWL_WidgetDelegate* delegate) { m_pDelegate = delegate; }
   IFWL_WidgetDelegate* GetDelegate() {
@@ -108,12 +127,9 @@
   uint32_t GetEventKey() const { return m_nEventKey; }
   void SetEventKey(uint32_t key) { m_nEventKey = key; }
 
-  CXFA_FFWidget* GetLayoutItem() const { return m_pLayoutItem; }
-  void SetLayoutItem(CXFA_FFWidget* pItem) { m_pLayoutItem = pItem; }
-
-  void SetFocus(bool bFocus);
+  AdapterIface* GetAdapterIface() const { return m_pAdapterIface; }
+  void SetAdapterIface(AdapterIface* pItem) { m_pAdapterIface = pItem; }
   void RepaintRect(const CFX_RectF& pRect);
-  void Repaint();
 
  protected:
   CFWL_Widget(const CFWL_App* app,
@@ -123,10 +139,11 @@
   bool IsEnabled() const;
   bool IsLocked() const { return m_iLock > 0; }
   bool HasBorder() const;
-  CFX_RectF GetEdgeRect();
-  float GetBorderSize(bool bCX);
-  CFX_RectF GetRelativeRect();
-  IFWL_ThemeProvider* GetAvailableTheme();
+  CFX_RectF GetEdgeRect() const;
+  float GetCXBorderSize() const;
+  float GetCYBorderSize() const;
+  CFX_RectF GetRelativeRect() const;
+  IFWL_ThemeProvider* GetAvailableTheme() const;
   CFX_SizeF CalcTextSize(const WideString& wsText,
                          IFWL_ThemeProvider* pTheme,
                          bool bMultiLine);
@@ -134,12 +151,8 @@
                     IFWL_ThemeProvider* pTheme,
                     const FDE_TextStyle& dwTTOStyles,
                     FDE_TextAlignment iTTOAlign,
-                    CFX_RectF& rect);
+                    CFX_RectF* pRect);
   void SetGrab(bool bSet);
-  void GetPopupPos(float fMinHeight,
-                   float fMaxHeight,
-                   const CFX_RectF& rtAnchor,
-                   CFX_RectF& rtPopup);
   void RegisterEventTarget(CFWL_Widget* pEventSource);
   void UnregisterEventTarget();
   void DispatchEvent(CFWL_Event* pEvent);
@@ -152,29 +165,17 @@
   UnownedPtr<CFWL_WidgetMgr> const m_pWidgetMgr;
   std::unique_ptr<CFWL_WidgetProperties> m_pProperties;
   CFWL_Widget* m_pOuter;
-  int32_t m_iLock;
+  int32_t m_iLock = 0;
 
  private:
-  CFWL_Widget* GetParent() { return m_pWidgetMgr->GetParentWidget(this); }
-  CFX_SizeF GetOffsetFromParent(CFWL_Widget* pParent);
+  void LockUpdate() { m_iLock++; }
+  void UnlockUpdate() {
+    if (IsLocked())
+      m_iLock--;
+  }
 
-  bool IsVisible() const;
-  bool IsOverLapper() const;
-  bool IsPopup() const;
-  bool IsChild() const;
-  CFWL_Widget* GetRootOuter();
-  bool GetPopupPosMenu(float fMinHeight,
-                       float fMaxHeight,
-                       const CFX_RectF& rtAnchor,
-                       CFX_RectF& rtPopup);
-  bool GetPopupPosComboBox(float fMinHeight,
-                           float fMaxHeight,
-                           const CFX_RectF& rtAnchor,
-                           CFX_RectF& rtPopup);
-  bool GetPopupPosGeneral(float fMinHeight,
-                          float fMaxHeight,
-                          const CFX_RectF& rtAnchor,
-                          CFX_RectF& rtPopup);
+  CFWL_Widget* GetParent() const { return m_pWidgetMgr->GetParentWidget(this); }
+  CFX_SizeF GetOffsetFromParent(CFWL_Widget* pParent);
   void DrawBackground(CXFA_Graphics* pGraphics,
                       CFWL_Part iPartBk,
                       IFWL_ThemeProvider* pTheme,
@@ -182,8 +183,8 @@
   void NotifyDriver();
   bool IsParent(CFWL_Widget* pParent);
 
-  CXFA_FFWidget* m_pLayoutItem;
-  uint32_t m_nEventKey;
+  uint32_t m_nEventKey = 0;
+  AdapterIface* m_pAdapterIface = nullptr;
   UnownedPtr<IFWL_WidgetDelegate> m_pDelegate;
 };
 
diff --git a/xfa/fwl/cfwl_widgetmgr.cpp b/xfa/fwl/cfwl_widgetmgr.cpp
index 3082b18..cb41430 100644
--- a/xfa/fwl/cfwl_widgetmgr.cpp
+++ b/xfa/fwl/cfwl_widgetmgr.cpp
@@ -8,44 +8,39 @@
 
 #include <utility>
 
+#include "build/build_config.h"
 #include "third_party/base/ptr_util.h"
 #include "xfa/fwl/cfwl_app.h"
-#include "xfa/fwl/cfwl_form.h"
+#include "xfa/fwl/cfwl_message.h"
 #include "xfa/fwl/cfwl_notedriver.h"
-#include "xfa/fxfa/cxfa_ffapp.h"
-#include "xfa/fxfa/cxfa_fwladapterwidgetmgr.h"
 
-namespace {
-
-const int kNeedRepaintHitPoints = 12;
-const int kNeedRepaintHitPiece = 3;
-
-struct FWL_NEEDREPAINTHITDATA {
-  CFX_PointF hitPoint;
-  bool bNotNeedRepaint;
-  bool bNotContainByDirty;
-};
-
-}  // namespace
-
-CFWL_WidgetMgr::CFWL_WidgetMgr(CXFA_FFApp* pAdapterNative)
-    : m_dwCapability(FWL_WGTMGR_DisableForm),
-      m_pAdapter(pAdapterNative->GetFWLAdapterWidgetMgr()) {
-  ASSERT(m_pAdapter);
+CFWL_WidgetMgr::CFWL_WidgetMgr(AdapterIface* pAdapterNative)
+    : m_pAdapter(pAdapterNative) {
   m_mapWidgetItem[nullptr] = pdfium::MakeUnique<Item>();
-#if _FX_PLATFORM_ == _FX_PLATFORM_WINDOWS_
-  m_rtScreen.Reset();
-#endif  // _FX_PLATFORM_ == _FX_PLATFORM_WINDOWS_
 }
 
-CFWL_WidgetMgr::~CFWL_WidgetMgr() {}
+CFWL_WidgetMgr::~CFWL_WidgetMgr() = default;
 
-CFWL_Widget* CFWL_WidgetMgr::GetParentWidget(CFWL_Widget* pWidget) const {
+// static
+CFWL_Widget* CFWL_WidgetMgr::NextTab(CFWL_Widget* parent, CFWL_Widget* focus) {
+  CFWL_WidgetMgr* pMgr = parent->GetOwnerApp()->GetWidgetMgr();
+  CFWL_Widget* child = pMgr->GetFirstChildWidget(parent);
+  while (child) {
+    CFWL_Widget* bRet = NextTab(child, focus);
+    if (bRet)
+      return bRet;
+
+    child = pMgr->GetNextSiblingWidget(child);
+  }
+  return nullptr;
+}
+
+CFWL_Widget* CFWL_WidgetMgr::GetParentWidget(const CFWL_Widget* pWidget) const {
   Item* pItem = GetWidgetMgrItem(pWidget);
   return pItem && pItem->pParent ? pItem->pParent->pWidget : nullptr;
 }
 
-CFWL_Widget* CFWL_WidgetMgr::GetOwnerWidget(CFWL_Widget* pWidget) const {
+CFWL_Widget* CFWL_WidgetMgr::GetOwnerWidget(const CFWL_Widget* pWidget) const {
   Item* pItem = GetWidgetMgrItem(pWidget);
   return pItem && pItem->pOwner ? pItem->pOwner->pWidget : nullptr;
 }
@@ -142,29 +137,15 @@
 
 void CFWL_WidgetMgr::RepaintWidget(CFWL_Widget* pWidget,
                                    const CFX_RectF& rect) {
-  if (!m_pAdapter)
-    return;
-
   CFWL_Widget* pNative = pWidget;
   CFX_RectF transformedRect = rect;
-  if (IsFormDisabled()) {
-    CFWL_Widget* pOuter = pWidget->GetOuter();
-    while (pOuter) {
-      CFX_RectF rtTemp = pNative->GetWidgetRect();
-      transformedRect.left += rtTemp.left;
-      transformedRect.top += rtTemp.top;
-      pNative = pOuter;
-      pOuter = pOuter->GetOuter();
-    }
-  } else if (!IsAbleNative(pWidget)) {
-    pNative = GetSystemFormWidget(pWidget);
-    if (!pNative)
-      return;
-
-    CFX_PointF pos = pWidget->TransformTo(
-        pNative, CFX_PointF(transformedRect.left, transformedRect.top));
-    transformedRect.left = pos.x;
-    transformedRect.top = pos.y;
+  CFWL_Widget* pOuter = pWidget->GetOuter();
+  while (pOuter) {
+    CFX_RectF rtTemp = pNative->GetWidgetRect();
+    transformedRect.left += rtTemp.left;
+    transformedRect.top += rtTemp.top;
+    pNative = pOuter;
+    pOuter = pOuter->GetOuter();
   }
   AddRedrawCounts(pNative);
   m_pAdapter->RepaintWidget(pNative);
@@ -263,12 +244,10 @@
   if (!parent)
     return nullptr;
 
-  CFX_PointF pos;
   CFWL_Widget* child = GetLastChildWidget(parent);
   while (child) {
-    if ((child->GetStates() & FWL_WGTSTATE_Invisible) == 0) {
-      pos = parent->GetMatrix().GetInverse().Transform(point);
-
+    if (child->IsVisible()) {
+      CFX_PointF pos = parent->GetMatrix().GetInverse().Transform(point);
       CFX_RectF bounds = child->GetWidgetRect();
       if (bounds.Contains(pos)) {
         pos -= bounds.TopLeft();
@@ -280,56 +259,6 @@
   return parent;
 }
 
-CFWL_Widget* CFWL_WidgetMgr::NextTab(CFWL_Widget* parent,
-                                     CFWL_Widget* focus,
-                                     bool& bFind) {
-  CFWL_WidgetMgr* pMgr = parent->GetOwnerApp()->GetWidgetMgr();
-  CFWL_Widget* child = pMgr->GetFirstChildWidget(parent);
-  while (child) {
-    if (focus == child)
-      bFind = true;
-
-    CFWL_Widget* bRet = NextTab(child, focus, bFind);
-    if (bRet)
-      return bRet;
-
-    child = pMgr->GetNextSiblingWidget(child);
-  }
-  return nullptr;
-}
-
-int32_t CFWL_WidgetMgr::CountRadioButtonGroup(CFWL_Widget* pFirst) const {
-  int32_t iRet = 0;
-  CFWL_Widget* pChild = pFirst;
-  while (pChild) {
-    pChild = GetNextSiblingWidget(pChild);
-    ++iRet;
-  }
-  return iRet;
-}
-
-CFWL_Widget* CFWL_WidgetMgr::GetRadioButtonGroupHeader(
-    CFWL_Widget* pRadioButton) const {
-  CFWL_Widget* pNext = pRadioButton;
-  if (pNext && (pNext->GetStyles() & FWL_WGTSTYLE_Group))
-    return pNext;
-  return nullptr;
-}
-
-std::vector<CFWL_Widget*> CFWL_WidgetMgr::GetSameGroupRadioButton(
-    CFWL_Widget* pRadioButton) const {
-  CFWL_Widget* pFirst = GetFirstSiblingWidget(pRadioButton);
-  if (!pFirst)
-    pFirst = pRadioButton;
-
-  if (CountRadioButtonGroup(pFirst) < 2)
-    return std::vector<CFWL_Widget*>();
-
-  std::vector<CFWL_Widget*> group;
-  group.push_back(GetRadioButtonGroupHeader(pRadioButton));
-  return group;
-}
-
 CFWL_Widget* CFWL_WidgetMgr::GetDefaultButton(CFWL_Widget* pParent) const {
   if ((pParent->GetClassID() == FWL_Type::PushButton) &&
       (pParent->GetStates() & (1 << (FWL_WGTSTATE_MAX + 2)))) {
@@ -360,58 +289,35 @@
 }
 
 CFWL_WidgetMgr::Item* CFWL_WidgetMgr::GetWidgetMgrItem(
-    CFWL_Widget* pWidget) const {
+    const CFWL_Widget* pWidget) const {
   auto it = m_mapWidgetItem.find(pWidget);
-  return it != m_mapWidgetItem.end() ? static_cast<Item*>(it->second.get())
-                                     : nullptr;
+  return it != m_mapWidgetItem.end() ? it->second.get() : nullptr;
 }
 
 bool CFWL_WidgetMgr::IsAbleNative(CFWL_Widget* pWidget) const {
-  if (!pWidget)
-    return false;
-  if (!pWidget->IsInstance(FWL_CLASS_Form))
+  if (!pWidget || !pWidget->IsForm())
     return false;
 
-  uint32_t dwStyles = pWidget->GetStyles();
-  return ((dwStyles & FWL_WGTSTYLE_WindowTypeMask) ==
-          FWL_WGTSTYLE_OverLapper) ||
-         (dwStyles & FWL_WGTSTYLE_Popup);
+  return pWidget->IsOverLapper() || pWidget->IsPopup();
 }
 
 void CFWL_WidgetMgr::GetAdapterPopupPos(CFWL_Widget* pWidget,
                                         float fMinHeight,
                                         float fMaxHeight,
                                         const CFX_RectF& rtAnchor,
-                                        CFX_RectF& rtPopup) const {
-  m_pAdapter->GetPopupPos(pWidget, fMinHeight, fMaxHeight, rtAnchor, rtPopup);
+                                        CFX_RectF* pPopupRect) const {
+  m_pAdapter->GetPopupPos(pWidget, fMinHeight, fMaxHeight, rtAnchor,
+                          pPopupRect);
 }
 
-void CFWL_WidgetMgr::OnProcessMessageToForm(CFWL_Message* pMessage) {
-  if (!pMessage)
-    return;
-  if (!pMessage->m_pDstTarget)
+void CFWL_WidgetMgr::OnProcessMessageToForm(
+    std::unique_ptr<CFWL_Message> pMessage) {
+  CFWL_Widget* pDstWidget = pMessage->GetDstTarget();
+  if (!pDstWidget)
     return;
 
-  CFWL_Widget* pDstWidget = pMessage->m_pDstTarget;
-  const CFWL_App* pApp = pDstWidget->GetOwnerApp();
-  if (!pApp)
-    return;
-
-  CFWL_NoteDriver* pNoteDriver =
-      static_cast<CFWL_NoteDriver*>(pApp->GetNoteDriver());
-  if (!pNoteDriver)
-    return;
-
-  if (IsFormDisabled())
-    pNoteDriver->ProcessMessage(pMessage->Clone());
-  else
-    pNoteDriver->QueueMessage(pMessage->Clone());
-
-#if (_FX_OS_ == _FX_OS_MACOSX_)
-  CFWL_NoteLoop* pTopLoop = pNoteDriver->GetTopLoop();
-  if (pTopLoop)
-    pNoteDriver->UnqueueMessageAndProcess(pTopLoop);
-#endif
+  CFWL_NoteDriver* pNoteDriver = pDstWidget->GetOwnerApp()->GetNoteDriver();
+  pNoteDriver->ProcessMessage(std::move(pMessage));
 }
 
 void CFWL_WidgetMgr::OnDrawWidget(CFWL_Widget* pWidget,
@@ -423,26 +329,10 @@
   CFX_RectF clipCopy(0, 0, pWidget->GetWidgetRect().Size());
   CFX_RectF clipBounds;
 
-#if _FX_OS_ == _FX_OS_MACOSX_
-  if (IsFormDisabled()) {
-#endif  // _FX_OS_ == _FX_OS_MACOSX_
+  pWidget->GetDelegate()->OnDrawWidget(pGraphics, matrix);
+  clipBounds = pGraphics->GetClipRect();
+  clipCopy = clipBounds;
 
-    pWidget->GetDelegate()->OnDrawWidget(pGraphics, matrix);
-    clipBounds = pGraphics->GetClipRect();
-    clipCopy = clipBounds;
-
-#if _FX_OS_ == _FX_OS_MACOSX_
-  } else {
-    clipBounds = CFX_RectF(matrix.a, matrix.b, matrix.c, matrix.d);
-    // FIXME: const cast
-    CFX_Matrix* pMatrixHack = const_cast<CFX_Matrix*>(&matrix);
-    pMatrixHack->SetIdentity();
-    pWidget->GetDelegate()->OnDrawWidget(pGraphics, *pMatrixHack);
-  }
-#endif  // _FX_OS_ == _FX_OS_MACOSX_
-
-  if (!IsFormDisabled())
-    clipBounds.Intersect(pWidget->GetClientRect());
   if (!clipBounds.IsEmpty())
     DrawChild(pWidget, clipBounds, pGraphics, &matrix);
 
@@ -457,12 +347,11 @@
   if (!parent)
     return;
 
-  bool bFormDisable = IsFormDisabled();
   CFWL_Widget* pNextChild = GetFirstChildWidget(parent);
   while (pNextChild) {
     CFWL_Widget* child = pNextChild;
     pNextChild = GetNextSiblingWidget(child);
-    if (child->GetStates() & FWL_WGTSTATE_Invisible)
+    if (!child->IsVisible())
       continue;
 
     CFX_RectF rtWidget = child->GetWidgetRect();
@@ -471,131 +360,18 @@
 
     CFX_Matrix widgetMatrix;
     CFX_RectF clipBounds(rtWidget);
-    if (!bFormDisable)
-      widgetMatrix = child->GetMatrix();
     if (pMatrix)
       widgetMatrix.Concat(*pMatrix);
 
-    if (!bFormDisable) {
-      CFX_PointF pos = widgetMatrix.Transform(clipBounds.TopLeft());
-      clipBounds.left = pos.x;
-      clipBounds.top = pos.y;
-      clipBounds.Intersect(rtClip);
-      if (clipBounds.IsEmpty())
-        continue;
+    widgetMatrix.TranslatePrepend(rtWidget.left, rtWidget.top);
 
-      pGraphics->SaveGraphState();
-      pGraphics->SetClipRect(clipBounds);
-    }
-    widgetMatrix.Translate(rtWidget.left, rtWidget.top, true);
+    if (IFWL_WidgetDelegate* pDelegate = child->GetDelegate())
+      pDelegate->OnDrawWidget(pGraphics, widgetMatrix);
 
-    if (IFWL_WidgetDelegate* pDelegate = child->GetDelegate()) {
-      if (IsFormDisabled() || IsNeedRepaint(child, &widgetMatrix, rtClip))
-        pDelegate->OnDrawWidget(pGraphics, widgetMatrix);
-    }
-    if (!bFormDisable)
-      pGraphics->RestoreGraphState();
-
-    DrawChild(child, clipBounds, pGraphics,
-              bFormDisable ? &widgetMatrix : pMatrix);
-    child = GetNextSiblingWidget(child);
+    DrawChild(child, clipBounds, pGraphics, &widgetMatrix);
   }
 }
 
-bool CFWL_WidgetMgr::IsNeedRepaint(CFWL_Widget* pWidget,
-                                   CFX_Matrix* pMatrix,
-                                   const CFX_RectF& rtDirty) {
-  Item* pItem = GetWidgetMgrItem(pWidget);
-  if (pItem && pItem->iRedrawCounter > 0) {
-    pItem->iRedrawCounter = 0;
-    return true;
-  }
-
-  CFX_RectF rtWidget =
-      pMatrix->TransformRect(CFX_RectF(0, 0, pWidget->GetWidgetRect().Size()));
-  if (!rtWidget.IntersectWith(rtDirty))
-    return false;
-
-  CFWL_Widget* pChild =
-      pWidget->GetOwnerApp()->GetWidgetMgr()->GetFirstChildWidget(pWidget);
-  if (!pChild)
-    return true;
-
-  CFX_RectF rtChilds;
-  bool bChildIntersectWithDirty = false;
-  bool bOrginPtIntersectWidthChild = false;
-  bool bOrginPtIntersectWidthDirty = rtDirty.Contains(rtWidget.TopLeft());
-  static FWL_NEEDREPAINTHITDATA hitPoint[kNeedRepaintHitPoints];
-  memset(hitPoint, 0, sizeof(hitPoint));
-  float fxPiece = rtWidget.width / kNeedRepaintHitPiece;
-  float fyPiece = rtWidget.height / kNeedRepaintHitPiece;
-  hitPoint[2].hitPoint.x = hitPoint[6].hitPoint.x = rtWidget.left;
-  hitPoint[0].hitPoint.x = hitPoint[3].hitPoint.x = hitPoint[7].hitPoint.x =
-      hitPoint[10].hitPoint.x = fxPiece + rtWidget.left;
-  hitPoint[1].hitPoint.x = hitPoint[4].hitPoint.x = hitPoint[8].hitPoint.x =
-      hitPoint[11].hitPoint.x = fxPiece * 2 + rtWidget.left;
-  hitPoint[5].hitPoint.x = hitPoint[9].hitPoint.x =
-      rtWidget.width + rtWidget.left;
-  hitPoint[0].hitPoint.y = hitPoint[1].hitPoint.y = rtWidget.top;
-  hitPoint[2].hitPoint.y = hitPoint[3].hitPoint.y = hitPoint[4].hitPoint.y =
-      hitPoint[5].hitPoint.y = fyPiece + rtWidget.top;
-  hitPoint[6].hitPoint.y = hitPoint[7].hitPoint.y = hitPoint[8].hitPoint.y =
-      hitPoint[9].hitPoint.y = fyPiece * 2 + rtWidget.top;
-  hitPoint[10].hitPoint.y = hitPoint[11].hitPoint.y =
-      rtWidget.height + rtWidget.top;
-  do {
-    CFX_RectF rect = pChild->GetWidgetRect();
-    CFX_RectF r(rect.left + rtWidget.left, rect.top + rtWidget.top, rect.width,
-                rect.height);
-    if (r.IsEmpty())
-      continue;
-    if (r.Contains(rtDirty))
-      return false;
-    if (!bChildIntersectWithDirty && r.IntersectWith(rtDirty))
-      bChildIntersectWithDirty = true;
-    if (bOrginPtIntersectWidthDirty && !bOrginPtIntersectWidthChild)
-      bOrginPtIntersectWidthChild = rect.Contains(CFX_PointF(0, 0));
-
-    if (rtChilds.IsEmpty())
-      rtChilds = rect;
-    else if (!(pChild->GetStates() & FWL_WGTSTATE_Invisible))
-      rtChilds.Union(rect);
-
-    for (int32_t i = 0; i < kNeedRepaintHitPoints; i++) {
-      if (hitPoint[i].bNotContainByDirty || hitPoint[i].bNotNeedRepaint)
-        continue;
-      if (!rtDirty.Contains(hitPoint[i].hitPoint)) {
-        hitPoint[i].bNotContainByDirty = true;
-        continue;
-      }
-      if (r.Contains(hitPoint[i].hitPoint))
-        hitPoint[i].bNotNeedRepaint = true;
-    }
-    pChild =
-        pChild->GetOwnerApp()->GetWidgetMgr()->GetNextSiblingWidget(pChild);
-  } while (pChild);
-
-  if (!bChildIntersectWithDirty)
-    return true;
-  if (bOrginPtIntersectWidthDirty && !bOrginPtIntersectWidthChild)
-    return true;
-  if (rtChilds.IsEmpty())
-    return true;
-
-  int32_t repaintPoint = kNeedRepaintHitPoints;
-  for (int32_t i = 0; i < kNeedRepaintHitPoints; i++) {
-    if (hitPoint[i].bNotNeedRepaint)
-      repaintPoint--;
-  }
-  if (repaintPoint > 0)
-    return true;
-
-  rtChilds = pMatrix->TransformRect(rtChilds);
-  if (rtChilds.Contains(rtDirty) || rtChilds.Contains(rtWidget))
-    return false;
-  return true;
-}
-
 CFWL_WidgetMgr::Item::Item() : CFWL_WidgetMgr::Item(nullptr) {}
 
 CFWL_WidgetMgr::Item::Item(CFWL_Widget* widget)
@@ -605,12 +381,6 @@
       pPrevious(nullptr),
       pNext(nullptr),
       pWidget(widget),
-      iRedrawCounter(0)
-#if _FX_PLATFORM_ == _FX_PLATFORM_WINDOWS_
-      ,
-      bOutsideChanged(false)
-#endif  // _FX_PLATFORM_ == _FX_PLATFORM_WINDOWS_
-{
-}
+      iRedrawCounter(0) {}
 
 CFWL_WidgetMgr::Item::~Item() {}
diff --git a/xfa/fwl/cfwl_widgetmgr.h b/xfa/fwl/cfwl_widgetmgr.h
index 153d0a9..a401e22 100644
--- a/xfa/fwl/cfwl_widgetmgr.h
+++ b/xfa/fwl/cfwl_widgetmgr.h
@@ -14,27 +14,36 @@
 #include "core/fxcrt/fx_system.h"
 #include "xfa/fxgraphics/cxfa_graphics.h"
 
-#define FWL_WGTMGR_DisableForm 0x00000002
-
 class CFWL_Message;
-class CXFA_FFApp;
-class CXFA_FWLAdapterWidgetMgr;
 class CXFA_Graphics;
 class CFX_Matrix;
 class CFWL_Widget;
 
 class CFWL_WidgetMgr {
  public:
-  explicit CFWL_WidgetMgr(CXFA_FFApp* pAdapterNative);
+  class AdapterIface {
+   public:
+    virtual ~AdapterIface() {}
+    virtual void RepaintWidget(CFWL_Widget* pWidget) = 0;
+    virtual bool GetPopupPos(CFWL_Widget* pWidget,
+                             float fMinHeight,
+                             float fMaxHeight,
+                             const CFX_RectF& rtAnchor,
+                             CFX_RectF* pPopupRect) = 0;
+  };
+
+  explicit CFWL_WidgetMgr(AdapterIface* pAdapterNative);
   ~CFWL_WidgetMgr();
 
-  void OnProcessMessageToForm(CFWL_Message* pMessage);
+  static CFWL_Widget* NextTab(CFWL_Widget* parent, CFWL_Widget* focus);
+
+  void OnProcessMessageToForm(std::unique_ptr<CFWL_Message> pMessage);
   void OnDrawWidget(CFWL_Widget* pWidget,
                     CXFA_Graphics* pGraphics,
                     const CFX_Matrix& matrix);
 
-  CFWL_Widget* GetParentWidget(CFWL_Widget* pWidget) const;
-  CFWL_Widget* GetOwnerWidget(CFWL_Widget* pWidget) const;
+  CFWL_Widget* GetParentWidget(const CFWL_Widget* pWidget) const;
+  CFWL_Widget* GetOwnerWidget(const CFWL_Widget* pWidget) const;
   CFWL_Widget* GetNextSiblingWidget(CFWL_Widget* pWidget) const;
   CFWL_Widget* GetFirstChildWidget(CFWL_Widget* pWidget) const;
   CFWL_Widget* GetSystemFormWidget(CFWL_Widget* pWidget) const;
@@ -48,23 +57,15 @@
 
   CFWL_Widget* GetWidgetAtPoint(CFWL_Widget* pParent,
                                 const CFX_PointF& point) const;
-  CFWL_Widget* NextTab(CFWL_Widget* parent, CFWL_Widget* focus, bool& bFind);
-
-  std::vector<CFWL_Widget*> GetSameGroupRadioButton(
-      CFWL_Widget* pRadioButton) const;
 
   CFWL_Widget* GetDefaultButton(CFWL_Widget* pParent) const;
   void AddRedrawCounts(CFWL_Widget* pWidget);
 
-  bool IsFormDisabled() const {
-    return !!(m_dwCapability & FWL_WGTMGR_DisableForm);
-  }
-
   void GetAdapterPopupPos(CFWL_Widget* pWidget,
                           float fMinHeight,
                           float fMaxHeight,
                           const CFX_RectF& rtAnchor,
-                          CFX_RectF& rtPopup) const;
+                          CFX_RectF* pPopupRect) const;
 
  private:
   class Item {
@@ -81,42 +82,24 @@
     CFWL_Widget* const pWidget;
     std::unique_ptr<CXFA_Graphics> pOffscreen;
     int32_t iRedrawCounter;
-#if _FX_PLATFORM_ == _FX_PLATFORM_WINDOWS_
-    bool bOutsideChanged;
-#endif  // _FX_PLATFORM_ == _FX_PLATFORM_WINDOWS_
   };
 
   CFWL_Widget* GetFirstSiblingWidget(CFWL_Widget* pWidget) const;
   CFWL_Widget* GetPriorSiblingWidget(CFWL_Widget* pWidget) const;
   CFWL_Widget* GetLastChildWidget(CFWL_Widget* pWidget) const;
-  Item* GetWidgetMgrItem(CFWL_Widget* pWidget) const;
+  Item* GetWidgetMgrItem(const CFWL_Widget* pWidget) const;
 
   void AppendWidget(CFWL_Widget* pWidget);
-
-  int32_t CountRadioButtonGroup(CFWL_Widget* pFirst) const;
-  CFWL_Widget* GetRadioButtonGroupHeader(CFWL_Widget* pRadioButton) const;
-
   void ResetRedrawCounts(CFWL_Widget* pWidget);
-
   void DrawChild(CFWL_Widget* pParent,
                  const CFX_RectF& rtClip,
                  CXFA_Graphics* pGraphics,
                  const CFX_Matrix* pMatrix);
-  CXFA_Graphics* DrawWidgetBefore(CFWL_Widget* pWidget,
-                                  CXFA_Graphics* pGraphics,
-                                  const CFX_Matrix* pMatrix);
-  bool IsNeedRepaint(CFWL_Widget* pWidget,
-                     CFX_Matrix* pMatrix,
-                     const CFX_RectF& rtDirty);
 
   bool IsAbleNative(CFWL_Widget* pWidget) const;
 
-  uint32_t m_dwCapability;
-  std::map<CFWL_Widget*, std::unique_ptr<Item>> m_mapWidgetItem;
-  UnownedPtr<CXFA_FWLAdapterWidgetMgr> const m_pAdapter;
-#if _FX_PLATFORM_ == _FX_PLATFORM_WINDOWS_
-  CFX_RectF m_rtScreen;
-#endif  // _FX_PLATFORM_ == _FX_PLATFORM_WINDOWS_
+  std::map<const CFWL_Widget*, std::unique_ptr<Item>> m_mapWidgetItem;
+  UnownedPtr<AdapterIface> const m_pAdapter;
 };
 
 #endif  // XFA_FWL_CFWL_WIDGETMGR_H_
diff --git a/xfa/fwl/cfwl_widgetproperties.cpp b/xfa/fwl/cfwl_widgetproperties.cpp
index fee957a..4dc3cd5 100644
--- a/xfa/fwl/cfwl_widgetproperties.cpp
+++ b/xfa/fwl/cfwl_widgetproperties.cpp
@@ -6,12 +6,6 @@
 
 #include "xfa/fwl/cfwl_widgetproperties.h"
 
-CFWL_WidgetProperties::CFWL_WidgetProperties()
-    : m_dwStyles(FWL_WGTSTYLE_Child),
-      m_dwStyleExes(0),
-      m_dwStates(0),
-      m_pThemeProvider(nullptr),
-      m_pParent(nullptr),
-      m_pOwner(nullptr) {}
+CFWL_WidgetProperties::CFWL_WidgetProperties() = default;
 
-CFWL_WidgetProperties::~CFWL_WidgetProperties() {}
+CFWL_WidgetProperties::~CFWL_WidgetProperties() = default;
diff --git a/xfa/fwl/cfwl_widgetproperties.h b/xfa/fwl/cfwl_widgetproperties.h
index 065acad..4148833 100644
--- a/xfa/fwl/cfwl_widgetproperties.h
+++ b/xfa/fwl/cfwl_widgetproperties.h
@@ -9,24 +9,23 @@
 
 #include "core/fxcrt/fx_coordinates.h"
 #include "core/fxcrt/fx_system.h"
-#include "xfa/fwl/cfwl_widget.h"
+#include "core/fxcrt/unowned_ptr.h"
 #include "xfa/fwl/fwl_widgetdef.h"
 
-class IFWL_ThemeProvider;
 class CFWL_Widget;
+class IFWL_ThemeProvider;
 
 class CFWL_WidgetProperties {
  public:
   CFWL_WidgetProperties();
   ~CFWL_WidgetProperties();
 
+  uint32_t m_dwStyles = FWL_WGTSTYLE_Child;
+  uint32_t m_dwStyleExes = 0;
+  uint32_t m_dwStates = 0;
   CFX_RectF m_rtWidget;
-  uint32_t m_dwStyles;
-  uint32_t m_dwStyleExes;
-  uint32_t m_dwStates;
-  IFWL_ThemeProvider* m_pThemeProvider;
-  CFWL_Widget* m_pParent;
-  CFWL_Widget* m_pOwner;
+  UnownedPtr<IFWL_ThemeProvider> m_pThemeProvider;
+  CFWL_Widget* m_pParent = nullptr;  // Raw, this class owned by node in tree.
 };
 
 #endif  // XFA_FWL_CFWL_WIDGETPROPERTIES_H_
diff --git a/xfa/fwl/cfx_barcode.cpp b/xfa/fwl/cfx_barcode.cpp
deleted file mode 100644
index 9d667c6..0000000
--- a/xfa/fwl/cfx_barcode.cpp
+++ /dev/null
@@ -1,304 +0,0 @@
-// Copyright 2014 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
-
-#include "xfa/fwl/cfx_barcode.h"
-
-#include <memory>
-
-#include "fxbarcode/cbc_codabar.h"
-#include "fxbarcode/cbc_code128.h"
-#include "fxbarcode/cbc_code39.h"
-#include "fxbarcode/cbc_codebase.h"
-#include "fxbarcode/cbc_datamatrix.h"
-#include "fxbarcode/cbc_ean13.h"
-#include "fxbarcode/cbc_ean8.h"
-#include "fxbarcode/cbc_pdf417i.h"
-#include "fxbarcode/cbc_qrcode.h"
-#include "fxbarcode/cbc_upca.h"
-#include "fxbarcode/utils.h"
-#include "third_party/base/ptr_util.h"
-
-namespace {
-
-std::unique_ptr<CBC_CodeBase> CreateBarCodeEngineObject(BC_TYPE type) {
-  switch (type) {
-    case BC_CODE39:
-      return pdfium::MakeUnique<CBC_Code39>();
-    case BC_CODABAR:
-      return pdfium::MakeUnique<CBC_Codabar>();
-    case BC_CODE128:
-      return pdfium::MakeUnique<CBC_Code128>(BC_CODE128_B);
-    case BC_CODE128_B:
-      return pdfium::MakeUnique<CBC_Code128>(BC_CODE128_B);
-    case BC_CODE128_C:
-      return pdfium::MakeUnique<CBC_Code128>(BC_CODE128_C);
-    case BC_EAN8:
-      return pdfium::MakeUnique<CBC_EAN8>();
-    case BC_UPCA:
-      return pdfium::MakeUnique<CBC_UPCA>();
-    case BC_EAN13:
-      return pdfium::MakeUnique<CBC_EAN13>();
-    case BC_QR_CODE:
-      return pdfium::MakeUnique<CBC_QRCode>();
-    case BC_PDF417:
-      return pdfium::MakeUnique<CBC_PDF417I>();
-    case BC_DATAMATRIX:
-      return pdfium::MakeUnique<CBC_DataMatrix>();
-    case BC_UNKNOWN:
-    default:
-      return nullptr;
-  }
-}
-
-}  // namespace
-
-CFX_Barcode::CFX_Barcode() {}
-
-CFX_Barcode::~CFX_Barcode() {}
-
-bool CFX_Barcode::Create(BC_TYPE type) {
-  m_pBCEngine = CreateBarCodeEngineObject(type);
-  return !!m_pBCEngine;
-}
-
-BC_TYPE CFX_Barcode::GetType() {
-  return m_pBCEngine ? m_pBCEngine->GetType() : BC_UNKNOWN;
-}
-
-bool CFX_Barcode::SetCharEncoding(BC_CHAR_ENCODING encoding) {
-  return m_pBCEngine ? m_pBCEngine->SetCharEncoding(encoding) : false;
-}
-
-bool CFX_Barcode::SetModuleHeight(int32_t moduleHeight) {
-  return m_pBCEngine ? m_pBCEngine->SetModuleHeight(moduleHeight) : false;
-}
-
-bool CFX_Barcode::SetModuleWidth(int32_t moduleWidth) {
-  return m_pBCEngine ? m_pBCEngine->SetModuleWidth(moduleWidth) : false;
-}
-
-bool CFX_Barcode::SetHeight(int32_t height) {
-  return m_pBCEngine ? m_pBCEngine->SetHeight(height) : false;
-}
-
-bool CFX_Barcode::SetWidth(int32_t width) {
-  return m_pBCEngine ? m_pBCEngine->SetWidth(width) : false;
-}
-
-bool CFX_Barcode::SetPrintChecksum(bool checksum) {
-  switch (GetType()) {
-    case BC_CODE39:
-    case BC_CODABAR:
-    case BC_CODE128:
-    case BC_CODE128_B:
-    case BC_CODE128_C:
-    case BC_EAN8:
-    case BC_EAN13:
-    case BC_UPCA:
-      return m_pBCEngine ? (static_cast<CBC_OneCode*>(m_pBCEngine.get())
-                                ->SetPrintChecksum(checksum),
-                            true)
-                         : false;
-    default:
-      return false;
-  }
-}
-
-bool CFX_Barcode::SetDataLength(int32_t length) {
-  switch (GetType()) {
-    case BC_CODE39:
-    case BC_CODABAR:
-    case BC_CODE128:
-    case BC_CODE128_B:
-    case BC_CODE128_C:
-    case BC_EAN8:
-    case BC_EAN13:
-    case BC_UPCA:
-      return m_pBCEngine ? (static_cast<CBC_OneCode*>(m_pBCEngine.get())
-                                ->SetDataLength(length),
-                            true)
-                         : false;
-    default:
-      return false;
-  }
-}
-
-bool CFX_Barcode::SetCalChecksum(bool state) {
-  switch (GetType()) {
-    case BC_CODE39:
-    case BC_CODABAR:
-    case BC_CODE128:
-    case BC_CODE128_B:
-    case BC_CODE128_C:
-    case BC_EAN8:
-    case BC_EAN13:
-    case BC_UPCA:
-      return m_pBCEngine ? (static_cast<CBC_OneCode*>(m_pBCEngine.get())
-                                ->SetCalChecksum(state),
-                            true)
-                         : false;
-    default:
-      return false;
-  }
-}
-
-bool CFX_Barcode::SetFont(CFX_Font* pFont) {
-  switch (GetType()) {
-    case BC_CODE39:
-    case BC_CODABAR:
-    case BC_CODE128:
-    case BC_CODE128_B:
-    case BC_CODE128_C:
-    case BC_EAN8:
-    case BC_EAN13:
-    case BC_UPCA:
-      return m_pBCEngine
-                 ? static_cast<CBC_OneCode*>(m_pBCEngine.get())->SetFont(pFont)
-                 : false;
-    default:
-      return false;
-  }
-}
-
-bool CFX_Barcode::SetFontSize(float size) {
-  switch (GetType()) {
-    case BC_CODE39:
-    case BC_CODABAR:
-    case BC_CODE128:
-    case BC_CODE128_B:
-    case BC_CODE128_C:
-    case BC_EAN8:
-    case BC_EAN13:
-    case BC_UPCA:
-      return m_pBCEngine ? (static_cast<CBC_OneCode*>(m_pBCEngine.get())
-                                ->SetFontSize(size),
-                            true)
-                         : false;
-    default:
-      return false;
-  }
-}
-
-bool CFX_Barcode::SetFontColor(FX_ARGB color) {
-  switch (GetType()) {
-    case BC_CODE39:
-    case BC_CODABAR:
-    case BC_CODE128:
-    case BC_CODE128_B:
-    case BC_CODE128_C:
-    case BC_EAN8:
-    case BC_EAN13:
-    case BC_UPCA:
-      return m_pBCEngine ? (static_cast<CBC_OneCode*>(m_pBCEngine.get())
-                                ->SetFontColor(color),
-                            true)
-                         : false;
-    default:
-      return false;
-  }
-}
-
-bool CFX_Barcode::SetTextLocation(BC_TEXT_LOC location) {
-  typedef bool (CBC_CodeBase::*memptrtype)(BC_TEXT_LOC);
-  memptrtype memptr = nullptr;
-  switch (GetType()) {
-    case BC_CODE39:
-      memptr = (memptrtype)&CBC_Code39::SetTextLocation;
-      break;
-    case BC_CODABAR:
-      memptr = (memptrtype)&CBC_Codabar::SetTextLocation;
-      break;
-    case BC_CODE128:
-    case BC_CODE128_B:
-    case BC_CODE128_C:
-      memptr = (memptrtype)&CBC_Code128::SetTextLocation;
-      break;
-    default:
-      break;
-  }
-  return m_pBCEngine && memptr ? (m_pBCEngine.get()->*memptr)(location) : false;
-}
-
-bool CFX_Barcode::SetWideNarrowRatio(int8_t ratio) {
-  typedef bool (CBC_CodeBase::*memptrtype)(int8_t);
-  memptrtype memptr = nullptr;
-  switch (GetType()) {
-    case BC_CODE39:
-      memptr = (memptrtype)&CBC_Code39::SetWideNarrowRatio;
-      break;
-    case BC_CODABAR:
-      memptr = (memptrtype)&CBC_Codabar::SetWideNarrowRatio;
-      break;
-    default:
-      break;
-  }
-  return m_pBCEngine && memptr ? (m_pBCEngine.get()->*memptr)(ratio) : false;
-}
-
-bool CFX_Barcode::SetStartChar(char start) {
-  typedef bool (CBC_CodeBase::*memptrtype)(char);
-  memptrtype memptr = nullptr;
-  switch (GetType()) {
-    case BC_CODABAR:
-      memptr = (memptrtype)&CBC_Codabar::SetStartChar;
-      break;
-    default:
-      break;
-  }
-  return m_pBCEngine && memptr ? (m_pBCEngine.get()->*memptr)(start) : false;
-}
-
-bool CFX_Barcode::SetEndChar(char end) {
-  typedef bool (CBC_CodeBase::*memptrtype)(char);
-  memptrtype memptr = nullptr;
-  switch (GetType()) {
-    case BC_CODABAR:
-      memptr = (memptrtype)&CBC_Codabar::SetEndChar;
-      break;
-    default:
-      break;
-  }
-  return m_pBCEngine && memptr ? (m_pBCEngine.get()->*memptr)(end) : false;
-}
-
-bool CFX_Barcode::SetErrorCorrectionLevel(int32_t level) {
-  typedef bool (CBC_CodeBase::*memptrtype)(int32_t);
-  memptrtype memptr = nullptr;
-  switch (GetType()) {
-    case BC_QR_CODE:
-      memptr = (memptrtype)&CBC_QRCode::SetErrorCorrectionLevel;
-      break;
-    case BC_PDF417:
-      memptr = (memptrtype)&CBC_PDF417I::SetErrorCorrectionLevel;
-      break;
-    default:
-      return false;
-  }
-  return m_pBCEngine && memptr ? (m_pBCEngine.get()->*memptr)(level) : false;
-}
-
-bool CFX_Barcode::SetTruncated(bool truncated) {
-  typedef void (CBC_CodeBase::*memptrtype)(bool);
-  memptrtype memptr = nullptr;
-  switch (GetType()) {
-    case BC_PDF417:
-      memptr = (memptrtype)&CBC_PDF417I::SetTruncated;
-      break;
-    default:
-      break;
-  }
-  return m_pBCEngine && memptr ? ((m_pBCEngine.get()->*memptr)(truncated), true)
-                               : false;
-}
-
-bool CFX_Barcode::Encode(const WideStringView& contents) {
-  return m_pBCEngine && m_pBCEngine->Encode(contents);
-}
-
-bool CFX_Barcode::RenderDevice(CFX_RenderDevice* device,
-                               const CFX_Matrix* matrix) {
-  return m_pBCEngine && m_pBCEngine->RenderDevice(device, matrix);
-}
diff --git a/xfa/fwl/cfx_barcode.h b/xfa/fwl/cfx_barcode.h
deleted file mode 100644
index eec4648..0000000
--- a/xfa/fwl/cfx_barcode.h
+++ /dev/null
@@ -1,62 +0,0 @@
-// Copyright 2014 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_FWL_CFX_BARCODE_H_
-#define XFA_FWL_CFX_BARCODE_H_
-
-#include <memory>
-
-#include "core/fxcrt/fx_coordinates.h"
-#include "core/fxcrt/fx_string.h"
-#include "core/fxcrt/fx_system.h"
-#include "core/fxge/fx_dib.h"
-#include "fxbarcode/BC_Library.h"
-
-class CBC_CodeBase;
-class CFX_Font;
-class CFX_RenderDevice;
-class CFX_Matrix;
-
-class CFX_Barcode {
- public:
-  CFX_Barcode();
-  ~CFX_Barcode();
-
-  bool Create(BC_TYPE type);
-  BC_TYPE GetType();
-  bool Encode(const WideStringView& contents);
-
-  bool RenderDevice(CFX_RenderDevice* device, const CFX_Matrix* matrix);
-
-  bool SetCharEncoding(BC_CHAR_ENCODING encoding);
-
-  bool SetModuleHeight(int32_t moduleHeight);
-  bool SetModuleWidth(int32_t moduleWidth);
-
-  bool SetHeight(int32_t height);
-  bool SetWidth(int32_t width);
-
-  bool SetPrintChecksum(bool checksum);
-  bool SetDataLength(int32_t length);
-  bool SetCalChecksum(bool state);
-
-  bool SetFont(CFX_Font* pFont);
-  bool SetFontSize(float size);
-  bool SetFontColor(FX_ARGB color);
-
-  bool SetTextLocation(BC_TEXT_LOC location);
-
-  bool SetWideNarrowRatio(int8_t ratio);
-  bool SetStartChar(char start);
-  bool SetEndChar(char end);
-  bool SetErrorCorrectionLevel(int32_t level);
-  bool SetTruncated(bool truncated);
-
- private:
-  std::unique_ptr<CBC_CodeBase> m_pBCEngine;
-};
-
-#endif  // XFA_FWL_CFX_BARCODE_H_
diff --git a/xfa/fwl/cfx_barcode_unittest.cpp b/xfa/fwl/cfx_barcode_unittest.cpp
deleted file mode 100644
index fe8aee4..0000000
--- a/xfa/fwl/cfx_barcode_unittest.cpp
+++ /dev/null
@@ -1,145 +0,0 @@
-// 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/fwl/cfx_barcode.h"
-
-#include <memory>
-#include <string>
-#include <utility>
-
-#include "core/fxcrt/fx_coordinates.h"
-#include "core/fxcrt/fx_string.h"
-#include "core/fxge/cfx_defaultrenderdevice.h"
-#include "core/fxge/cfx_renderdevice.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "testing/test_support.h"
-#include "third_party/base/ptr_util.h"
-
-class BarcodeTest : public testing::Test {
- public:
-  void SetUp() override {
-    BC_Library_Init();
-    barcode_ = pdfium::MakeUnique<CFX_Barcode>();
-
-    auto device = pdfium::MakeUnique<CFX_DefaultRenderDevice>();
-    auto bitmap = pdfium::MakeRetain<CFX_DIBitmap>();
-    if (bitmap->Create(640, 480, FXDIB_Rgb32))
-      bitmap_ = bitmap;
-    ASSERT_TRUE(bitmap_);
-    ASSERT_TRUE(device->Attach(bitmap_, false, nullptr, false));
-    device_ = std::move(device);
-  }
-
-  void TearDown() override {
-    bitmap_.Reset();
-    device_.reset();
-    barcode_.reset();
-    BC_Library_Destroy();
-  }
-
-  CFX_Barcode* barcode() const { return barcode_.get(); }
-
-  bool Create(BC_TYPE type) {
-    if (!barcode_->Create(type))
-      return false;
-
-    barcode_->SetModuleHeight(300);
-    barcode_->SetModuleWidth(420);
-    barcode_->SetHeight(298);
-    barcode_->SetWidth(418);
-    return true;
-  }
-
-  bool RenderDevice() {
-    return barcode_->RenderDevice(device_.get(), &matrix_);
-  }
-
-  std::string BitmapChecksum() {
-    return GenerateMD5Base16(bitmap_->GetBuffer(),
-                             bitmap_->GetPitch() * bitmap_->GetHeight());
-  }
-
- protected:
-  CFX_Matrix matrix_;
-  std::unique_ptr<CFX_Barcode> barcode_;
-  std::unique_ptr<CFX_RenderDevice> device_;
-  RetainPtr<CFX_DIBitmap> bitmap_;
-};
-
-TEST_F(BarcodeTest, Code39) {
-  EXPECT_TRUE(Create(BC_CODE39));
-  EXPECT_TRUE(barcode()->Encode(L"clams"));
-  RenderDevice();
-  EXPECT_EQ("cd4cd3f36da38ff58d9f621827018903", BitmapChecksum());
-}
-
-TEST_F(BarcodeTest, CodaBar) {
-  EXPECT_TRUE(Create(BC_CODABAR));
-  EXPECT_TRUE(barcode()->Encode(L"clams"));
-  RenderDevice();
-  EXPECT_EQ("481189dc4f86eddb8c42343c9b8ef1dd", BitmapChecksum());
-}
-
-TEST_F(BarcodeTest, Code128) {
-  EXPECT_TRUE(Create(BC_CODE128));
-  EXPECT_TRUE(barcode()->Encode(L"clams"));
-  RenderDevice();
-  EXPECT_EQ("11b21c178a9fd866d8be196c2103b263", BitmapChecksum());
-}
-
-TEST_F(BarcodeTest, Code128_B) {
-  EXPECT_TRUE(Create(BC_CODE128_B));
-  EXPECT_TRUE(barcode()->Encode(L"clams"));
-  RenderDevice();
-  EXPECT_EQ("11b21c178a9fd866d8be196c2103b263", BitmapChecksum());
-}
-
-TEST_F(BarcodeTest, Code128_C) {
-  EXPECT_TRUE(Create(BC_CODE128_C));
-  EXPECT_TRUE(barcode()->Encode(L"clams"));
-  RenderDevice();
-  EXPECT_EQ("6284ec8503d5a948c9518108da33cdd3", BitmapChecksum());
-}
-
-TEST_F(BarcodeTest, Ean8) {
-  EXPECT_TRUE(Create(BC_EAN8));
-  EXPECT_TRUE(barcode()->Encode(L"clams"));
-  RenderDevice();
-  EXPECT_EQ("22d85bcb02d48f48813f02a1cc9cfe8c", BitmapChecksum());
-}
-
-TEST_F(BarcodeTest, UPCA) {
-  EXPECT_TRUE(Create(BC_UPCA));
-  EXPECT_TRUE(barcode()->Encode(L"clams"));
-  RenderDevice();
-  EXPECT_EQ("cce41fc30852744c44b3353059b568b4", BitmapChecksum());
-}
-
-TEST_F(BarcodeTest, Ean13) {
-  EXPECT_TRUE(Create(BC_EAN13));
-  EXPECT_TRUE(barcode()->Encode(L"clams"));
-  RenderDevice();
-  EXPECT_EQ("187091ec1fd1830fc4d41d40a923d4fb", BitmapChecksum());
-}
-
-TEST_F(BarcodeTest, Pdf417) {
-  EXPECT_TRUE(Create(BC_PDF417));
-  EXPECT_TRUE(barcode()->Encode(L"clams"));
-  RenderDevice();
-  EXPECT_EQ("2bdb9b39f20c5763da6a0d7c7b1f6933", BitmapChecksum());
-}
-
-TEST_F(BarcodeTest, DataMatrix) {
-  EXPECT_TRUE(Create(BC_DATAMATRIX));
-  EXPECT_TRUE(barcode()->Encode(L"clams"));
-  RenderDevice();
-  EXPECT_EQ("5e5cd9a680b86fcd4ffd53ed36e3c980", BitmapChecksum());
-}
-
-TEST_F(BarcodeTest, QrCode) {
-  EXPECT_TRUE(Create(BC_QR_CODE));
-  EXPECT_TRUE(barcode()->Encode(L"clams"));
-  RenderDevice();
-  EXPECT_EQ("4751c6e0f67749fabe24f787128decee", BitmapChecksum());
-}
diff --git a/xfa/fwl/fwl_widgetdef.h b/xfa/fwl/fwl_widgetdef.h
index a85ba15..19eb508 100644
--- a/xfa/fwl/fwl_widgetdef.h
+++ b/xfa/fwl/fwl_widgetdef.h
@@ -21,177 +21,178 @@
 #define FWL_WGTSTATE_Invisible (1L << 5)
 #define FWL_WGTSTATE_MAX (6)
 
-#define FWL_VKEY_LButton 0x01
-#define FWL_VKEY_RButton 0x02
-#define FWL_VKEY_MButton 0x04
-#define FWL_VKEY_Back 0x08
-#define FWL_VKEY_Tab 0x09
-#define FWL_VKEY_NewLine 0x0A
-#define FWL_VKEY_Clear 0x0C
-#define FWL_VKEY_Return 0x0D
-#define FWL_VKEY_Shift 0x10
-#define FWL_VKEY_Control 0x11
-#define FWL_VKEY_Menu 0x12
-#define FWL_VKEY_Pause 0x13
-#define FWL_VKEY_Capital 0x14
-#define FWL_VKEY_Kana 0x15
-#define FWL_VKEY_Hangul 0x15
-#define FWL_VKEY_Junja 0x17
-#define FWL_VKEY_Final 0x18
-#define FWL_VKEY_Hanja 0x19
-#define FWL_VKEY_Kanji 0x19
-#define FWL_VKEY_Escape 0x1B
-#define FWL_VKEY_Convert 0x1C
-#define FWL_VKEY_NonConvert 0x1D
-#define FWL_VKEY_Accept 0x1E
-#define FWL_VKEY_ModeChange 0x1F
-#define FWL_VKEY_Space 0x20
-#define FWL_VKEY_Prior 0x21
-#define FWL_VKEY_Next 0x22
-#define FWL_VKEY_End 0x23
-#define FWL_VKEY_Home 0x24
-#define FWL_VKEY_Left 0x25
-#define FWL_VKEY_Up 0x26
-#define FWL_VKEY_Right 0x27
-#define FWL_VKEY_Down 0x28
-#define FWL_VKEY_Select 0x29
-#define FWL_VKEY_Print 0x2A
-#define FWL_VKEY_Execute 0x2B
-#define FWL_VKEY_Snapshot 0x2C
-#define FWL_VKEY_Insert 0x2D
-#define FWL_VKEY_Delete 0x2E
-#define FWL_VKEY_Help 0x2F
-#define FWL_VKEY_0 0x30
-#define FWL_VKEY_1 0x31
-#define FWL_VKEY_2 0x32
-#define FWL_VKEY_3 0x33
-#define FWL_VKEY_4 0x34
-#define FWL_VKEY_5 0x35
-#define FWL_VKEY_6 0x36
-#define FWL_VKEY_7 0x37
-#define FWL_VKEY_8 0x38
-#define FWL_VKEY_9 0x39
-#define FWL_VKEY_A 0x41
-#define FWL_VKEY_B 0x42
-#define FWL_VKEY_C 0x43
-#define FWL_VKEY_D 0x44
-#define FWL_VKEY_E 0x45
-#define FWL_VKEY_F 0x46
-#define FWL_VKEY_G 0x47
-#define FWL_VKEY_H 0x48
-#define FWL_VKEY_I 0x49
-#define FWL_VKEY_J 0x4A
-#define FWL_VKEY_K 0x4B
-#define FWL_VKEY_L 0x4C
-#define FWL_VKEY_M 0x4D
-#define FWL_VKEY_N 0x4E
-#define FWL_VKEY_O 0x4F
-#define FWL_VKEY_P 0x50
-#define FWL_VKEY_Q 0x51
-#define FWL_VKEY_R 0x52
-#define FWL_VKEY_S 0x53
-#define FWL_VKEY_T 0x54
-#define FWL_VKEY_U 0x55
-#define FWL_VKEY_V 0x56
-#define FWL_VKEY_W 0x57
-#define FWL_VKEY_X 0x58
-#define FWL_VKEY_Y 0x59
-#define FWL_VKEY_Z 0x5A
-#define FWL_VKEY_LWin 0x5B
-#define FWL_VKEY_Command 0x5B
-#define FWL_VKEY_RWin 0x5C
-#define FWL_VKEY_Apps 0x5D
-#define FWL_VKEY_Sleep 0x5F
-#define FWL_VKEY_NumPad0 0x60
-#define FWL_VKEY_NumPad1 0x61
-#define FWL_VKEY_NumPad2 0x62
-#define FWL_VKEY_NumPad3 0x63
-#define FWL_VKEY_NumPad4 0x64
-#define FWL_VKEY_NumPad5 0x65
-#define FWL_VKEY_NumPad6 0x66
-#define FWL_VKEY_NumPad7 0x67
-#define FWL_VKEY_NumPad8 0x68
-#define FWL_VKEY_NumPad9 0x69
-#define FWL_VKEY_Multiply 0x6A
-#define FWL_VKEY_Add 0x6B
-#define FWL_VKEY_Separator 0x6C
-#define FWL_VKEY_Subtract 0x6D
-#define FWL_VKEY_Decimal 0x6E
-#define FWL_VKEY_Divide 0x6F
-#define FWL_VKEY_F1 0x70
-#define FWL_VKEY_F2 0x71
-#define FWL_VKEY_F3 0x72
-#define FWL_VKEY_F4 0x73
-#define FWL_VKEY_F5 0x74
-#define FWL_VKEY_F6 0x75
-#define FWL_VKEY_F7 0x76
-#define FWL_VKEY_F8 0x77
-#define FWL_VKEY_F9 0x78
-#define FWL_VKEY_F10 0x79
-#define FWL_VKEY_F11 0x7A
-#define FWL_VKEY_F12 0x7B
-#define FWL_VKEY_F13 0x7C
-#define FWL_VKEY_F14 0x7D
-#define FWL_VKEY_F15 0x7E
-#define FWL_VKEY_F16 0x7F
-#define FWL_VKEY_F17 0x80
-#define FWL_VKEY_F18 0x81
-#define FWL_VKEY_F19 0x82
-#define FWL_VKEY_F20 0x83
-#define FWL_VKEY_F21 0x84
-#define FWL_VKEY_F22 0x85
-#define FWL_VKEY_F23 0x86
-#define FWL_VKEY_F24 0x87
-#define FWL_VKEY_NunLock 0x90
-#define FWL_VKEY_Scroll 0x91
-#define FWL_VKEY_LShift 0xA0
-#define FWL_VKEY_RShift 0xA1
-#define FWL_VKEY_LControl 0xA2
-#define FWL_VKEY_RControl 0xA3
-#define FWL_VKEY_LMenu 0xA4
-#define FWL_VKEY_RMenu 0xA5
-#define FWL_VKEY_BROWSER_Back 0xA6
-#define FWL_VKEY_BROWSER_Forward 0xA7
-#define FWL_VKEY_BROWSER_Refresh 0xA8
-#define FWL_VKEY_BROWSER_Stop 0xA9
-#define FWL_VKEY_BROWSER_Search 0xAA
-#define FWL_VKEY_BROWSER_Favorites 0xAB
-#define FWL_VKEY_BROWSER_Home 0xAC
-#define FWL_VKEY_VOLUME_Mute 0xAD
-#define FWL_VKEY_VOLUME_Down 0xAE
-#define FWL_VKEY_VOLUME_Up 0xAF
-#define FWL_VKEY_MEDIA_NEXT_Track 0xB0
-#define FWL_VKEY_MEDIA_PREV_Track 0xB1
-#define FWL_VKEY_MEDIA_Stop 0xB2
-#define FWL_VKEY_MEDIA_PLAY_Pause 0xB3
-#define FWL_VKEY_MEDIA_LAUNCH_Mail 0xB4
-#define FWL_VKEY_MEDIA_LAUNCH_MEDIA_Select 0xB5
-#define FWL_VKEY_MEDIA_LAUNCH_APP1 0xB6
-#define FWL_VKEY_MEDIA_LAUNCH_APP2 0xB7
-#define FWL_VKEY_OEM_1 0xBA
-#define FWL_VKEY_OEM_Plus 0xBB
-#define FWL_VKEY_OEM_Comma 0xBC
-#define FWL_VKEY_OEM_Minus 0xBD
-#define FWL_VKEY_OEM_Period 0xBE
-#define FWL_VKEY_OEM_2 0xBF
-#define FWL_VKEY_OEM_3 0xC0
-#define FWL_VKEY_OEM_4 0xDB
-#define FWL_VKEY_OEM_5 0xDC
-#define FWL_VKEY_OEM_6 0xDD
-#define FWL_VKEY_OEM_7 0xDE
-#define FWL_VKEY_OEM_8 0xDF
-#define FWL_VKEY_OEM_102 0xE2
-#define FWL_VKEY_ProcessKey 0xE5
-#define FWL_VKEY_Packet 0xE7
-#define FWL_VKEY_Attn 0xF6
-#define FWL_VKEY_Crsel 0xF7
-#define FWL_VKEY_Exsel 0xF8
-#define FWL_VKEY_Ereof 0xF9
-#define FWL_VKEY_Play 0xFA
-#define FWL_VKEY_Zoom 0xFB
-#define FWL_VKEY_NoName 0xFC
-#define FWL_VKEY_PA1 0xFD
-#define FWL_VKEY_OEM_Clear 0xFE
-#define FWL_VKEY_Unknown 0
+// Same as enum FWL_VKEYCODE in public/fpdf_fwlevent.h, but duplicated to keep
+// xfa/fwl standalone.
+enum XFA_FWL_VKEYCODE {
+  XFA_FWL_VKEY_Back = 0x08,
+  XFA_FWL_VKEY_Tab = 0x09,
+  XFA_FWL_VKEY_NewLine = 0x0A,
+  XFA_FWL_VKEY_Clear = 0x0C,
+  XFA_FWL_VKEY_Return = 0x0D,
+  XFA_FWL_VKEY_Shift = 0x10,
+  XFA_FWL_VKEY_Control = 0x11,
+  XFA_FWL_VKEY_Menu = 0x12,
+  XFA_FWL_VKEY_Pause = 0x13,
+  XFA_FWL_VKEY_Capital = 0x14,
+  XFA_FWL_VKEY_Kana = 0x15,
+  XFA_FWL_VKEY_Hangul = 0x15,
+  XFA_FWL_VKEY_Junja = 0x17,
+  XFA_FWL_VKEY_Final = 0x18,
+  XFA_FWL_VKEY_Hanja = 0x19,
+  XFA_FWL_VKEY_Kanji = 0x19,
+  XFA_FWL_VKEY_Escape = 0x1B,
+  XFA_FWL_VKEY_Convert = 0x1C,
+  XFA_FWL_VKEY_NonConvert = 0x1D,
+  XFA_FWL_VKEY_Accept = 0x1E,
+  XFA_FWL_VKEY_ModeChange = 0x1F,
+  XFA_FWL_VKEY_Space = 0x20,
+  XFA_FWL_VKEY_Prior = 0x21,
+  XFA_FWL_VKEY_Next = 0x22,
+  XFA_FWL_VKEY_End = 0x23,
+  XFA_FWL_VKEY_Home = 0x24,
+  XFA_FWL_VKEY_Left = 0x25,
+  XFA_FWL_VKEY_Up = 0x26,
+  XFA_FWL_VKEY_Right = 0x27,
+  XFA_FWL_VKEY_Down = 0x28,
+  XFA_FWL_VKEY_Select = 0x29,
+  XFA_FWL_VKEY_Print = 0x2A,
+  XFA_FWL_VKEY_Execute = 0x2B,
+  XFA_FWL_VKEY_Snapshot = 0x2C,
+  XFA_FWL_VKEY_Insert = 0x2D,
+  XFA_FWL_VKEY_Delete = 0x2E,
+  XFA_FWL_VKEY_Help = 0x2F,
+  XFA_FWL_VKEY_0 = 0x30,
+  XFA_FWL_VKEY_1 = 0x31,
+  XFA_FWL_VKEY_2 = 0x32,
+  XFA_FWL_VKEY_3 = 0x33,
+  XFA_FWL_VKEY_4 = 0x34,
+  XFA_FWL_VKEY_5 = 0x35,
+  XFA_FWL_VKEY_6 = 0x36,
+  XFA_FWL_VKEY_7 = 0x37,
+  XFA_FWL_VKEY_8 = 0x38,
+  XFA_FWL_VKEY_9 = 0x39,
+  XFA_FWL_VKEY_A = 0x41,
+  XFA_FWL_VKEY_B = 0x42,
+  XFA_FWL_VKEY_C = 0x43,
+  XFA_FWL_VKEY_D = 0x44,
+  XFA_FWL_VKEY_E = 0x45,
+  XFA_FWL_VKEY_F = 0x46,
+  XFA_FWL_VKEY_G = 0x47,
+  XFA_FWL_VKEY_H = 0x48,
+  XFA_FWL_VKEY_I = 0x49,
+  XFA_FWL_VKEY_J = 0x4A,
+  XFA_FWL_VKEY_K = 0x4B,
+  XFA_FWL_VKEY_L = 0x4C,
+  XFA_FWL_VKEY_M = 0x4D,
+  XFA_FWL_VKEY_N = 0x4E,
+  XFA_FWL_VKEY_O = 0x4F,
+  XFA_FWL_VKEY_P = 0x50,
+  XFA_FWL_VKEY_Q = 0x51,
+  XFA_FWL_VKEY_R = 0x52,
+  XFA_FWL_VKEY_S = 0x53,
+  XFA_FWL_VKEY_T = 0x54,
+  XFA_FWL_VKEY_U = 0x55,
+  XFA_FWL_VKEY_V = 0x56,
+  XFA_FWL_VKEY_W = 0x57,
+  XFA_FWL_VKEY_X = 0x58,
+  XFA_FWL_VKEY_Y = 0x59,
+  XFA_FWL_VKEY_Z = 0x5A,
+  XFA_FWL_VKEY_LWin = 0x5B,
+  XFA_FWL_VKEY_Command = 0x5B,
+  XFA_FWL_VKEY_RWin = 0x5C,
+  XFA_FWL_VKEY_Apps = 0x5D,
+  XFA_FWL_VKEY_Sleep = 0x5F,
+  XFA_FWL_VKEY_NumPad0 = 0x60,
+  XFA_FWL_VKEY_NumPad1 = 0x61,
+  XFA_FWL_VKEY_NumPad2 = 0x62,
+  XFA_FWL_VKEY_NumPad3 = 0x63,
+  XFA_FWL_VKEY_NumPad4 = 0x64,
+  XFA_FWL_VKEY_NumPad5 = 0x65,
+  XFA_FWL_VKEY_NumPad6 = 0x66,
+  XFA_FWL_VKEY_NumPad7 = 0x67,
+  XFA_FWL_VKEY_NumPad8 = 0x68,
+  XFA_FWL_VKEY_NumPad9 = 0x69,
+  XFA_FWL_VKEY_Multiply = 0x6A,
+  XFA_FWL_VKEY_Add = 0x6B,
+  XFA_FWL_VKEY_Separator = 0x6C,
+  XFA_FWL_VKEY_Subtract = 0x6D,
+  XFA_FWL_VKEY_Decimal = 0x6E,
+  XFA_FWL_VKEY_Divide = 0x6F,
+  XFA_FWL_VKEY_F1 = 0x70,
+  XFA_FWL_VKEY_F2 = 0x71,
+  XFA_FWL_VKEY_F3 = 0x72,
+  XFA_FWL_VKEY_F4 = 0x73,
+  XFA_FWL_VKEY_F5 = 0x74,
+  XFA_FWL_VKEY_F6 = 0x75,
+  XFA_FWL_VKEY_F7 = 0x76,
+  XFA_FWL_VKEY_F8 = 0x77,
+  XFA_FWL_VKEY_F9 = 0x78,
+  XFA_FWL_VKEY_F10 = 0x79,
+  XFA_FWL_VKEY_F11 = 0x7A,
+  XFA_FWL_VKEY_F12 = 0x7B,
+  XFA_FWL_VKEY_F13 = 0x7C,
+  XFA_FWL_VKEY_F14 = 0x7D,
+  XFA_FWL_VKEY_F15 = 0x7E,
+  XFA_FWL_VKEY_F16 = 0x7F,
+  XFA_FWL_VKEY_F17 = 0x80,
+  XFA_FWL_VKEY_F18 = 0x81,
+  XFA_FWL_VKEY_F19 = 0x82,
+  XFA_FWL_VKEY_F20 = 0x83,
+  XFA_FWL_VKEY_F21 = 0x84,
+  XFA_FWL_VKEY_F22 = 0x85,
+  XFA_FWL_VKEY_F23 = 0x86,
+  XFA_FWL_VKEY_F24 = 0x87,
+  XFA_FWL_VKEY_NunLock = 0x90,
+  XFA_FWL_VKEY_Scroll = 0x91,
+  XFA_FWL_VKEY_LShift = 0xA0,
+  XFA_FWL_VKEY_RShift = 0xA1,
+  XFA_FWL_VKEY_LControl = 0xA2,
+  XFA_FWL_VKEY_RControl = 0xA3,
+  XFA_FWL_VKEY_LMenu = 0xA4,
+  XFA_FWL_VKEY_RMenu = 0xA5,
+  XFA_FWL_VKEY_BROWSER_Back = 0xA6,
+  XFA_FWL_VKEY_BROWSER_Forward = 0xA7,
+  XFA_FWL_VKEY_BROWSER_Refresh = 0xA8,
+  XFA_FWL_VKEY_BROWSER_Stop = 0xA9,
+  XFA_FWL_VKEY_BROWSER_Search = 0xAA,
+  XFA_FWL_VKEY_BROWSER_Favorites = 0xAB,
+  XFA_FWL_VKEY_BROWSER_Home = 0xAC,
+  XFA_FWL_VKEY_VOLUME_Mute = 0xAD,
+  XFA_FWL_VKEY_VOLUME_Down = 0xAE,
+  XFA_FWL_VKEY_VOLUME_Up = 0xAF,
+  XFA_FWL_VKEY_MEDIA_NEXT_Track = 0xB0,
+  XFA_FWL_VKEY_MEDIA_PREV_Track = 0xB1,
+  XFA_FWL_VKEY_MEDIA_Stop = 0xB2,
+  XFA_FWL_VKEY_MEDIA_PLAY_Pause = 0xB3,
+  XFA_FWL_VKEY_MEDIA_LAUNCH_Mail = 0xB4,
+  XFA_FWL_VKEY_MEDIA_LAUNCH_MEDIA_Select = 0xB5,
+  XFA_FWL_VKEY_MEDIA_LAUNCH_APP1 = 0xB6,
+  XFA_FWL_VKEY_MEDIA_LAUNCH_APP2 = 0xB7,
+  XFA_FWL_VKEY_OEM_1 = 0xBA,
+  XFA_FWL_VKEY_OEM_Plus = 0xBB,
+  XFA_FWL_VKEY_OEM_Comma = 0xBC,
+  XFA_FWL_VKEY_OEM_Minus = 0xBD,
+  XFA_FWL_VKEY_OEM_Period = 0xBE,
+  XFA_FWL_VKEY_OEM_2 = 0xBF,
+  XFA_FWL_VKEY_OEM_3 = 0xC0,
+  XFA_FWL_VKEY_OEM_4 = 0xDB,
+  XFA_FWL_VKEY_OEM_5 = 0xDC,
+  XFA_FWL_VKEY_OEM_6 = 0xDD,
+  XFA_FWL_VKEY_OEM_7 = 0xDE,
+  XFA_FWL_VKEY_OEM_8 = 0xDF,
+  XFA_FWL_VKEY_OEM_102 = 0xE2,
+  XFA_FWL_VKEY_ProcessKey = 0xE5,
+  XFA_FWL_VKEY_Packet = 0xE7,
+  XFA_FWL_VKEY_Attn = 0xF6,
+  XFA_FWL_VKEY_Crsel = 0xF7,
+  XFA_FWL_VKEY_Exsel = 0xF8,
+  XFA_FWL_VKEY_Ereof = 0xF9,
+  XFA_FWL_VKEY_Play = 0xFA,
+  XFA_FWL_VKEY_Zoom = 0xFB,
+  XFA_FWL_VKEY_NoName = 0xFC,
+  XFA_FWL_VKEY_PA1 = 0xFD,
+  XFA_FWL_VKEY_OEM_Clear = 0xFE,
+  XFA_FWL_VKEY_Unknown = 0,
+};
 
 #endif  // XFA_FWL_FWL_WIDGETDEF_H_
diff --git a/xfa/fwl/ifwl_adaptertimermgr.h b/xfa/fwl/ifwl_adaptertimermgr.h
deleted file mode 100644
index 1f65589..0000000
--- a/xfa/fwl/ifwl_adaptertimermgr.h
+++ /dev/null
@@ -1,21 +0,0 @@
-// Copyright 2014 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_FWL_IFWL_ADAPTERTIMERMGR_H_
-#define XFA_FWL_IFWL_ADAPTERTIMERMGR_H_
-
-#include "xfa/fwl/cfwl_timer.h"
-
-class IFWL_AdapterTimerMgr {
- public:
-  virtual void Start(CFWL_Timer* pTimer,
-                     uint32_t dwElapse,
-                     bool bImmediately,
-                     CFWL_TimerInfo** pTimerInfo) = 0;
-  virtual void Stop(CFWL_TimerInfo* pTimerInfo) = 0;
-};
-
-#endif  // XFA_FWL_IFWL_ADAPTERTIMERMGR_H_
diff --git a/xfa/fwl/ifwl_themeprovider.h b/xfa/fwl/ifwl_themeprovider.h
index eba3085..5700d34 100644
--- a/xfa/fwl/ifwl_themeprovider.h
+++ b/xfa/fwl/ifwl_themeprovider.h
@@ -19,20 +19,23 @@
 
 class IFWL_ThemeProvider {
  public:
-  virtual ~IFWL_ThemeProvider() {}
+  virtual ~IFWL_ThemeProvider() = default;
 
-  virtual void DrawBackground(CFWL_ThemeBackground* pParams) = 0;
-  virtual void DrawText(CFWL_ThemeText* pParams) = 0;
-  virtual void CalcTextRect(CFWL_ThemeText* pParams, CFX_RectF& rect) = 0;
+  virtual void DrawBackground(const CFWL_ThemeBackground& pParams) = 0;
+  virtual void DrawText(const CFWL_ThemeText& pParams) = 0;
+  virtual void CalcTextRect(const CFWL_ThemeText& pParams,
+                            CFX_RectF* pRect) = 0;
   virtual float GetCXBorderSize() const = 0;
   virtual float GetCYBorderSize() const = 0;
-  virtual CFX_RectF GetUIMargin(CFWL_ThemePart* pThemePart) const = 0;
-  virtual float GetFontSize(CFWL_ThemePart* pThemePart) const = 0;
-  virtual RetainPtr<CFGAS_GEFont> GetFont(CFWL_ThemePart* pThemePart) const = 0;
-  virtual float GetLineHeight(CFWL_ThemePart* pThemePart) const = 0;
+  virtual CFX_RectF GetUIMargin(const CFWL_ThemePart& pThemePart) const = 0;
+  virtual float GetFontSize(const CFWL_ThemePart& pThemePart) const = 0;
+  virtual RetainPtr<CFGAS_GEFont> GetFont(
+      const CFWL_ThemePart& pThemePart) const = 0;
+  virtual float GetLineHeight(const CFWL_ThemePart& pThemePart) const = 0;
   virtual float GetScrollBarWidth() const = 0;
-  virtual FX_COLORREF GetTextColor(CFWL_ThemePart* pThemePart) const = 0;
-  virtual CFX_SizeF GetSpaceAboveBelow(CFWL_ThemePart* pThemePart) const = 0;
+  virtual FX_COLORREF GetTextColor(const CFWL_ThemePart& pThemePart) const = 0;
+  virtual CFX_SizeF GetSpaceAboveBelow(
+      const CFWL_ThemePart& pThemePart) const = 0;
 };
 
 #endif  // XFA_FWL_IFWL_THEMEPROVIDER_H_
diff --git a/xfa/fwl/ifwl_widgetdelegate.h b/xfa/fwl/ifwl_widgetdelegate.h
index 09bac9a..17b8933 100644
--- a/xfa/fwl/ifwl_widgetdelegate.h
+++ b/xfa/fwl/ifwl_widgetdelegate.h
@@ -16,7 +16,7 @@
 
 class IFWL_WidgetDelegate {
  public:
-  virtual ~IFWL_WidgetDelegate() {}
+  virtual ~IFWL_WidgetDelegate() = default;
 
   virtual void OnProcessMessage(CFWL_Message* pMessage) = 0;
   virtual void OnProcessEvent(CFWL_Event* pEvent) = 0;
diff --git a/xfa/fwl/theme/cfwl_barcodetp.cpp b/xfa/fwl/theme/cfwl_barcodetp.cpp
index cafdf17..222d008 100644
--- a/xfa/fwl/theme/cfwl_barcodetp.cpp
+++ b/xfa/fwl/theme/cfwl_barcodetp.cpp
@@ -14,20 +14,15 @@
 
 CFWL_BarcodeTP::~CFWL_BarcodeTP() {}
 
-void CFWL_BarcodeTP::DrawBackground(CFWL_ThemeBackground* pParams) {
-  if (!pParams)
-    return;
-
-  switch (pParams->m_iPart) {
-    case CFWL_Part::Border: {
-      DrawBorder(pParams->m_pGraphics, &pParams->m_rtPart, &pParams->m_matrix);
+void CFWL_BarcodeTP::DrawBackground(const CFWL_ThemeBackground& pParams) {
+  switch (pParams.m_iPart) {
+    case CFWL_Part::Border:
+      DrawBorder(pParams.m_pGraphics.Get(), pParams.m_rtPart, pParams.m_matrix);
       break;
-    }
-    case CFWL_Part::Background: {
-      FillBackground(pParams->m_pGraphics, &pParams->m_rtPart,
-                     &pParams->m_matrix);
+    case CFWL_Part::Background:
+      FillBackground(pParams.m_pGraphics.Get(), pParams.m_rtPart,
+                     pParams.m_matrix);
       break;
-    }
     default:
       break;
   }
diff --git a/xfa/fwl/theme/cfwl_barcodetp.h b/xfa/fwl/theme/cfwl_barcodetp.h
index 42b41e7..8b88fcd 100644
--- a/xfa/fwl/theme/cfwl_barcodetp.h
+++ b/xfa/fwl/theme/cfwl_barcodetp.h
@@ -10,13 +10,13 @@
 #include "xfa/fwl/theme/cfwl_utils.h"
 #include "xfa/fwl/theme/cfwl_widgettp.h"
 
-class CFWL_BarcodeTP : public CFWL_WidgetTP {
+class CFWL_BarcodeTP final : public CFWL_WidgetTP {
  public:
   CFWL_BarcodeTP();
   ~CFWL_BarcodeTP() override;
 
   // CFWL_WidgetTP
-  void DrawBackground(CFWL_ThemeBackground* pParams) override;
+  void DrawBackground(const CFWL_ThemeBackground& pParams) override;
 };
 
 #endif  // XFA_FWL_THEME_CFWL_BARCODETP_H_
diff --git a/xfa/fwl/theme/cfwl_carettp.cpp b/xfa/fwl/theme/cfwl_carettp.cpp
index 9735319..8d32a37 100644
--- a/xfa/fwl/theme/cfwl_carettp.cpp
+++ b/xfa/fwl/theme/cfwl_carettp.cpp
@@ -6,27 +6,25 @@
 
 #include "xfa/fwl/theme/cfwl_carettp.h"
 
+#include "core/fxge/render_defines.h"
 #include "xfa/fwl/cfwl_caret.h"
 #include "xfa/fwl/cfwl_themebackground.h"
 #include "xfa/fwl/cfwl_widget.h"
 #include "xfa/fxgraphics/cxfa_gecolor.h"
 #include "xfa/fxgraphics/cxfa_gepath.h"
 
-CFWL_CaretTP::CFWL_CaretTP() {}
-CFWL_CaretTP::~CFWL_CaretTP() {}
+CFWL_CaretTP::CFWL_CaretTP() = default;
 
-void CFWL_CaretTP::DrawBackground(CFWL_ThemeBackground* pParams) {
-  if (!pParams)
-    return;
+CFWL_CaretTP::~CFWL_CaretTP() = default;
 
-  switch (pParams->m_iPart) {
+void CFWL_CaretTP::DrawBackground(const CFWL_ThemeBackground& pParams) {
+  switch (pParams.m_iPart) {
     case CFWL_Part::Background: {
-      if (!(pParams->m_dwStates & CFWL_PartState_HightLight))
+      if (!(pParams.m_dwStates & CFWL_PartState_HightLight))
         return;
 
-      DrawCaretBK(pParams->m_pGraphics, pParams->m_dwStates,
-                  &(pParams->m_rtPart), (CXFA_GEColor*)pParams->m_pData,
-                  &(pParams->m_matrix));
+      DrawCaretBK(pParams.m_pGraphics.Get(), pParams.m_dwStates,
+                  pParams.m_rtPart, pParams.m_matrix);
       break;
     }
     default:
@@ -36,16 +34,10 @@
 
 void CFWL_CaretTP::DrawCaretBK(CXFA_Graphics* pGraphics,
                                uint32_t dwStates,
-                               const CFX_RectF* pRect,
-                               CXFA_GEColor* crFill,
-                               CFX_Matrix* pMatrix) {
+                               const CFX_RectF& rect,
+                               const CFX_Matrix& matrix) {
   CXFA_GEPath path;
-  CFX_RectF rect = *pRect;
   path.AddRectangle(rect.left, rect.top, rect.width, rect.height);
-  if (crFill) {
-    pGraphics->SetFillColor(*crFill);
-  } else {
-    pGraphics->SetFillColor(CXFA_GEColor(ArgbEncode(255, 0, 0, 0)));
-  }
-  pGraphics->FillPath(&path, FXFILL_WINDING, pMatrix);
+  pGraphics->SetFillColor(CXFA_GEColor(ArgbEncode(255, 0, 0, 0)));
+  pGraphics->FillPath(&path, FXFILL_WINDING, &matrix);
 }
diff --git a/xfa/fwl/theme/cfwl_carettp.h b/xfa/fwl/theme/cfwl_carettp.h
index 8b88fee..a0f9dc5 100644
--- a/xfa/fwl/theme/cfwl_carettp.h
+++ b/xfa/fwl/theme/cfwl_carettp.h
@@ -9,20 +9,19 @@
 
 #include "xfa/fwl/theme/cfwl_widgettp.h"
 
-class CFWL_CaretTP : public CFWL_WidgetTP {
+class CFWL_CaretTP final : public CFWL_WidgetTP {
  public:
   CFWL_CaretTP();
   ~CFWL_CaretTP() override;
 
   // CFWL_WidgetTP
-  void DrawBackground(CFWL_ThemeBackground* pParams) override;
+  void DrawBackground(const CFWL_ThemeBackground& pParams) override;
 
- protected:
+ private:
   void DrawCaretBK(CXFA_Graphics* pGraphics,
                    uint32_t dwStates,
-                   const CFX_RectF* pRect,
-                   CXFA_GEColor* crFill,
-                   CFX_Matrix* pMatrix = nullptr);
+                   const CFX_RectF& rect,
+                   const CFX_Matrix& matrix);
 };
 
 #endif  // XFA_FWL_THEME_CFWL_CARETTP_H_
diff --git a/xfa/fwl/theme/cfwl_checkboxtp.cpp b/xfa/fwl/theme/cfwl_checkboxtp.cpp
index 82fdc1a..3436389 100644
--- a/xfa/fwl/theme/cfwl_checkboxtp.cpp
+++ b/xfa/fwl/theme/cfwl_checkboxtp.cpp
@@ -7,6 +7,7 @@
 #include "xfa/fwl/theme/cfwl_checkboxtp.h"
 
 #include "core/fxge/cfx_pathdata.h"
+#include "core/fxge/render_defines.h"
 #include "third_party/base/ptr_util.h"
 #include "xfa/fde/cfde_textout.h"
 #include "xfa/fwl/cfwl_checkbox.h"
@@ -18,7 +19,7 @@
 
 namespace {
 
-const int kSignPath = 100;
+constexpr int kSignPath = 100;
 
 CFX_PointF ScaleBezierPoint(const CFX_PointF& point) {
   CFX_PointF scaled_point(point);
@@ -29,50 +30,31 @@
 
 }  // namespace
 
-#define CHECKBOX_COLOR_BOXLT1 (ArgbEncode(255, 172, 168, 153))
-#define CHECKBOX_COLOR_BOXLT2 (ArgbEncode(255, 113, 111, 100))
-#define CHECKBOX_COLOR_BOXRB1 (ArgbEncode(255, 241, 239, 226))
-#define CHECKBOX_COLOR_BOXRB2 (ArgbEncode(255, 255, 255, 255))
-
-CFWL_CheckBoxTP::CFWL_CheckBoxTP() : m_pThemeData(new CKBThemeData) {
-  SetThemeData();
-}
+CFWL_CheckBoxTP::CFWL_CheckBoxTP() = default;
 
 CFWL_CheckBoxTP::~CFWL_CheckBoxTP() {
   if (m_pCheckPath)
     m_pCheckPath->Clear();
 }
 
-void CFWL_CheckBoxTP::Initialize() {
-  CFWL_WidgetTP::Initialize();
-  InitTTO();
-}
-
-void CFWL_CheckBoxTP::Finalize() {
-  FinalizeTTO();
-  CFWL_WidgetTP::Finalize();
-}
-
-void CFWL_CheckBoxTP::DrawText(CFWL_ThemeText* pParams) {
-  if (!m_pTextOut)
-    return;
-
-  m_pTextOut->SetTextColor(pParams->m_dwStates & CFWL_PartState_Disabled
+void CFWL_CheckBoxTP::DrawText(const CFWL_ThemeText& pParams) {
+  EnsureTTOInitialized();
+  m_pTextOut->SetTextColor(pParams.m_dwStates & CFWL_PartState_Disabled
                                ? FWLTHEME_CAPACITY_TextDisColor
                                : FWLTHEME_CAPACITY_TextColor);
   CFWL_WidgetTP::DrawText(pParams);
 }
 
 void CFWL_CheckBoxTP::DrawSignCheck(CXFA_Graphics* pGraphics,
-                                    const CFX_RectF* pRtSign,
+                                    const CFX_RectF& rtSign,
                                     FX_ARGB argbFill,
-                                    CFX_Matrix* pMatrix) {
+                                    const CFX_Matrix& matrix) {
   if (!m_pCheckPath)
-    InitCheckPath(pRtSign->width);
+    InitCheckPath(rtSign.width);
 
   CFX_Matrix mt;
-  mt.Translate(pRtSign->left, pRtSign->top);
-  mt.Concat(*pMatrix);
+  mt.Translate(rtSign.left, rtSign.top);
+  mt.Concat(matrix);
   pGraphics->SaveGraphState();
   pGraphics->SetFillColor(CXFA_GEColor(argbFill));
   pGraphics->FillPath(m_pCheckPath.get(), FXFILL_WINDING, &mt);
@@ -80,78 +62,77 @@
 }
 
 void CFWL_CheckBoxTP::DrawSignCircle(CXFA_Graphics* pGraphics,
-                                     const CFX_RectF* pRtSign,
+                                     const CFX_RectF& rtSign,
                                      FX_ARGB argbFill,
-                                     CFX_Matrix* pMatrix) {
+                                     const CFX_Matrix& matrix) {
   CXFA_GEPath path;
-  path.AddEllipse(*pRtSign);
+  path.AddEllipse(rtSign);
   pGraphics->SaveGraphState();
   pGraphics->SetFillColor(CXFA_GEColor(argbFill));
-  pGraphics->FillPath(&path, FXFILL_WINDING, pMatrix);
+  pGraphics->FillPath(&path, FXFILL_WINDING, &matrix);
   pGraphics->RestoreGraphState();
 }
 
 void CFWL_CheckBoxTP::DrawSignCross(CXFA_Graphics* pGraphics,
-                                    const CFX_RectF* pRtSign,
+                                    const CFX_RectF& rtSign,
                                     FX_ARGB argbFill,
-                                    CFX_Matrix* pMatrix) {
+                                    const CFX_Matrix& matrix) {
   CXFA_GEPath path;
-  float fRight = pRtSign->right();
-  float fBottom = pRtSign->bottom();
-  path.AddLine(pRtSign->TopLeft(), CFX_PointF(fRight, fBottom));
-  path.AddLine(CFX_PointF(pRtSign->left, fBottom),
-               CFX_PointF(fRight, pRtSign->top));
+  float fRight = rtSign.right();
+  float fBottom = rtSign.bottom();
+  path.AddLine(rtSign.TopLeft(), CFX_PointF(fRight, fBottom));
+  path.AddLine(CFX_PointF(rtSign.left, fBottom),
+               CFX_PointF(fRight, rtSign.top));
 
   pGraphics->SaveGraphState();
   pGraphics->SetStrokeColor(CXFA_GEColor(argbFill));
   pGraphics->SetLineWidth(1.0f);
-  pGraphics->StrokePath(&path, pMatrix);
+  pGraphics->StrokePath(&path, &matrix);
   pGraphics->RestoreGraphState();
 }
 
 void CFWL_CheckBoxTP::DrawSignDiamond(CXFA_Graphics* pGraphics,
-                                      const CFX_RectF* pRtSign,
+                                      const CFX_RectF& rtSign,
                                       FX_ARGB argbFill,
-                                      CFX_Matrix* pMatrix) {
+                                      const CFX_Matrix& matrix) {
   CXFA_GEPath path;
-  float fWidth = pRtSign->width;
-  float fHeight = pRtSign->height;
-  float fBottom = pRtSign->bottom();
-  path.MoveTo(CFX_PointF(pRtSign->left + fWidth / 2, pRtSign->top));
-  path.LineTo(CFX_PointF(pRtSign->left, pRtSign->top + fHeight / 2));
-  path.LineTo(CFX_PointF(pRtSign->left + fWidth / 2, fBottom));
-  path.LineTo(CFX_PointF(pRtSign->right(), pRtSign->top + fHeight / 2));
-  path.LineTo(CFX_PointF(pRtSign->left + fWidth / 2, pRtSign->top));
+  float fWidth = rtSign.width;
+  float fHeight = rtSign.height;
+  float fBottom = rtSign.bottom();
+  path.MoveTo(CFX_PointF(rtSign.left + fWidth / 2, rtSign.top));
+  path.LineTo(CFX_PointF(rtSign.left, rtSign.top + fHeight / 2));
+  path.LineTo(CFX_PointF(rtSign.left + fWidth / 2, fBottom));
+  path.LineTo(CFX_PointF(rtSign.right(), rtSign.top + fHeight / 2));
+  path.LineTo(CFX_PointF(rtSign.left + fWidth / 2, rtSign.top));
 
   pGraphics->SaveGraphState();
   pGraphics->SetFillColor(CXFA_GEColor(argbFill));
-  pGraphics->FillPath(&path, FXFILL_WINDING, pMatrix);
+  pGraphics->FillPath(&path, FXFILL_WINDING, &matrix);
   pGraphics->RestoreGraphState();
 }
 
 void CFWL_CheckBoxTP::DrawSignSquare(CXFA_Graphics* pGraphics,
-                                     const CFX_RectF* pRtSign,
+                                     const CFX_RectF& rtSign,
                                      FX_ARGB argbFill,
-                                     CFX_Matrix* pMatrix) {
+                                     const CFX_Matrix& matrix) {
   CXFA_GEPath path;
-  path.AddRectangle(pRtSign->left, pRtSign->top, pRtSign->width,
-                    pRtSign->height);
+  path.AddRectangle(rtSign.left, rtSign.top, rtSign.width, rtSign.height);
   pGraphics->SaveGraphState();
   pGraphics->SetFillColor(CXFA_GEColor(argbFill));
-  pGraphics->FillPath(&path, FXFILL_WINDING, pMatrix);
+  pGraphics->FillPath(&path, FXFILL_WINDING, &matrix);
   pGraphics->RestoreGraphState();
 }
 
 void CFWL_CheckBoxTP::DrawSignStar(CXFA_Graphics* pGraphics,
-                                   const CFX_RectF* pRtSign,
+                                   const CFX_RectF& rtSign,
                                    FX_ARGB argbFill,
-                                   CFX_Matrix* pMatrix) {
+                                   const CFX_Matrix& matrix) {
   CXFA_GEPath path;
-  float fBottom = pRtSign->bottom();
+  float fBottom = rtSign.bottom();
   float fRadius =
-      (pRtSign->top - fBottom) / (1 + static_cast<float>(cos(FX_PI / 5.0f)));
-  CFX_PointF ptCenter((pRtSign->left + pRtSign->right()) / 2.0f,
-                      (pRtSign->top + fBottom) / 2.0f);
+      (rtSign.top - fBottom) / (1 + static_cast<float>(cos(FX_PI / 5.0f)));
+  CFX_PointF ptCenter((rtSign.left + rtSign.right()) / 2.0f,
+                      (rtSign.top + fBottom) / 2.0f);
 
   CFX_PointF points[5];
   float fAngel = FX_PI / 10.0f;
@@ -173,48 +154,10 @@
   }
   pGraphics->SaveGraphState();
   pGraphics->SetFillColor(CXFA_GEColor(argbFill));
-  pGraphics->FillPath(&path, FXFILL_WINDING, pMatrix);
+  pGraphics->FillPath(&path, FXFILL_WINDING, &matrix);
   pGraphics->RestoreGraphState();
 }
 
-void CFWL_CheckBoxTP::SetThemeData() {
-  uint32_t* pData = (uint32_t*)&m_pThemeData->clrBoxBk;
-
-  *pData++ = 0;
-  *pData++ = 0;
-  *pData++ = ArgbEncode(255, 220, 220, 215),
-  *pData++ = ArgbEncode(255, 255, 255, 255),
-  *pData++ = ArgbEncode(255, 255, 240, 207),
-  *pData++ = ArgbEncode(255, 248, 179, 48),
-  *pData++ = ArgbEncode(255, 176, 176, 167),
-  *pData++ = ArgbEncode(255, 241, 239, 239),
-  *pData++ = ArgbEncode(255, 255, 255, 255),
-  *pData++ = ArgbEncode(255, 255, 255, 255),
-  *pData++ = ArgbEncode(255, 220, 220, 215),
-  *pData++ = ArgbEncode(255, 255, 255, 255),
-  *pData++ = ArgbEncode(255, 255, 240, 207),
-  *pData++ = ArgbEncode(255, 248, 179, 48),
-  *pData++ = ArgbEncode(255, 176, 176, 167),
-  *pData++ = ArgbEncode(255, 241, 239, 239),
-  *pData++ = ArgbEncode(255, 255, 255, 255),
-  *pData++ = ArgbEncode(255, 255, 255, 255),
-  *pData++ = ArgbEncode(255, 220, 220, 215),
-  *pData++ = ArgbEncode(255, 255, 255, 255),
-  *pData++ = ArgbEncode(255, 255, 240, 207),
-  *pData++ = ArgbEncode(255, 248, 179, 48),
-  *pData++ = ArgbEncode(255, 176, 176, 167),
-  *pData++ = ArgbEncode(255, 241, 239, 239),
-  *pData++ = ArgbEncode(255, 255, 255, 255),
-  *pData++ = ArgbEncode(255, 255, 255, 255);
-  m_pThemeData->clrSignBorderNormal = ArgbEncode(255, 28, 81, 128);
-  m_pThemeData->clrSignBorderDisable = ArgbEncode(255, 202, 200, 187);
-  m_pThemeData->clrSignCheck = ArgbEncode(255, 28, 81, 128);
-  m_pThemeData->clrSignNeutral = ArgbEncode(255, 28, 134, 26);
-  m_pThemeData->clrSignNeutralNormal = ArgbEncode(255, 114, 192, 113);
-  m_pThemeData->clrSignNeutralHover = ArgbEncode(255, 33, 161, 33);
-  m_pThemeData->clrSignNeutralPressed = ArgbEncode(255, 28, 134, 26);
-}
-
 void CFWL_CheckBoxTP::InitCheckPath(float fCheckLen) {
   if (!m_pCheckPath) {
     m_pCheckPath = pdfium::MakeUnique<CXFA_GEPath>();
@@ -269,14 +212,14 @@
   }
 }
 
-void CFWL_CheckBoxTP::DrawBackground(CFWL_ThemeBackground* pParams) {
-  if (pParams->m_iPart != CFWL_Part::CheckBox)
+void CFWL_CheckBoxTP::DrawBackground(const CFWL_ThemeBackground& pParams) {
+  if (pParams.m_iPart != CFWL_Part::CheckBox)
     return;
 
-  if ((pParams->m_dwStates & CFWL_PartState_Checked) ||
-      (pParams->m_dwStates & CFWL_PartState_Neutral)) {
-    DrawCheckSign(pParams->m_pWidget, pParams->m_pGraphics, pParams->m_rtPart,
-                  pParams->m_dwStates, &pParams->m_matrix);
+  if ((pParams.m_dwStates & CFWL_PartState_Checked) ||
+      (pParams.m_dwStates & CFWL_PartState_Neutral)) {
+    DrawCheckSign(pParams.m_pWidget, pParams.m_pGraphics.Get(),
+                  pParams.m_rtPart, pParams.m_dwStates, pParams.m_matrix);
   }
 }
 
@@ -284,7 +227,7 @@
                                     CXFA_Graphics* pGraphics,
                                     const CFX_RectF& pRtBox,
                                     int32_t iState,
-                                    CFX_Matrix* pMatrix) {
+                                    const CFX_Matrix& matrix) {
   CFX_RectF rtSign(pRtBox);
   uint32_t dwColor = iState & CFWL_PartState_Neutral ? 0xFFA9A9A9 : 0xFF000000;
 
@@ -292,22 +235,22 @@
   rtSign.Deflate(rtSign.width / 4, rtSign.height / 4);
   switch (dwStyle & FWL_STYLEEXT_CKB_SignShapeMask) {
     case FWL_STYLEEXT_CKB_SignShapeCheck:
-      DrawSignCheck(pGraphics, &rtSign, dwColor, pMatrix);
+      DrawSignCheck(pGraphics, rtSign, dwColor, matrix);
       break;
     case FWL_STYLEEXT_CKB_SignShapeCircle:
-      DrawSignCircle(pGraphics, &rtSign, dwColor, pMatrix);
+      DrawSignCircle(pGraphics, rtSign, dwColor, matrix);
       break;
     case FWL_STYLEEXT_CKB_SignShapeCross:
-      DrawSignCross(pGraphics, &rtSign, dwColor, pMatrix);
+      DrawSignCross(pGraphics, rtSign, dwColor, matrix);
       break;
     case FWL_STYLEEXT_CKB_SignShapeDiamond:
-      DrawSignDiamond(pGraphics, &rtSign, dwColor, pMatrix);
+      DrawSignDiamond(pGraphics, rtSign, dwColor, matrix);
       break;
     case FWL_STYLEEXT_CKB_SignShapeSquare:
-      DrawSignSquare(pGraphics, &rtSign, dwColor, pMatrix);
+      DrawSignSquare(pGraphics, rtSign, dwColor, matrix);
       break;
     case FWL_STYLEEXT_CKB_SignShapeStar:
-      DrawSignStar(pGraphics, &rtSign, dwColor, pMatrix);
+      DrawSignStar(pGraphics, rtSign, dwColor, matrix);
       break;
     default:
       break;
diff --git a/xfa/fwl/theme/cfwl_checkboxtp.h b/xfa/fwl/theme/cfwl_checkboxtp.h
index e373b38..e79a693 100644
--- a/xfa/fwl/theme/cfwl_checkboxtp.h
+++ b/xfa/fwl/theme/cfwl_checkboxtp.h
@@ -9,69 +9,53 @@
 
 #include <memory>
 
-#include "xfa/fwl/theme/cfwl_utils.h"
 #include "xfa/fwl/theme/cfwl_widgettp.h"
 
-class CFWL_CheckBoxTP : public CFWL_WidgetTP {
+class CFWL_Widget;
+
+class CFWL_CheckBoxTP final : public CFWL_WidgetTP {
  public:
   CFWL_CheckBoxTP();
   ~CFWL_CheckBoxTP() override;
 
-  // CFWL_WidgeTP
-  void Initialize() override;
-  void Finalize() override;
-  void DrawText(CFWL_ThemeText* pParams) override;
-  void DrawBackground(CFWL_ThemeBackground* pParams) override;
+  // CFWL_WidgetTP
+  void DrawBackground(const CFWL_ThemeBackground& pParams) override;
+  void DrawText(const CFWL_ThemeText& pParams) override;
 
- protected:
-  struct CKBThemeData {
-    FX_ARGB clrBoxBk[13][2];
-    FX_ARGB clrSignBorderNormal;
-    FX_ARGB clrSignBorderDisable;
-    FX_ARGB clrSignCheck;
-    FX_ARGB clrSignNeutral;
-    FX_ARGB clrSignNeutralNormal;
-    FX_ARGB clrSignNeutralHover;
-    FX_ARGB clrSignNeutralPressed;
-  };
-
+ private:
   void DrawCheckSign(CFWL_Widget* pWidget,
                      CXFA_Graphics* pGraphics,
                      const CFX_RectF& pRtBox,
                      int32_t iState,
-                     CFX_Matrix* pMatrix);
+                     const CFX_Matrix& matrix);
   void DrawSignCheck(CXFA_Graphics* pGraphics,
-                     const CFX_RectF* pRtSign,
+                     const CFX_RectF& rtSign,
                      FX_ARGB argbFill,
-                     CFX_Matrix* pMatrix);
+                     const CFX_Matrix& matrix);
   void DrawSignCircle(CXFA_Graphics* pGraphics,
-                      const CFX_RectF* pRtSign,
+                      const CFX_RectF& rtSign,
                       FX_ARGB argbFill,
-                      CFX_Matrix* pMatrix);
+                      const CFX_Matrix& matrix);
   void DrawSignCross(CXFA_Graphics* pGraphics,
-                     const CFX_RectF* pRtSign,
+                     const CFX_RectF& rtSign,
                      FX_ARGB argbFill,
-                     CFX_Matrix* pMatrix);
+                     const CFX_Matrix& matrix);
   void DrawSignDiamond(CXFA_Graphics* pGraphics,
-                       const CFX_RectF* pRtSign,
+                       const CFX_RectF& rtSign,
                        FX_ARGB argbFill,
-                       CFX_Matrix* pMatrix);
+                       const CFX_Matrix& matrix);
   void DrawSignSquare(CXFA_Graphics* pGraphics,
-                      const CFX_RectF* pRtSign,
+                      const CFX_RectF& rtSign,
                       FX_ARGB argbFill,
-                      CFX_Matrix* pMatrix);
+                      const CFX_Matrix& matrix);
   void DrawSignStar(CXFA_Graphics* pGraphics,
-                    const CFX_RectF* pRtSign,
+                    const CFX_RectF& rtSign,
                     FX_ARGB argbFill,
-                    CFX_Matrix* pMatrix);
+                    const CFX_Matrix& matrix);
 
   void InitCheckPath(float fCheckLen);
 
-  std::unique_ptr<CKBThemeData> m_pThemeData;
   std::unique_ptr<CXFA_GEPath> m_pCheckPath;
-
- private:
-  void SetThemeData();
 };
 
 #endif  // XFA_FWL_THEME_CFWL_CHECKBOXTP_H_
diff --git a/xfa/fwl/theme/cfwl_comboboxtp.cpp b/xfa/fwl/theme/cfwl_comboboxtp.cpp
index 7695342..6cc842d 100644
--- a/xfa/fwl/theme/cfwl_comboboxtp.cpp
+++ b/xfa/fwl/theme/cfwl_comboboxtp.cpp
@@ -6,6 +6,7 @@
 
 #include "xfa/fwl/theme/cfwl_comboboxtp.h"
 
+#include "core/fxge/render_defines.h"
 #include "xfa/fwl/cfwl_combobox.h"
 #include "xfa/fwl/cfwl_themebackground.h"
 #include "xfa/fwl/cfwl_widget.h"
@@ -13,25 +14,22 @@
 #include "xfa/fxgraphics/cxfa_gecolor.h"
 #include "xfa/fxgraphics/cxfa_gepath.h"
 
-CFWL_ComboBoxTP::CFWL_ComboBoxTP() {}
+CFWL_ComboBoxTP::CFWL_ComboBoxTP() = default;
 
-CFWL_ComboBoxTP::~CFWL_ComboBoxTP() {}
+CFWL_ComboBoxTP::~CFWL_ComboBoxTP() = default;
 
-void CFWL_ComboBoxTP::DrawBackground(CFWL_ThemeBackground* pParams) {
-  if (!pParams)
-    return;
-
-  switch (pParams->m_iPart) {
+void CFWL_ComboBoxTP::DrawBackground(const CFWL_ThemeBackground& pParams) {
+  switch (pParams.m_iPart) {
     case CFWL_Part::Border: {
-      DrawBorder(pParams->m_pGraphics, &pParams->m_rtPart, &pParams->m_matrix);
+      DrawBorder(pParams.m_pGraphics.Get(), pParams.m_rtPart, pParams.m_matrix);
       break;
     }
     case CFWL_Part::Background: {
       CXFA_GEPath path;
-      CFX_RectF& rect = pParams->m_rtPart;
+      const CFX_RectF& rect = pParams.m_rtPart;
       path.AddRectangle(rect.left, rect.top, rect.width, rect.height);
       FX_ARGB argb_color;
-      switch (pParams->m_dwStates) {
+      switch (pParams.m_dwStates) {
         case CFWL_PartState_Selected:
           argb_color = FWLTHEME_COLOR_BKSelected;
           break;
@@ -41,18 +39,14 @@
         default:
           argb_color = 0xFFFFFFFF;
       }
-      pParams->m_pGraphics->SaveGraphState();
-      pParams->m_pGraphics->SetFillColor(CXFA_GEColor(argb_color));
-      pParams->m_pGraphics->FillPath(&path, FXFILL_WINDING, &pParams->m_matrix);
-      pParams->m_pGraphics->RestoreGraphState();
+      pParams.m_pGraphics->SaveGraphState();
+      pParams.m_pGraphics->SetFillColor(CXFA_GEColor(argb_color));
+      pParams.m_pGraphics->FillPath(&path, FXFILL_WINDING, &pParams.m_matrix);
+      pParams.m_pGraphics->RestoreGraphState();
       break;
     }
     case CFWL_Part::DropDownButton: {
-      DrawDropDownButton(pParams, pParams->m_dwStates, &pParams->m_matrix);
-      break;
-    }
-    case CFWL_Part::StretchHandler: {
-      DrawStrethHandler(pParams, 0, &pParams->m_matrix);
+      DrawDropDownButton(pParams, pParams.m_dwStates, pParams.m_matrix);
       break;
     }
     default:
@@ -60,20 +54,9 @@
   }
 }
 
-void CFWL_ComboBoxTP::DrawStrethHandler(CFWL_ThemeBackground* pParams,
-                                        uint32_t dwStates,
-                                        CFX_Matrix* pMatrix) {
-  CXFA_GEPath path;
-  path.AddRectangle(pParams->m_rtPart.left, pParams->m_rtPart.top,
-                    pParams->m_rtPart.width - 1, pParams->m_rtPart.height);
-  pParams->m_pGraphics->SetFillColor(
-      CXFA_GEColor(ArgbEncode(0xff, 0xff, 0, 0)));
-  pParams->m_pGraphics->FillPath(&path, FXFILL_WINDING, &pParams->m_matrix);
-}
-
-void CFWL_ComboBoxTP::DrawDropDownButton(CFWL_ThemeBackground* pParams,
+void CFWL_ComboBoxTP::DrawDropDownButton(const CFWL_ThemeBackground& pParams,
                                          uint32_t dwStates,
-                                         CFX_Matrix* pMatrix) {
+                                         const CFX_Matrix& matrix) {
   FWLTHEME_STATE eState = FWLTHEME_STATE_Normal;
   switch (dwStates) {
     case CFWL_PartState_Normal: {
@@ -95,6 +78,6 @@
     default:
       break;
   }
-  DrawArrowBtn(pParams->m_pGraphics, &pParams->m_rtPart,
-               FWLTHEME_DIRECTION_Down, eState, &pParams->m_matrix);
+  DrawArrowBtn(pParams.m_pGraphics.Get(), pParams.m_rtPart,
+               FWLTHEME_DIRECTION_Down, eState, pParams.m_matrix);
 }
diff --git a/xfa/fwl/theme/cfwl_comboboxtp.h b/xfa/fwl/theme/cfwl_comboboxtp.h
index 183d3a0..b3a75a5 100644
--- a/xfa/fwl/theme/cfwl_comboboxtp.h
+++ b/xfa/fwl/theme/cfwl_comboboxtp.h
@@ -9,21 +9,18 @@
 
 #include "xfa/fwl/theme/cfwl_widgettp.h"
 
-class CFWL_ComboBoxTP : public CFWL_WidgetTP {
+class CFWL_ComboBoxTP final : public CFWL_WidgetTP {
  public:
   CFWL_ComboBoxTP();
   ~CFWL_ComboBoxTP() override;
 
   // CFWL_WidgetTP
-  void DrawBackground(CFWL_ThemeBackground* pParams) override;
+  void DrawBackground(const CFWL_ThemeBackground& pParams) override;
 
- protected:
-  void DrawDropDownButton(CFWL_ThemeBackground* pParams,
+ private:
+  void DrawDropDownButton(const CFWL_ThemeBackground& pParams,
                           uint32_t dwStates,
-                          CFX_Matrix* pMatrix);
-  void DrawStrethHandler(CFWL_ThemeBackground* pParams,
-                         uint32_t dwStates,
-                         CFX_Matrix* pMatrix);
+                          const CFX_Matrix& matrix);
 };
 
 #endif  // XFA_FWL_THEME_CFWL_COMBOBOXTP_H_
diff --git a/xfa/fwl/theme/cfwl_datetimepickertp.cpp b/xfa/fwl/theme/cfwl_datetimepickertp.cpp
index 8902ef9..a185952 100644
--- a/xfa/fwl/theme/cfwl_datetimepickertp.cpp
+++ b/xfa/fwl/theme/cfwl_datetimepickertp.cpp
@@ -13,27 +13,24 @@
 
 CFWL_DateTimePickerTP::~CFWL_DateTimePickerTP() {}
 
-void CFWL_DateTimePickerTP::DrawBackground(CFWL_ThemeBackground* pParams) {
-  if (!pParams)
-    return;
-
-  switch (pParams->m_iPart) {
-    case CFWL_Part::Border: {
-      DrawBorder(pParams->m_pGraphics, &pParams->m_rtPart, &pParams->m_matrix);
+void CFWL_DateTimePickerTP::DrawBackground(
+    const CFWL_ThemeBackground& pParams) {
+  switch (pParams.m_iPart) {
+    case CFWL_Part::Border:
+      DrawBorder(pParams.m_pGraphics.Get(), pParams.m_rtPart, pParams.m_matrix);
       break;
-    }
-    case CFWL_Part::DropDownButton: {
-      DrawDropDownButton(pParams, &pParams->m_matrix);
+    case CFWL_Part::DropDownButton:
+      DrawDropDownButton(pParams, pParams.m_matrix);
       break;
-    }
     default:
       break;
   }
 }
 
-void CFWL_DateTimePickerTP::DrawDropDownButton(CFWL_ThemeBackground* pParams,
-                                               CFX_Matrix* pMatrix) {
-  uint32_t dwStates = pParams->m_dwStates;
+void CFWL_DateTimePickerTP::DrawDropDownButton(
+    const CFWL_ThemeBackground& pParams,
+    const CFX_Matrix& matrix) {
+  uint32_t dwStates = pParams.m_dwStates;
   dwStates &= 0x03;
   FWLTHEME_STATE eState = FWLTHEME_STATE_Normal;
   switch (eState & dwStates) {
@@ -56,7 +53,6 @@
     default:
       break;
   }
-  DrawArrowBtn(pParams->m_pGraphics, &pParams->m_rtPart,
-               FWLTHEME_DIRECTION_Down, eState, pMatrix);
+  DrawArrowBtn(pParams.m_pGraphics.Get(), pParams.m_rtPart,
+               FWLTHEME_DIRECTION_Down, eState, matrix);
 }
-
diff --git a/xfa/fwl/theme/cfwl_datetimepickertp.h b/xfa/fwl/theme/cfwl_datetimepickertp.h
index 11536a3..e7163e0 100644
--- a/xfa/fwl/theme/cfwl_datetimepickertp.h
+++ b/xfa/fwl/theme/cfwl_datetimepickertp.h
@@ -9,16 +9,17 @@
 
 #include "xfa/fwl/theme/cfwl_widgettp.h"
 
-class CFWL_DateTimePickerTP : public CFWL_WidgetTP {
+class CFWL_DateTimePickerTP final : public CFWL_WidgetTP {
  public:
   CFWL_DateTimePickerTP();
   ~CFWL_DateTimePickerTP() override;
 
   // CFWL_WidgetTP
-  void DrawBackground(CFWL_ThemeBackground* pParams) override;
+  void DrawBackground(const CFWL_ThemeBackground& pParams) override;
 
- protected:
-  void DrawDropDownButton(CFWL_ThemeBackground* pParams, CFX_Matrix* pMatrix);
+ private:
+  void DrawDropDownButton(const CFWL_ThemeBackground& pParams,
+                          const CFX_Matrix& matrix);
 };
 
 #endif  // XFA_FWL_THEME_CFWL_DATETIMEPICKERTP_H_
diff --git a/xfa/fwl/theme/cfwl_edittp.cpp b/xfa/fwl/theme/cfwl_edittp.cpp
index 599a4dd..cacdf09 100644
--- a/xfa/fwl/theme/cfwl_edittp.cpp
+++ b/xfa/fwl/theme/cfwl_edittp.cpp
@@ -6,77 +6,67 @@
 
 #include "xfa/fwl/theme/cfwl_edittp.h"
 
+#include "core/fxge/render_defines.h"
 #include "xfa/fwl/cfwl_edit.h"
 #include "xfa/fwl/cfwl_themebackground.h"
 #include "xfa/fwl/cfwl_widget.h"
-#include "xfa/fxfa/cxfa_ffwidget.h"
-#include "xfa/fxfa/cxfa_fwltheme.h"
-#include "xfa/fxfa/parser/cxfa_border.h"
-#include "xfa/fxfa/parser/cxfa_edge.h"
 #include "xfa/fxgraphics/cxfa_gecolor.h"
 #include "xfa/fxgraphics/cxfa_gepath.h"
 
-CFWL_EditTP::CFWL_EditTP() {}
+CFWL_EditTP::CFWL_EditTP() = default;
 
-CFWL_EditTP::~CFWL_EditTP() {}
+CFWL_EditTP::~CFWL_EditTP() = default;
 
-void CFWL_EditTP::DrawBackground(CFWL_ThemeBackground* pParams) {
-  if (CFWL_Part::CombTextLine == pParams->m_iPart) {
-    CXFA_FFWidget* pWidget = XFA_ThemeGetOuterWidget(pParams->m_pWidget);
-    CXFA_Border* borderUI = pWidget->GetNode()->GetWidgetAcc()->GetUIBorder();
+void CFWL_EditTP::DrawBackground(const CFWL_ThemeBackground& pParams) {
+  if (CFWL_Part::CombTextLine == pParams.m_iPart) {
+    CFWL_Widget::AdapterIface* pWidget =
+        pParams.m_pWidget->GetOutmost()->GetAdapterIface();
     FX_ARGB cr = 0xFF000000;
     float fWidth = 1.0f;
-    if (borderUI) {
-      CXFA_Edge* edge = borderUI->GetEdgeIfExists(0);
-      if (edge) {
-        cr = edge->GetColor();
-        fWidth = edge->GetThickness();
-      }
-    }
-    pParams->m_pGraphics->SetStrokeColor(CXFA_GEColor(cr));
-    pParams->m_pGraphics->SetLineWidth(fWidth);
-    pParams->m_pGraphics->StrokePath(pParams->m_pPath, &pParams->m_matrix);
+    pWidget->GetBorderColorAndThickness(&cr, &fWidth);
+    pParams.m_pGraphics->SetStrokeColor(CXFA_GEColor(cr));
+    pParams.m_pGraphics->SetLineWidth(fWidth);
+    pParams.m_pGraphics->StrokePath(pParams.m_pPath.Get(), &pParams.m_matrix);
     return;
   }
 
-  switch (pParams->m_iPart) {
+  switch (pParams.m_iPart) {
     case CFWL_Part::Border: {
-      DrawBorder(pParams->m_pGraphics, &pParams->m_rtPart, &pParams->m_matrix);
+      DrawBorder(pParams.m_pGraphics.Get(), pParams.m_rtPart, pParams.m_matrix);
       break;
     }
     case CFWL_Part::Background: {
-      if (pParams->m_pPath) {
-        CXFA_Graphics* pGraphics = pParams->m_pGraphics;
+      if (pParams.m_pPath) {
+        CXFA_Graphics* pGraphics = pParams.m_pGraphics.Get();
         pGraphics->SaveGraphState();
         pGraphics->SetFillColor(CXFA_GEColor(FWLTHEME_COLOR_BKSelected));
-        pGraphics->FillPath(pParams->m_pPath, FXFILL_WINDING,
-                            &pParams->m_matrix);
+        pGraphics->FillPath(pParams.m_pPath.Get(), FXFILL_WINDING,
+                            &pParams.m_matrix);
         pGraphics->RestoreGraphState();
       } else {
         CXFA_GEPath path;
-        path.AddRectangle(pParams->m_rtPart.left, pParams->m_rtPart.top,
-                          pParams->m_rtPart.width, pParams->m_rtPart.height);
+        path.AddRectangle(pParams.m_rtPart.left, pParams.m_rtPart.top,
+                          pParams.m_rtPart.width, pParams.m_rtPart.height);
         CXFA_GEColor cr(FWLTHEME_COLOR_Background);
-        if (!pParams->m_bStaticBackground) {
-          if (pParams->m_dwStates & CFWL_PartState_Disabled)
+        if (!pParams.m_bStaticBackground) {
+          if (pParams.m_dwStates & CFWL_PartState_Disabled)
             cr = CXFA_GEColor(FWLTHEME_COLOR_EDGERB1);
-          else if (pParams->m_dwStates & CFWL_PartState_ReadOnly)
+          else if (pParams.m_dwStates & CFWL_PartState_ReadOnly)
             cr = CXFA_GEColor(ArgbEncode(255, 236, 233, 216));
           else
             cr = CXFA_GEColor(0xFFFFFFFF);
         }
-        pParams->m_pGraphics->SaveGraphState();
-        pParams->m_pGraphics->SetFillColor(cr);
-        pParams->m_pGraphics->FillPath(&path, FXFILL_WINDING,
-                                       &pParams->m_matrix);
-        pParams->m_pGraphics->RestoreGraphState();
+        pParams.m_pGraphics->SaveGraphState();
+        pParams.m_pGraphics->SetFillColor(cr);
+        pParams.m_pGraphics->FillPath(&path, FXFILL_WINDING, &pParams.m_matrix);
+        pParams.m_pGraphics->RestoreGraphState();
       }
       break;
     }
     case CFWL_Part::CombTextLine: {
-      pParams->m_pGraphics->SetStrokeColor(CXFA_GEColor(0xFF000000));
-      pParams->m_pGraphics->SetLineWidth(1.0f);
-      pParams->m_pGraphics->StrokePath(pParams->m_pPath, &pParams->m_matrix);
+      pParams.m_pGraphics->SetStrokeColor(CXFA_GEColor(0xFF000000));
+      pParams.m_pGraphics->SetLineWidth(1.0f);
+      pParams.m_pGraphics->StrokePath(pParams.m_pPath.Get(), &pParams.m_matrix);
       break;
     }
     default:
diff --git a/xfa/fwl/theme/cfwl_edittp.h b/xfa/fwl/theme/cfwl_edittp.h
index e1c6ac9..b5b58f3 100644
--- a/xfa/fwl/theme/cfwl_edittp.h
+++ b/xfa/fwl/theme/cfwl_edittp.h
@@ -9,13 +9,13 @@
 
 #include "xfa/fwl/theme/cfwl_widgettp.h"
 
-class CFWL_EditTP : public CFWL_WidgetTP {
+class CFWL_EditTP final : public CFWL_WidgetTP {
  public:
   CFWL_EditTP();
   ~CFWL_EditTP() override;
 
-  // CFWL_WidgeTTP
-  void DrawBackground(CFWL_ThemeBackground* pParams) override;
+  // CFWL_WidgetTP
+  void DrawBackground(const CFWL_ThemeBackground& pParams) override;
 };
 
 #endif  // XFA_FWL_THEME_CFWL_EDITTP_H_
diff --git a/xfa/fwl/theme/cfwl_listboxtp.cpp b/xfa/fwl/theme/cfwl_listboxtp.cpp
index 6b8aa76..28b5e34 100644
--- a/xfa/fwl/theme/cfwl_listboxtp.cpp
+++ b/xfa/fwl/theme/cfwl_listboxtp.cpp
@@ -6,48 +6,48 @@
 
 #include "xfa/fwl/theme/cfwl_listboxtp.h"
 
+#include "build/build_config.h"
+#include "core/fxge/render_defines.h"
 #include "xfa/fwl/cfwl_listbox.h"
 #include "xfa/fwl/cfwl_themebackground.h"
 #include "xfa/fwl/cfwl_widget.h"
 #include "xfa/fxgraphics/cxfa_gecolor.h"
 #include "xfa/fxgraphics/cxfa_gepath.h"
 
-CFWL_ListBoxTP::CFWL_ListBoxTP() {}
+CFWL_ListBoxTP::CFWL_ListBoxTP() = default;
 
-CFWL_ListBoxTP::~CFWL_ListBoxTP() {}
+CFWL_ListBoxTP::~CFWL_ListBoxTP() = default;
 
-void CFWL_ListBoxTP::DrawBackground(CFWL_ThemeBackground* pParams) {
-  if (!pParams)
-    return;
-
-  switch (pParams->m_iPart) {
+void CFWL_ListBoxTP::DrawBackground(const CFWL_ThemeBackground& pParams) {
+  switch (pParams.m_iPart) {
     case CFWL_Part::Border: {
-      DrawBorder(pParams->m_pGraphics, &pParams->m_rtPart, &pParams->m_matrix);
+      DrawBorder(pParams.m_pGraphics.Get(), pParams.m_rtPart, pParams.m_matrix);
       break;
     }
     case CFWL_Part::Background: {
-      FillSoildRect(pParams->m_pGraphics, ArgbEncode(255, 255, 255, 255),
-                    &pParams->m_rtPart, &pParams->m_matrix);
-      if (pParams->m_pData) {
-        FillSoildRect(pParams->m_pGraphics, FWLTHEME_COLOR_Background,
-                      (CFX_RectF*)pParams->m_pData, &pParams->m_matrix);
+      FillSolidRect(pParams.m_pGraphics.Get(), ArgbEncode(255, 255, 255, 255),
+                    pParams.m_rtPart, pParams.m_matrix);
+      if (pParams.m_pRtData) {
+        FillSolidRect(pParams.m_pGraphics.Get(), FWLTHEME_COLOR_Background,
+                      *pParams.m_pRtData, pParams.m_matrix);
       }
       break;
     }
     case CFWL_Part::ListItem: {
-      DrawListBoxItem(pParams->m_pGraphics, pParams->m_dwStates,
-                      &pParams->m_rtPart, pParams->m_pData, &pParams->m_matrix);
+      DrawListBoxItem(pParams.m_pGraphics.Get(), pParams.m_dwStates,
+                      pParams.m_rtPart, pParams.m_pRtData, pParams.m_matrix);
       break;
     }
     case CFWL_Part::Check: {
       uint32_t color = 0xFF000000;
-      if (pParams->m_dwStates == CFWL_PartState_Checked) {
+      if (pParams.m_dwStates == CFWL_PartState_Checked) {
         color = 0xFFFF0000;
-      } else if (pParams->m_dwStates == CFWL_PartState_Normal) {
+      } else if (pParams.m_dwStates == CFWL_PartState_Normal) {
         color = 0xFF0000FF;
       }
-      FillSoildRect(pParams->m_pGraphics, color, &pParams->m_rtPart,
-                    &pParams->m_matrix);
+      FillSolidRect(pParams.m_pGraphics.Get(), color, pParams.m_rtPart,
+                    pParams.m_matrix);
+      break;
     }
     default:
       break;
@@ -56,22 +56,22 @@
 
 void CFWL_ListBoxTP::DrawListBoxItem(CXFA_Graphics* pGraphics,
                                      uint32_t dwStates,
-                                     const CFX_RectF* prtItem,
-                                     void* pData,
-                                     CFX_Matrix* pMatrix) {
+                                     const CFX_RectF& rtItem,
+                                     const CFX_RectF* pData,
+                                     const CFX_Matrix& matrix) {
   if (dwStates & CFWL_PartState_Selected) {
     pGraphics->SaveGraphState();
     pGraphics->SetFillColor(CXFA_GEColor(FWLTHEME_COLOR_BKSelected));
-    CFX_RectF rt(*prtItem);
     CXFA_GEPath path;
-#if (_FX_OS_ == _FX_OS_MACOSX_)
-    path.AddRectangle(rt.left, rt.top, rt.width - 1, rt.height - 1);
+#if defined(OS_MACOSX)
+    path.AddRectangle(rtItem.left, rtItem.top, rtItem.width - 1,
+                      rtItem.height - 1);
 #else
-    path.AddRectangle(rt.left, rt.top, rt.width, rt.height);
+    path.AddRectangle(rtItem.left, rtItem.top, rtItem.width, rtItem.height);
 #endif
-    pGraphics->FillPath(&path, FXFILL_WINDING, pMatrix);
+    pGraphics->FillPath(&path, FXFILL_WINDING, &matrix);
     pGraphics->RestoreGraphState();
   }
-  if (dwStates & CFWL_PartState_Focused && pData)
-    DrawFocus(pGraphics, (CFX_RectF*)pData, pMatrix);
+  if ((dwStates & CFWL_PartState_Focused) && pData)
+    DrawFocus(pGraphics, *pData, matrix);
 }
diff --git a/xfa/fwl/theme/cfwl_listboxtp.h b/xfa/fwl/theme/cfwl_listboxtp.h
index 5dc45af..ee954b8 100644
--- a/xfa/fwl/theme/cfwl_listboxtp.h
+++ b/xfa/fwl/theme/cfwl_listboxtp.h
@@ -9,20 +9,20 @@
 
 #include "xfa/fwl/theme/cfwl_widgettp.h"
 
-class CFWL_ListBoxTP : public CFWL_WidgetTP {
+class CFWL_ListBoxTP final : public CFWL_WidgetTP {
  public:
   CFWL_ListBoxTP();
   ~CFWL_ListBoxTP() override;
 
   // CFWL_WidgetTP
-  void DrawBackground(CFWL_ThemeBackground* pParams) override;
+  void DrawBackground(const CFWL_ThemeBackground& pParams) override;
 
- protected:
+ private:
   void DrawListBoxItem(CXFA_Graphics* pGraphics,
                        uint32_t dwStates,
-                       const CFX_RectF* prtItem,
-                       void* pData = nullptr,
-                       CFX_Matrix* pMatrix = nullptr);
+                       const CFX_RectF& rtItem,
+                       const CFX_RectF* pData,
+                       const CFX_Matrix& matrix);
 };
 
 #endif  // XFA_FWL_THEME_CFWL_LISTBOXTP_H_
diff --git a/xfa/fwl/theme/cfwl_monthcalendartp.cpp b/xfa/fwl/theme/cfwl_monthcalendartp.cpp
index 6bb3f18..47ba930 100644
--- a/xfa/fwl/theme/cfwl_monthcalendartp.cpp
+++ b/xfa/fwl/theme/cfwl_monthcalendartp.cpp
@@ -6,6 +6,7 @@
 
 #include "xfa/fwl/theme/cfwl_monthcalendartp.h"
 
+#include "core/fxge/render_defines.h"
 #include "xfa/fde/cfde_textout.h"
 #include "xfa/fwl/cfwl_monthcalendar.h"
 #include "xfa/fwl/cfwl_themebackground.h"
@@ -15,69 +16,66 @@
 #include "xfa/fxgraphics/cxfa_gecolor.h"
 #include "xfa/fxgraphics/cxfa_gepath.h"
 
-CFWL_MonthCalendarTP::CFWL_MonthCalendarTP() : m_pThemeData(new MCThemeData) {
-  SetThemeData();
-}
+namespace {
 
-CFWL_MonthCalendarTP::~CFWL_MonthCalendarTP() {}
+constexpr FX_ARGB kCaptionColor = ArgbEncode(0xff, 0, 153, 255);
+constexpr FX_ARGB kSeparatorColor = ArgbEncode(0xff, 141, 161, 239);
+constexpr FX_ARGB kDatesHoverBackgroundColor = ArgbEncode(0xff, 193, 211, 251);
+constexpr FX_ARGB kDatesSelectedBackgroundColor =
+    ArgbEncode(0xff, 173, 188, 239);
+constexpr FX_ARGB kDatesCircleColor = ArgbEncode(0xff, 103, 144, 209);
+constexpr FX_ARGB kBackgroundColor = ArgbEncode(0xff, 255, 255, 255);
 
-void CFWL_MonthCalendarTP::Initialize() {
-  CFWL_WidgetTP::Initialize();
-  InitTTO();
-}
+}  // namespace
 
-void CFWL_MonthCalendarTP::Finalize() {
-  FinalizeTTO();
-  CFWL_WidgetTP::Finalize();
-}
+CFWL_MonthCalendarTP::CFWL_MonthCalendarTP() = default;
 
-void CFWL_MonthCalendarTP::DrawBackground(CFWL_ThemeBackground* pParams) {
-  if (!pParams)
-    return;
+CFWL_MonthCalendarTP::~CFWL_MonthCalendarTP() = default;
 
-  switch (pParams->m_iPart) {
+void CFWL_MonthCalendarTP::DrawBackground(const CFWL_ThemeBackground& pParams) {
+  switch (pParams.m_iPart) {
     case CFWL_Part::Border: {
-      DrawBorder(pParams->m_pGraphics, &pParams->m_rtPart, &pParams->m_matrix);
+      DrawBorder(pParams.m_pGraphics.Get(), pParams.m_rtPart, pParams.m_matrix);
       break;
     }
     case CFWL_Part::Background: {
-      DrawTotalBK(pParams, &pParams->m_matrix);
+      DrawTotalBK(pParams, pParams.m_matrix);
       break;
     }
     case CFWL_Part::Header: {
-      DrawHeadBk(pParams, &pParams->m_matrix);
+      DrawHeadBk(pParams, pParams.m_matrix);
       break;
     }
     case CFWL_Part::LBtn: {
-      FWLTHEME_STATE eState = GetState(pParams->m_dwStates);
-      DrawArrowBtn(pParams->m_pGraphics, &pParams->m_rtPart,
-                   FWLTHEME_DIRECTION_Left, eState, &pParams->m_matrix);
+      FWLTHEME_STATE eState = GetState(pParams.m_dwStates);
+      DrawArrowBtn(pParams.m_pGraphics.Get(), pParams.m_rtPart,
+                   FWLTHEME_DIRECTION_Left, eState, pParams.m_matrix);
       break;
     }
     case CFWL_Part::RBtn: {
-      FWLTHEME_STATE eState = GetState(pParams->m_dwStates);
-      DrawArrowBtn(pParams->m_pGraphics, &pParams->m_rtPart,
-                   FWLTHEME_DIRECTION_Right, eState, &pParams->m_matrix);
+      FWLTHEME_STATE eState = GetState(pParams.m_dwStates);
+      DrawArrowBtn(pParams.m_pGraphics.Get(), pParams.m_rtPart,
+                   FWLTHEME_DIRECTION_Right, eState, pParams.m_matrix);
       break;
     }
     case CFWL_Part::HSeparator: {
-      DrawHSeperator(pParams, &pParams->m_matrix);
+      DrawHSeparator(pParams, pParams.m_matrix);
       break;
     }
     case CFWL_Part::DatesIn: {
-      DrawDatesInBK(pParams, &pParams->m_matrix);
+      DrawDatesInBK(pParams, pParams.m_matrix);
       break;
     }
     case CFWL_Part::TodayCircle: {
-      DrawTodayCircle(pParams, &pParams->m_matrix);
+      DrawTodayCircle(pParams, pParams.m_matrix);
       break;
     }
     case CFWL_Part::DateInCircle: {
-      DrawDatesInCircle(pParams, &pParams->m_matrix);
+      DrawDatesInCircle(pParams, pParams.m_matrix);
       break;
     }
     case CFWL_Part::WeekNumSep: {
-      DrawWeekNumSep(pParams, &pParams->m_matrix);
+      DrawWeekNumSep(pParams, pParams.m_matrix);
       break;
     }
     default:
@@ -85,62 +83,60 @@
   }
 }
 
-void CFWL_MonthCalendarTP::DrawText(CFWL_ThemeText* pParams) {
-  if (!m_pTextOut)
-    return;
-
-  if ((pParams->m_iPart == CFWL_Part::DatesIn) &&
-      !(pParams->m_dwStates & FWL_ITEMSTATE_MCD_Flag) &&
-      (pParams->m_dwStates &
+void CFWL_MonthCalendarTP::DrawText(const CFWL_ThemeText& pParams) {
+  EnsureTTOInitialized();
+  if ((pParams.m_iPart == CFWL_Part::DatesIn) &&
+      !(pParams.m_dwStates & FWL_ITEMSTATE_MCD_Flag) &&
+      (pParams.m_dwStates &
        (CFWL_PartState_Hovered | CFWL_PartState_Selected))) {
     m_pTextOut->SetTextColor(0xFFFFFFFF);
-  } else if (pParams->m_iPart == CFWL_Part::Caption) {
-    m_pTextOut->SetTextColor(m_pThemeData->clrCaption);
+  } else if (pParams.m_iPart == CFWL_Part::Caption) {
+    m_pTextOut->SetTextColor(kCaptionColor);
   } else {
     m_pTextOut->SetTextColor(0xFF000000);
   }
   CFWL_WidgetTP::DrawText(pParams);
 }
 
-void CFWL_MonthCalendarTP::DrawTotalBK(CFWL_ThemeBackground* pParams,
-                                       CFX_Matrix* pMatrix) {
+void CFWL_MonthCalendarTP::DrawTotalBK(const CFWL_ThemeBackground& pParams,
+                                       const CFX_Matrix& matrix) {
   CXFA_GEPath path;
-  CFX_RectF rtTotal(pParams->m_rtPart);
+  CFX_RectF rtTotal(pParams.m_rtPart);
   path.AddRectangle(rtTotal.left, rtTotal.top, rtTotal.width, rtTotal.height);
-  pParams->m_pGraphics->SaveGraphState();
-  pParams->m_pGraphics->SetFillColor(CXFA_GEColor(m_pThemeData->clrBK));
-  pParams->m_pGraphics->FillPath(&path, FXFILL_WINDING, pMatrix);
-  pParams->m_pGraphics->RestoreGraphState();
+  pParams.m_pGraphics->SaveGraphState();
+  pParams.m_pGraphics->SetFillColor(CXFA_GEColor(kBackgroundColor));
+  pParams.m_pGraphics->FillPath(&path, FXFILL_WINDING, &matrix);
+  pParams.m_pGraphics->RestoreGraphState();
 }
 
-void CFWL_MonthCalendarTP::DrawHeadBk(CFWL_ThemeBackground* pParams,
-                                      CFX_Matrix* pMatrix) {
+void CFWL_MonthCalendarTP::DrawHeadBk(const CFWL_ThemeBackground& pParams,
+                                      const CFX_Matrix& matrix) {
   CXFA_GEPath path;
-  CFX_RectF rtHead = pParams->m_rtPart;
+  CFX_RectF rtHead = pParams.m_rtPart;
   path.AddRectangle(rtHead.left, rtHead.top, rtHead.width, rtHead.height);
-  pParams->m_pGraphics->SaveGraphState();
-  pParams->m_pGraphics->SetFillColor(CXFA_GEColor(m_pThemeData->clrBK));
-  pParams->m_pGraphics->FillPath(&path, FXFILL_WINDING, pMatrix);
-  pParams->m_pGraphics->RestoreGraphState();
+  pParams.m_pGraphics->SaveGraphState();
+  pParams.m_pGraphics->SetFillColor(CXFA_GEColor(kBackgroundColor));
+  pParams.m_pGraphics->FillPath(&path, FXFILL_WINDING, &matrix);
+  pParams.m_pGraphics->RestoreGraphState();
 }
 
-void CFWL_MonthCalendarTP::DrawLButton(CFWL_ThemeBackground* pParams,
-                                       CFX_Matrix* pMatrix) {
+void CFWL_MonthCalendarTP::DrawLButton(const CFWL_ThemeBackground& pParams,
+                                       const CFX_Matrix& matrix) {
   CXFA_GEPath path;
-  CFX_RectF rtLBtn = pParams->m_rtPart;
+  CFX_RectF rtLBtn = pParams.m_rtPart;
   path.AddRectangle(rtLBtn.left, rtLBtn.top, rtLBtn.width, rtLBtn.height);
-  pParams->m_pGraphics->SaveGraphState();
-  pParams->m_pGraphics->SetStrokeColor(
+  pParams.m_pGraphics->SaveGraphState();
+  pParams.m_pGraphics->SetStrokeColor(
       CXFA_GEColor(ArgbEncode(0xff, 205, 219, 243)));
-  pParams->m_pGraphics->StrokePath(&path, pMatrix);
-  if (pParams->m_dwStates & CFWL_PartState_Pressed) {
-    pParams->m_pGraphics->SetFillColor(
+  pParams.m_pGraphics->StrokePath(&path, &matrix);
+  if (pParams.m_dwStates & CFWL_PartState_Pressed) {
+    pParams.m_pGraphics->SetFillColor(
         CXFA_GEColor(ArgbEncode(0xff, 174, 198, 242)));
-    pParams->m_pGraphics->FillPath(&path, FXFILL_WINDING, pMatrix);
+    pParams.m_pGraphics->FillPath(&path, FXFILL_WINDING, &matrix);
   } else {
-    pParams->m_pGraphics->SetFillColor(
+    pParams.m_pGraphics->SetFillColor(
         CXFA_GEColor(ArgbEncode(0xff, 227, 235, 249)));
-    pParams->m_pGraphics->FillPath(&path, FXFILL_WINDING, pMatrix);
+    pParams.m_pGraphics->FillPath(&path, FXFILL_WINDING, &matrix);
   }
 
   path.Clear();
@@ -151,29 +147,29 @@
   path.LineTo(CFX_PointF(rtLBtn.left + rtLBtn.Width() / 3 * 2,
                          rtLBtn.bottom() - rtLBtn.height / 4));
 
-  pParams->m_pGraphics->SetStrokeColor(
+  pParams.m_pGraphics->SetStrokeColor(
       CXFA_GEColor(ArgbEncode(0xff, 50, 104, 205)));
-  pParams->m_pGraphics->StrokePath(&path, pMatrix);
-  pParams->m_pGraphics->RestoreGraphState();
+  pParams.m_pGraphics->StrokePath(&path, &matrix);
+  pParams.m_pGraphics->RestoreGraphState();
 }
 
-void CFWL_MonthCalendarTP::DrawRButton(CFWL_ThemeBackground* pParams,
-                                       CFX_Matrix* pMatrix) {
+void CFWL_MonthCalendarTP::DrawRButton(const CFWL_ThemeBackground& pParams,
+                                       const CFX_Matrix& matrix) {
   CXFA_GEPath path;
-  CFX_RectF rtRBtn = pParams->m_rtPart;
+  CFX_RectF rtRBtn = pParams.m_rtPart;
   path.AddRectangle(rtRBtn.left, rtRBtn.top, rtRBtn.width, rtRBtn.height);
-  pParams->m_pGraphics->SaveGraphState();
-  pParams->m_pGraphics->SetStrokeColor(
+  pParams.m_pGraphics->SaveGraphState();
+  pParams.m_pGraphics->SetStrokeColor(
       CXFA_GEColor(ArgbEncode(0xff, 205, 219, 243)));
-  pParams->m_pGraphics->StrokePath(&path, pMatrix);
-  if (pParams->m_dwStates & CFWL_PartState_Pressed) {
-    pParams->m_pGraphics->SetFillColor(
+  pParams.m_pGraphics->StrokePath(&path, &matrix);
+  if (pParams.m_dwStates & CFWL_PartState_Pressed) {
+    pParams.m_pGraphics->SetFillColor(
         CXFA_GEColor(ArgbEncode(0xff, 174, 198, 242)));
-    pParams->m_pGraphics->FillPath(&path, FXFILL_WINDING, pMatrix);
+    pParams.m_pGraphics->FillPath(&path, FXFILL_WINDING, &matrix);
   } else {
-    pParams->m_pGraphics->SetFillColor(
+    pParams.m_pGraphics->SetFillColor(
         CXFA_GEColor(ArgbEncode(0xff, 227, 235, 249)));
-    pParams->m_pGraphics->FillPath(&path, FXFILL_WINDING, pMatrix);
+    pParams.m_pGraphics->FillPath(&path, FXFILL_WINDING, &matrix);
   }
 
   path.Clear();
@@ -184,85 +180,81 @@
   path.LineTo(CFX_PointF(rtRBtn.left + rtRBtn.Width() / 3,
                          rtRBtn.bottom() - rtRBtn.height / 4));
 
-  pParams->m_pGraphics->SetStrokeColor(
+  pParams.m_pGraphics->SetStrokeColor(
       CXFA_GEColor(ArgbEncode(0xff, 50, 104, 205)));
-  pParams->m_pGraphics->StrokePath(&path, pMatrix);
-  pParams->m_pGraphics->RestoreGraphState();
+  pParams.m_pGraphics->StrokePath(&path, &matrix);
+  pParams.m_pGraphics->RestoreGraphState();
 }
 
-void CFWL_MonthCalendarTP::DrawHSeperator(CFWL_ThemeBackground* pParams,
-                                          CFX_Matrix* pMatrix) {
+void CFWL_MonthCalendarTP::DrawHSeparator(const CFWL_ThemeBackground& pParams,
+                                          const CFX_Matrix& matrix) {
   CXFA_GEPath path;
-  CFX_RectF rtHSep = pParams->m_rtPart;
+  CFX_RectF rtHSep = pParams.m_rtPart;
   path.MoveTo(CFX_PointF(rtHSep.left, rtHSep.top + rtHSep.height / 2));
   path.LineTo(CFX_PointF(rtHSep.right(), rtHSep.top + rtHSep.height / 2));
-  pParams->m_pGraphics->SaveGraphState();
-  pParams->m_pGraphics->SetStrokeColor(
-      CXFA_GEColor(m_pThemeData->clrSeperator));
-  pParams->m_pGraphics->StrokePath(&path, pMatrix);
-  pParams->m_pGraphics->RestoreGraphState();
+  pParams.m_pGraphics->SaveGraphState();
+  pParams.m_pGraphics->SetStrokeColor(CXFA_GEColor(kSeparatorColor));
+  pParams.m_pGraphics->StrokePath(&path, &matrix);
+  pParams.m_pGraphics->RestoreGraphState();
 }
 
-void CFWL_MonthCalendarTP::DrawWeekNumSep(CFWL_ThemeBackground* pParams,
-                                          CFX_Matrix* pMatrix) {
+void CFWL_MonthCalendarTP::DrawWeekNumSep(const CFWL_ThemeBackground& pParams,
+                                          const CFX_Matrix& matrix) {
   CXFA_GEPath path;
-  CFX_RectF rtWeekSep = pParams->m_rtPart;
+  CFX_RectF rtWeekSep = pParams.m_rtPart;
   path.MoveTo(rtWeekSep.TopLeft());
   path.LineTo(rtWeekSep.BottomLeft());
-  pParams->m_pGraphics->SaveGraphState();
-  pParams->m_pGraphics->SetStrokeColor(
-      CXFA_GEColor(m_pThemeData->clrSeperator));
-  pParams->m_pGraphics->StrokePath(&path, pMatrix);
-  pParams->m_pGraphics->RestoreGraphState();
+  pParams.m_pGraphics->SaveGraphState();
+  pParams.m_pGraphics->SetStrokeColor(CXFA_GEColor(kSeparatorColor));
+  pParams.m_pGraphics->StrokePath(&path, &matrix);
+  pParams.m_pGraphics->RestoreGraphState();
 }
 
-void CFWL_MonthCalendarTP::DrawDatesInBK(CFWL_ThemeBackground* pParams,
-                                         CFX_Matrix* pMatrix) {
-  pParams->m_pGraphics->SaveGraphState();
-  if (pParams->m_dwStates & CFWL_PartState_Selected) {
+void CFWL_MonthCalendarTP::DrawDatesInBK(const CFWL_ThemeBackground& pParams,
+                                         const CFX_Matrix& matrix) {
+  pParams.m_pGraphics->SaveGraphState();
+  if (pParams.m_dwStates & CFWL_PartState_Selected) {
     CXFA_GEPath path;
-    CFX_RectF rtSelDay = pParams->m_rtPart;
+    CFX_RectF rtSelDay = pParams.m_rtPart;
     path.AddRectangle(rtSelDay.left, rtSelDay.top, rtSelDay.width,
                       rtSelDay.height);
-    pParams->m_pGraphics->SetFillColor(
-        CXFA_GEColor(m_pThemeData->clrDatesSelectedBK));
-    pParams->m_pGraphics->FillPath(&path, FXFILL_WINDING, pMatrix);
-  } else if (pParams->m_dwStates & CFWL_PartState_Hovered) {
+    pParams.m_pGraphics->SetFillColor(
+        CXFA_GEColor(kDatesSelectedBackgroundColor));
+    pParams.m_pGraphics->FillPath(&path, FXFILL_WINDING, &matrix);
+  } else if (pParams.m_dwStates & CFWL_PartState_Hovered) {
     CXFA_GEPath path;
-    CFX_RectF rtSelDay = pParams->m_rtPart;
+    CFX_RectF rtSelDay = pParams.m_rtPart;
     path.AddRectangle(rtSelDay.left, rtSelDay.top, rtSelDay.width,
                       rtSelDay.height);
-    pParams->m_pGraphics->SetFillColor(
-        CXFA_GEColor(m_pThemeData->clrDatesHoverBK));
-    pParams->m_pGraphics->FillPath(&path, FXFILL_WINDING, pMatrix);
+    pParams.m_pGraphics->SetFillColor(CXFA_GEColor(kDatesHoverBackgroundColor));
+    pParams.m_pGraphics->FillPath(&path, FXFILL_WINDING, &matrix);
   }
-  pParams->m_pGraphics->RestoreGraphState();
+  pParams.m_pGraphics->RestoreGraphState();
 }
 
-void CFWL_MonthCalendarTP::DrawDatesInCircle(CFWL_ThemeBackground* pParams,
-                                             CFX_Matrix* pMatrix) {
+void CFWL_MonthCalendarTP::DrawDatesInCircle(
+    const CFWL_ThemeBackground& pParams,
+    const CFX_Matrix& matrix) {
   CXFA_GEPath path;
-  CFX_RectF rtSelDay = pParams->m_rtPart;
+  CFX_RectF rtSelDay = pParams.m_rtPart;
   path.AddRectangle(rtSelDay.left, rtSelDay.top, rtSelDay.width,
                     rtSelDay.height);
-  pParams->m_pGraphics->SaveGraphState();
-  pParams->m_pGraphics->SetStrokeColor(
-      CXFA_GEColor(m_pThemeData->clrDatesCircle));
-  pParams->m_pGraphics->StrokePath(&path, pMatrix);
-  pParams->m_pGraphics->RestoreGraphState();
+  pParams.m_pGraphics->SaveGraphState();
+  pParams.m_pGraphics->SetStrokeColor(CXFA_GEColor(kDatesCircleColor));
+  pParams.m_pGraphics->StrokePath(&path, &matrix);
+  pParams.m_pGraphics->RestoreGraphState();
 }
 
-void CFWL_MonthCalendarTP::DrawTodayCircle(CFWL_ThemeBackground* pParams,
-                                           CFX_Matrix* pMatrix) {
+void CFWL_MonthCalendarTP::DrawTodayCircle(const CFWL_ThemeBackground& pParams,
+                                           const CFX_Matrix& matrix) {
   CXFA_GEPath path;
-  CFX_RectF rtTodayCircle = pParams->m_rtPart;
+  CFX_RectF rtTodayCircle = pParams.m_rtPart;
   path.AddRectangle(rtTodayCircle.left, rtTodayCircle.top, rtTodayCircle.width,
                     rtTodayCircle.height);
-  pParams->m_pGraphics->SaveGraphState();
-  pParams->m_pGraphics->SetStrokeColor(
-      CXFA_GEColor(m_pThemeData->clrDatesCircle));
-  pParams->m_pGraphics->StrokePath(&path, pMatrix);
-  pParams->m_pGraphics->RestoreGraphState();
+  pParams.m_pGraphics->SaveGraphState();
+  pParams.m_pGraphics->SetStrokeColor(CXFA_GEColor(kDatesCircleColor));
+  pParams.m_pGraphics->StrokePath(&path, &matrix);
+  pParams.m_pGraphics->RestoreGraphState();
 }
 
 FWLTHEME_STATE CFWL_MonthCalendarTP::GetState(uint32_t dwFWLStates) {
@@ -272,13 +264,3 @@
     return FWLTHEME_STATE_Pressed;
   return FWLTHEME_STATE_Normal;
 }
-
-void CFWL_MonthCalendarTP::SetThemeData() {
-  m_pThemeData->clrCaption = ArgbEncode(0xff, 0, 153, 255);
-  m_pThemeData->clrSeperator = ArgbEncode(0xff, 141, 161, 239);
-  m_pThemeData->clrDatesHoverBK = ArgbEncode(0xff, 193, 211, 251);
-  m_pThemeData->clrDatesSelectedBK = ArgbEncode(0xff, 173, 188, 239);
-  m_pThemeData->clrDatesCircle = ArgbEncode(0xff, 103, 144, 209);
-  m_pThemeData->clrToday = ArgbEncode(0xff, 0, 0, 0);
-  m_pThemeData->clrBK = ArgbEncode(0xff, 255, 255, 255);
-}
diff --git a/xfa/fwl/theme/cfwl_monthcalendartp.h b/xfa/fwl/theme/cfwl_monthcalendartp.h
index 6a1b9be..dd82cc1 100644
--- a/xfa/fwl/theme/cfwl_monthcalendartp.h
+++ b/xfa/fwl/theme/cfwl_monthcalendartp.h
@@ -7,48 +7,37 @@
 #ifndef XFA_FWL_THEME_CFWL_MONTHCALENDARTP_H_
 #define XFA_FWL_THEME_CFWL_MONTHCALENDARTP_H_
 
-#include <memory>
-
 #include "xfa/fwl/theme/cfwl_widgettp.h"
 
-class CFWL_MonthCalendarTP : public CFWL_WidgetTP {
+class CFWL_MonthCalendarTP final : public CFWL_WidgetTP {
  public:
   CFWL_MonthCalendarTP();
   ~CFWL_MonthCalendarTP() override;
 
   // CFWL_WidgetTP
-  void Initialize() override;
-  void Finalize() override;
-  void DrawBackground(CFWL_ThemeBackground* pParams) override;
-  void DrawText(CFWL_ThemeText* pParams) override;
-
- protected:
-  struct MCThemeData {
-    FX_ARGB clrCaption;
-    FX_ARGB clrSeperator;
-    FX_ARGB clrDatesHoverBK;
-    FX_ARGB clrDatesSelectedBK;
-    FX_ARGB clrDatesCircle;
-    FX_ARGB clrToday;
-    FX_ARGB clrBK;
-  };
-
-  void DrawTotalBK(CFWL_ThemeBackground* pParams, CFX_Matrix* pMatrix);
-  void DrawHeadBk(CFWL_ThemeBackground* pParams, CFX_Matrix* pMatrix);
-  void DrawLButton(CFWL_ThemeBackground* pParams, CFX_Matrix* pMatrix);
-  void DrawRButton(CFWL_ThemeBackground* pParams, CFX_Matrix* pMatrix);
-  void DrawDatesInBK(CFWL_ThemeBackground* pParams, CFX_Matrix* pMatrix);
-  void DrawDatesInCircle(CFWL_ThemeBackground* pParams, CFX_Matrix* pMatrix);
-  void DrawTodayCircle(CFWL_ThemeBackground* pParams, CFX_Matrix* pMatrix);
-  void DrawHSeperator(CFWL_ThemeBackground* pParams, CFX_Matrix* pMatrix);
-  void DrawWeekNumSep(CFWL_ThemeBackground* pParams, CFX_Matrix* pMatrix);
-  FWLTHEME_STATE GetState(uint32_t dwFWLStates);
-
-  std::unique_ptr<MCThemeData> m_pThemeData;
-  WideString wsResource;
+  void DrawBackground(const CFWL_ThemeBackground& pParams) override;
+  void DrawText(const CFWL_ThemeText& pParams) override;
 
  private:
-  void SetThemeData();
+  void DrawTotalBK(const CFWL_ThemeBackground& pParams,
+                   const CFX_Matrix& matrix);
+  void DrawHeadBk(const CFWL_ThemeBackground& pParams,
+                  const CFX_Matrix& matrix);
+  void DrawLButton(const CFWL_ThemeBackground& pParams,
+                   const CFX_Matrix& matrix);
+  void DrawRButton(const CFWL_ThemeBackground& pParams,
+                   const CFX_Matrix& matrix);
+  void DrawDatesInBK(const CFWL_ThemeBackground& pParams,
+                     const CFX_Matrix& matrix);
+  void DrawDatesInCircle(const CFWL_ThemeBackground& pParams,
+                         const CFX_Matrix& matrix);
+  void DrawTodayCircle(const CFWL_ThemeBackground& pParams,
+                       const CFX_Matrix& matrix);
+  void DrawHSeparator(const CFWL_ThemeBackground& pParams,
+                      const CFX_Matrix& matrix);
+  void DrawWeekNumSep(const CFWL_ThemeBackground& pParams,
+                      const CFX_Matrix& matrix);
+  FWLTHEME_STATE GetState(uint32_t dwFWLStates);
 };
 
 #endif  // XFA_FWL_THEME_CFWL_MONTHCALENDARTP_H_
diff --git a/xfa/fwl/theme/cfwl_pictureboxtp.cpp b/xfa/fwl/theme/cfwl_pictureboxtp.cpp
index 27abbe2..39611bd 100644
--- a/xfa/fwl/theme/cfwl_pictureboxtp.cpp
+++ b/xfa/fwl/theme/cfwl_pictureboxtp.cpp
@@ -14,15 +14,11 @@
 
 CFWL_PictureBoxTP::~CFWL_PictureBoxTP() {}
 
-void CFWL_PictureBoxTP::DrawBackground(CFWL_ThemeBackground* pParams) {
-  if (!pParams)
-    return;
-
-  switch (pParams->m_iPart) {
-    case CFWL_Part::Border: {
-      DrawBorder(pParams->m_pGraphics, &pParams->m_rtPart, &pParams->m_matrix);
+void CFWL_PictureBoxTP::DrawBackground(const CFWL_ThemeBackground& pParams) {
+  switch (pParams.m_iPart) {
+    case CFWL_Part::Border:
+      DrawBorder(pParams.m_pGraphics.Get(), pParams.m_rtPart, pParams.m_matrix);
       break;
-    }
     default:
       break;
   }
diff --git a/xfa/fwl/theme/cfwl_pictureboxtp.h b/xfa/fwl/theme/cfwl_pictureboxtp.h
index 4a118f2..4bb295a 100644
--- a/xfa/fwl/theme/cfwl_pictureboxtp.h
+++ b/xfa/fwl/theme/cfwl_pictureboxtp.h
@@ -9,13 +9,13 @@
 
 #include "xfa/fwl/theme/cfwl_widgettp.h"
 
-class CFWL_PictureBoxTP : public CFWL_WidgetTP {
+class CFWL_PictureBoxTP final : public CFWL_WidgetTP {
  public:
   CFWL_PictureBoxTP();
   ~CFWL_PictureBoxTP() override;
 
   // CFWL_WidgetTP
-  void DrawBackground(CFWL_ThemeBackground* pParams) override;
+  void DrawBackground(const CFWL_ThemeBackground& pParams) override;
 };
 
 #endif  // XFA_FWL_THEME_CFWL_PICTUREBOXTP_H_
diff --git a/xfa/fwl/theme/cfwl_pushbuttontp.cpp b/xfa/fwl/theme/cfwl_pushbuttontp.cpp
index 3d3b1aa..45144b4 100644
--- a/xfa/fwl/theme/cfwl_pushbuttontp.cpp
+++ b/xfa/fwl/theme/cfwl_pushbuttontp.cpp
@@ -6,6 +6,7 @@
 
 #include "xfa/fwl/theme/cfwl_pushbuttontp.h"
 
+#include "core/fxge/render_defines.h"
 #include "xfa/fwl/cfwl_pushbutton.h"
 #include "xfa/fwl/cfwl_themebackground.h"
 #include "xfa/fwl/cfwl_widget.h"
@@ -21,14 +22,14 @@
 
 CFWL_PushButtonTP::~CFWL_PushButtonTP() {}
 
-void CFWL_PushButtonTP::DrawBackground(CFWL_ThemeBackground* pParams) {
-  switch (pParams->m_iPart) {
+void CFWL_PushButtonTP::DrawBackground(const CFWL_ThemeBackground& pParams) {
+  switch (pParams.m_iPart) {
     case CFWL_Part::Border: {
-      DrawBorder(pParams->m_pGraphics, &pParams->m_rtPart, &pParams->m_matrix);
+      DrawBorder(pParams.m_pGraphics.Get(), pParams.m_rtPart, pParams.m_matrix);
       break;
     }
     case CFWL_Part::Background: {
-      CFX_RectF& rect = pParams->m_rtPart;
+      const CFX_RectF& rect = pParams.m_rtPart;
       float fRight = rect.right();
       float fBottom = rect.bottom();
 
@@ -51,7 +52,7 @@
       CXFA_GEPath fillPath;
       fillPath.AddSubpath(&strokePath);
 
-      CXFA_Graphics* pGraphics = pParams->m_pGraphics;
+      CXFA_Graphics* pGraphics = pParams.m_pGraphics.Get();
       pGraphics->SaveGraphState();
 
       CFX_RectF rtInner(rect);
@@ -60,25 +61,22 @@
       fillPath.AddRectangle(rtInner.left, rtInner.top, rtInner.width,
                             rtInner.height);
 
-      int32_t iColor = GetColorID(pParams->m_dwStates);
-      DrawAxialShading(pGraphics, rect.left + PUSHBUTTON_SIZE_Corner, rect.top,
-                       rect.left + PUSHBUTTON_SIZE_Corner, rect.bottom(),
-                       m_pThemeData->clrStart[iColor],
-                       m_pThemeData->clrEnd[iColor], &fillPath,
-                       FXFILL_ALTERNATE, &pParams->m_matrix);
+      int32_t iColor = GetColorID(pParams.m_dwStates);
+      FillSolidRect(pGraphics, m_pThemeData->clrEnd[iColor], rect,
+                    pParams.m_matrix);
 
       pGraphics->SetStrokeColor(CXFA_GEColor(m_pThemeData->clrBorder[iColor]));
-      pGraphics->StrokePath(&strokePath, &pParams->m_matrix);
+      pGraphics->StrokePath(&strokePath, &pParams.m_matrix);
 
       fillPath.Clear();
       fillPath.AddRectangle(rtInner.left, rtInner.top, rtInner.width,
                             rtInner.height);
 
       pGraphics->SetFillColor(CXFA_GEColor(m_pThemeData->clrFill[iColor]));
-      pGraphics->FillPath(&fillPath, FXFILL_WINDING, &pParams->m_matrix);
-      if (pParams->m_dwStates & CFWL_PartState_Focused) {
+      pGraphics->FillPath(&fillPath, FXFILL_WINDING, &pParams.m_matrix);
+      if (pParams.m_dwStates & CFWL_PartState_Focused) {
         rtInner.Inflate(1, 1, 0, 0);
-        DrawFocus(pGraphics, &rtInner, &pParams->m_matrix);
+        DrawFocus(pGraphics, rtInner, pParams.m_matrix);
       }
       pGraphics->RestoreGraphState();
       break;
diff --git a/xfa/fwl/theme/cfwl_pushbuttontp.h b/xfa/fwl/theme/cfwl_pushbuttontp.h
index b2372bb..c3079dd 100644
--- a/xfa/fwl/theme/cfwl_pushbuttontp.h
+++ b/xfa/fwl/theme/cfwl_pushbuttontp.h
@@ -11,15 +11,15 @@
 
 #include "xfa/fwl/theme/cfwl_widgettp.h"
 
-class CFWL_PushButtonTP : public CFWL_WidgetTP {
+class CFWL_PushButtonTP final : public CFWL_WidgetTP {
  public:
   CFWL_PushButtonTP();
   ~CFWL_PushButtonTP() override;
 
   // CFWL_WidgetTP
-  void DrawBackground(CFWL_ThemeBackground* pParams) override;
+  void DrawBackground(const CFWL_ThemeBackground& pParams) override;
 
- protected:
+ private:
   struct PBThemeData {
     FX_ARGB clrBorder[5];
     FX_ARGB clrStart[5];
@@ -34,13 +34,10 @@
   void SetBackgroudColor(uint32_t* pData);
   void SetCaptionColor(uint32_t* pData);
   void SetCornerColor(uint32_t* pData);
-
   int32_t GetColorID(uint32_t dwStates) const;
+  void SetThemeData();
 
   std::unique_ptr<PBThemeData> m_pThemeData;
-
- private:
-  void SetThemeData();
 };
 
 #endif  // XFA_FWL_THEME_CFWL_PUSHBUTTONTP_H_
diff --git a/xfa/fwl/theme/cfwl_scrollbartp.cpp b/xfa/fwl/theme/cfwl_scrollbartp.cpp
index d94eed0..55adc3e 100644
--- a/xfa/fwl/theme/cfwl_scrollbartp.cpp
+++ b/xfa/fwl/theme/cfwl_scrollbartp.cpp
@@ -6,6 +6,7 @@
 
 #include "xfa/fwl/theme/cfwl_scrollbartp.h"
 
+#include "core/fxge/render_defines.h"
 #include "xfa/fwl/cfwl_scrollbar.h"
 #include "xfa/fwl/cfwl_themebackground.h"
 #include "xfa/fwl/cfwl_widget.h"
@@ -25,45 +26,44 @@
 
 CFWL_ScrollBarTP::~CFWL_ScrollBarTP() {}
 
-void CFWL_ScrollBarTP::DrawBackground(CFWL_ThemeBackground* pParams) {
-  if (!pParams)
-    return;
-
-  CFWL_Widget* pWidget = pParams->m_pWidget;
+void CFWL_ScrollBarTP::DrawBackground(const CFWL_ThemeBackground& pParams) {
+  CFWL_Widget* pWidget = pParams.m_pWidget;
   FWLTHEME_STATE eState = FWLTHEME_STATE_Normal;
-  if (pParams->m_dwStates & CFWL_PartState_Hovered)
+  if (pParams.m_dwStates & CFWL_PartState_Hovered)
     eState = FWLTHEME_STATE_Hover;
-  else if (pParams->m_dwStates & CFWL_PartState_Pressed)
+  else if (pParams.m_dwStates & CFWL_PartState_Pressed)
     eState = FWLTHEME_STATE_Pressed;
-  else if (pParams->m_dwStates & CFWL_PartState_Disabled)
+  else if (pParams.m_dwStates & CFWL_PartState_Disabled)
     eState = FWLTHEME_STATE_Disable;
 
-  CXFA_Graphics* pGraphics = pParams->m_pGraphics;
-  CFX_RectF* pRect = &pParams->m_rtPart;
+  CXFA_Graphics* pGraphics = pParams.m_pGraphics.Get();
   bool bVert = !!pWidget->GetStylesEx();
-  switch (pParams->m_iPart) {
+  switch (pParams.m_iPart) {
     case CFWL_Part::ForeArrow: {
-      DrawMaxMinBtn(pGraphics, pRect,
+      DrawMaxMinBtn(pGraphics, pParams.m_rtPart,
                     bVert ? FWLTHEME_DIRECTION_Up : FWLTHEME_DIRECTION_Left,
-                    eState, &pParams->m_matrix);
+                    eState, pParams.m_matrix);
       break;
     }
     case CFWL_Part::BackArrow: {
-      DrawMaxMinBtn(pGraphics, pRect,
+      DrawMaxMinBtn(pGraphics, pParams.m_rtPart,
                     bVert ? FWLTHEME_DIRECTION_Down : FWLTHEME_DIRECTION_Right,
-                    eState, &pParams->m_matrix);
+                    eState, pParams.m_matrix);
       break;
     }
     case CFWL_Part::Thumb: {
-      DrawThumbBtn(pGraphics, pRect, bVert, eState, true, &pParams->m_matrix);
+      DrawThumbBtn(pGraphics, pParams.m_rtPart, bVert, eState, true,
+                   pParams.m_matrix);
       break;
     }
     case CFWL_Part::LowerTrack: {
-      DrawTrack(pGraphics, pRect, bVert, eState, true, &pParams->m_matrix);
+      DrawTrack(pGraphics, pParams.m_rtPart, bVert, eState, true,
+                pParams.m_matrix);
       break;
     }
     case CFWL_Part::UpperTrack: {
-      DrawTrack(pGraphics, pRect, bVert, eState, false, &pParams->m_matrix);
+      DrawTrack(pGraphics, pParams.m_rtPart, bVert, eState, false,
+                pParams.m_matrix);
       break;
     }
     default:
@@ -72,63 +72,49 @@
 }
 
 void CFWL_ScrollBarTP::DrawThumbBtn(CXFA_Graphics* pGraphics,
-                                    const CFX_RectF* pRect,
+                                    const CFX_RectF& input_rect,
                                     bool bVert,
                                     FWLTHEME_STATE eState,
                                     bool bPawButton,
-                                    CFX_Matrix* pMatrix) {
+                                    const CFX_Matrix& matrix) {
   if (eState < FWLTHEME_STATE_Normal || eState > FWLTHEME_STATE_Disable)
     return;
 
-  CXFA_GEPath path;
-  CFX_RectF rect(*pRect);
-  if (bVert) {
+  CFX_RectF rect = input_rect;
+  if (bVert)
     rect.Deflate(1, 0);
-    if (rect.IsEmpty(0.1f))
-      return;
-
-    path.AddRectangle(rect.left, rect.top, rect.width, rect.height);
-    DrawAxialShading(pGraphics, rect.left, rect.top, rect.right(), rect.top,
-                     m_pThemeData->clrBtnBK[eState - 1][0],
-                     m_pThemeData->clrBtnBK[eState - 1][1], &path,
-                     FXFILL_WINDING, pMatrix);
-    pGraphics->SaveGraphState();
-    pGraphics->SetStrokeColor(
-        CXFA_GEColor(m_pThemeData->clrBtnBorder[eState - 1]));
-    pGraphics->StrokePath(&path, pMatrix);
-    pGraphics->RestoreGraphState();
-  } else {
+  else
     rect.Deflate(0, 1);
-    if (rect.IsEmpty(0.1f))
-      return;
 
-    path.AddRectangle(rect.left, rect.top, rect.width, rect.height);
-    DrawAxialShading(pGraphics, rect.left, rect.top, rect.left, rect.bottom(),
-                     m_pThemeData->clrBtnBK[eState - 1][0],
-                     m_pThemeData->clrBtnBK[eState - 1][1], &path,
-                     FXFILL_WINDING, pMatrix);
-    pGraphics->SaveGraphState();
-    pGraphics->SetStrokeColor(
-        CXFA_GEColor(m_pThemeData->clrBtnBorder[eState - 1]));
-    pGraphics->StrokePath(&path, pMatrix);
-    pGraphics->RestoreGraphState();
-  }
+  if (rect.IsEmpty(0.1f))
+    return;
+
+  FillSolidRect(pGraphics, m_pThemeData->clrBtnBK[eState - 1][1], rect, matrix);
+
+  pGraphics->SaveGraphState();
+
+  CXFA_GEPath path;
+  path.AddRectangle(rect.left, rect.top, rect.width, rect.height);
+  pGraphics->SetStrokeColor(
+      CXFA_GEColor(m_pThemeData->clrBtnBorder[eState - 1]));
+  pGraphics->StrokePath(&path, &matrix);
+  pGraphics->RestoreGraphState();
 }
 
 void CFWL_ScrollBarTP::DrawPaw(CXFA_Graphics* pGraphics,
-                               const CFX_RectF* pRect,
+                               const CFX_RectF& rect,
                                bool bVert,
                                FWLTHEME_STATE eState,
-                               CFX_Matrix* pMatrix) {
+                               const CFX_Matrix& matrix) {
   CXFA_GEPath path;
   if (bVert) {
     float fPawLen = kPawLength;
-    if (pRect->width / 2 <= fPawLen) {
-      fPawLen = (pRect->width - 6) / 2;
+    if (rect.width / 2 <= fPawLen) {
+      fPawLen = (rect.width - 6) / 2;
     }
 
-    float fX = pRect->left + pRect->width / 4;
-    float fY = pRect->top + pRect->height / 2;
+    float fX = rect.left + rect.width / 4;
+    float fY = rect.top + rect.height / 2;
     path.MoveTo(CFX_PointF(fX, fY - 4));
     path.LineTo(CFX_PointF(fX + fPawLen, fY - 4));
     path.MoveTo(CFX_PointF(fX, fY - 2));
@@ -157,15 +143,15 @@
     pGraphics->SetLineWidth(1);
     pGraphics->SetStrokeColor(
         CXFA_GEColor(m_pThemeData->clrPawColorDark[eState - 1]));
-    pGraphics->StrokePath(&path, pMatrix);
+    pGraphics->StrokePath(&path, &matrix);
   } else {
     float fPawLen = kPawLength;
-    if (pRect->height / 2 <= fPawLen) {
-      fPawLen = (pRect->height - 6) / 2;
+    if (rect.height / 2 <= fPawLen) {
+      fPawLen = (rect.height - 6) / 2;
     }
 
-    float fX = pRect->left + pRect->width / 2;
-    float fY = pRect->top + pRect->height / 4;
+    float fX = rect.left + rect.width / 2;
+    float fY = rect.top + rect.height / 4;
     path.MoveTo(CFX_PointF(fX - 4, fY));
     path.LineTo(CFX_PointF(fX - 4, fY + fPawLen));
     path.MoveTo(CFX_PointF(fX - 2, fY));
@@ -178,7 +164,7 @@
     pGraphics->SetLineWidth(1);
     pGraphics->SetStrokeColor(
         CXFA_GEColor(m_pThemeData->clrPawColorLight[eState - 1]));
-    pGraphics->StrokePath(&path, pMatrix);
+    pGraphics->StrokePath(&path, &matrix);
     fY++;
 
     path.Clear();
@@ -194,55 +180,49 @@
     pGraphics->SetLineWidth(1);
     pGraphics->SetStrokeColor(
         CXFA_GEColor(m_pThemeData->clrPawColorDark[eState - 1]));
-    pGraphics->StrokePath(&path, pMatrix);
+    pGraphics->StrokePath(&path, &matrix);
   }
 }
 
 void CFWL_ScrollBarTP::DrawTrack(CXFA_Graphics* pGraphics,
-                                 const CFX_RectF* pRect,
+                                 const CFX_RectF& rect,
                                  bool bVert,
                                  FWLTHEME_STATE eState,
                                  bool bLowerTrack,
-                                 CFX_Matrix* pMatrix) {
+                                 const CFX_Matrix& matrix) {
   if (eState < FWLTHEME_STATE_Normal || eState > FWLTHEME_STATE_Disable)
     return;
 
   pGraphics->SaveGraphState();
   CXFA_GEPath path;
-  float fRight = pRect->right();
-  float fBottom = pRect->bottom();
+  float fRight = rect.right();
+  float fBottom = rect.bottom();
   if (bVert) {
-    path.AddRectangle(pRect->left, pRect->top, 1, pRect->height);
-    path.AddRectangle(fRight - 1, pRect->top, 1, pRect->height);
+    path.AddRectangle(rect.left, rect.top, 1, rect.height);
+    path.AddRectangle(fRight - 1, rect.top, 1, rect.height);
   } else {
-    path.AddRectangle(pRect->left, pRect->top, pRect->width, 1);
-    path.AddRectangle(pRect->left, fBottom - 1, pRect->width, 1);
+    path.AddRectangle(rect.left, rect.top, rect.width, 1);
+    path.AddRectangle(rect.left, fBottom - 1, rect.width, 1);
   }
   pGraphics->SetFillColor(CXFA_GEColor(ArgbEncode(255, 238, 237, 229)));
-  pGraphics->FillPath(&path, FXFILL_WINDING, pMatrix);
+  pGraphics->FillPath(&path, FXFILL_WINDING, &matrix);
   path.Clear();
-  path.AddRectangle(pRect->left + 1, pRect->top, pRect->width - 2,
-                    pRect->height);
-  float x1 = bVert ? pRect->left + 1 : pRect->left;
-  float y1 = bVert ? pRect->top : pRect->top + 1;
-  float x2 = bVert ? fRight - 1 : pRect->left;
-  float y2 = bVert ? pRect->top : fBottom - 1;
+  path.AddRectangle(rect.left + 1, rect.top, rect.width - 2, rect.height);
   pGraphics->RestoreGraphState();
-  DrawAxialShading(pGraphics, x1, y1, x2, y2, m_pThemeData->clrTrackBKStart,
-                   m_pThemeData->clrTrackBKEnd, &path, FXFILL_WINDING, pMatrix);
+  FillSolidRect(pGraphics, m_pThemeData->clrTrackBKEnd, rect, matrix);
 }
 
 void CFWL_ScrollBarTP::DrawMaxMinBtn(CXFA_Graphics* pGraphics,
-                                     const CFX_RectF* pRect,
+                                     const CFX_RectF& rect,
                                      FWLTHEME_DIRECTION eDict,
                                      FWLTHEME_STATE eState,
-                                     CFX_Matrix* pMatrix) {
-  DrawTrack(pGraphics, pRect,
+                                     const CFX_Matrix& matrix) {
+  DrawTrack(pGraphics, rect,
             eDict == FWLTHEME_DIRECTION_Up || eDict == FWLTHEME_DIRECTION_Down,
-            eState, true, pMatrix);
-  CFX_RectF rtArrowBtn(*pRect);
+            eState, true, matrix);
+  CFX_RectF rtArrowBtn = rect;
   rtArrowBtn.Deflate(1, 1, 1, 1);
-  DrawArrowBtn(pGraphics, &rtArrowBtn, eDict, eState, pMatrix);
+  DrawArrowBtn(pGraphics, rtArrowBtn, eDict, eState, matrix);
 }
 
 void CFWL_ScrollBarTP::SetThemeData() {
diff --git a/xfa/fwl/theme/cfwl_scrollbartp.h b/xfa/fwl/theme/cfwl_scrollbartp.h
index eec372c..f07d102 100644
--- a/xfa/fwl/theme/cfwl_scrollbartp.h
+++ b/xfa/fwl/theme/cfwl_scrollbartp.h
@@ -11,51 +11,49 @@
 
 #include "xfa/fwl/theme/cfwl_widgettp.h"
 
-class CFWL_ScrollBarTP : public CFWL_WidgetTP {
+class CFWL_ScrollBarTP final : public CFWL_WidgetTP {
  public:
   CFWL_ScrollBarTP();
   ~CFWL_ScrollBarTP() override;
 
   // CFWL_WidgetTP
-  void DrawBackground(CFWL_ThemeBackground* pParams) override;
+  void DrawBackground(const CFWL_ThemeBackground& pParams) override;
 
- protected:
+ private:
   struct SBThemeData {
+    FX_ARGB clrTrackBKStart;
+    FX_ARGB clrTrackBKEnd;
     FX_ARGB clrPawColorLight[4];
     FX_ARGB clrPawColorDark[4];
     FX_ARGB clrBtnBK[4][2];
     FX_ARGB clrBtnBorder[4];
-    FX_ARGB clrTrackBKStart;
-    FX_ARGB clrTrackBKEnd;
   };
 
   void DrawThumbBtn(CXFA_Graphics* pGraphics,
-                    const CFX_RectF* pRect,
+                    const CFX_RectF& rect,
                     bool bVert,
                     FWLTHEME_STATE eState,
-                    bool bPawButton = true,
-                    CFX_Matrix* pMatrix = nullptr);
+                    bool bPawButton,
+                    const CFX_Matrix& matrix);
   void DrawTrack(CXFA_Graphics* pGraphics,
-                 const CFX_RectF* pRect,
+                 const CFX_RectF& rect,
                  bool bVert,
                  FWLTHEME_STATE eState,
                  bool bLowerTrack,
-                 CFX_Matrix* pMatrix = nullptr);
+                 const CFX_Matrix& matrix);
   void DrawMaxMinBtn(CXFA_Graphics* pGraphics,
-                     const CFX_RectF* pRect,
+                     const CFX_RectF& rect,
                      FWLTHEME_DIRECTION eDict,
                      FWLTHEME_STATE eState,
-                     CFX_Matrix* pMatrix = nullptr);
+                     const CFX_Matrix& matrix);
   void DrawPaw(CXFA_Graphics* pGraphics,
-               const CFX_RectF* pRect,
+               const CFX_RectF& rect,
                bool bVert,
                FWLTHEME_STATE eState,
-               CFX_Matrix* pMatrix = nullptr);
+               const CFX_Matrix& matrix);
+  void SetThemeData();
 
   std::unique_ptr<SBThemeData> m_pThemeData;
-
- private:
-  void SetThemeData();
 };
 
 #endif  // XFA_FWL_THEME_CFWL_SCROLLBARTP_H_
diff --git a/xfa/fwl/theme/cfwl_widgettp.cpp b/xfa/fwl/theme/cfwl_widgettp.cpp
index 3113d24..27caf99 100644
--- a/xfa/fwl/theme/cfwl_widgettp.cpp
+++ b/xfa/fwl/theme/cfwl_widgettp.cpp
@@ -9,6 +9,7 @@
 #include <algorithm>
 #include <utility>
 
+#include "core/fxge/render_defines.h"
 #include "third_party/base/ptr_util.h"
 #include "xfa/fde/cfde_textout.h"
 #include "xfa/fgas/font/cfgas_fontmgr.h"
@@ -23,38 +24,34 @@
 #include "xfa/fxgraphics/cxfa_gepath.h"
 #include "xfa/fxgraphics/cxfa_geshading.h"
 
-CFWL_WidgetTP::CFWL_WidgetTP()
-    : m_dwRefCount(1), m_pFDEFont(nullptr), m_pColorData(nullptr) {}
+namespace {
 
-CFWL_WidgetTP::~CFWL_WidgetTP() {}
+CFWL_FontManager* g_FontManager = nullptr;
 
-void CFWL_WidgetTP::Initialize() {}
+}  // namespace
 
-void CFWL_WidgetTP::Finalize() {
-  if (m_pTextOut)
-    FinalizeTTO();
-}
+CFWL_WidgetTP::CFWL_WidgetTP() = default;
 
-void CFWL_WidgetTP::DrawBackground(CFWL_ThemeBackground* pParams) {}
+CFWL_WidgetTP::~CFWL_WidgetTP() = default;
 
-void CFWL_WidgetTP::DrawText(CFWL_ThemeText* pParams) {
-  if (!m_pTextOut)
-    InitTTO();
+void CFWL_WidgetTP::DrawBackground(const CFWL_ThemeBackground& pParams) {}
 
-  int32_t iLen = pParams->m_wsText.GetLength();
+void CFWL_WidgetTP::DrawText(const CFWL_ThemeText& pParams) {
+  EnsureTTOInitialized();
+  int32_t iLen = pParams.m_wsText.GetLength();
   if (iLen <= 0)
     return;
 
-  CXFA_Graphics* pGraphics = pParams->m_pGraphics;
-  m_pTextOut->SetStyles(pParams->m_dwTTOStyles);
-  m_pTextOut->SetAlignment(pParams->m_iTTOAlign);
+  CXFA_Graphics* pGraphics = pParams.m_pGraphics;
+  m_pTextOut->SetStyles(pParams.m_dwTTOStyles);
+  m_pTextOut->SetAlignment(pParams.m_iTTOAlign);
 
-  CFX_Matrix* pMatrix = &pParams->m_matrix;
-  pMatrix->Concat(*pGraphics->GetMatrix());
-  m_pTextOut->SetMatrix(*pMatrix);
+  CFX_Matrix matrix = pParams.m_matrix;
+  matrix.Concat(*pGraphics->GetMatrix());
+  m_pTextOut->SetMatrix(matrix);
   m_pTextOut->DrawLogicText(pGraphics->GetRenderDevice(),
-                            WideStringView(pParams->m_wsText.c_str(), iLen),
-                            pParams->m_rtPart);
+                            WideStringView(pParams.m_wsText.c_str(), iLen),
+                            pParams.m_rtPart);
 }
 
 const RetainPtr<CFGAS_GEFont>& CFWL_WidgetTP::GetFont() const {
@@ -84,8 +81,7 @@
   m_pColorData->clrSign[3] = ArgbEncode(255, 128, 128, 128);
 }
 
-
-void CFWL_WidgetTP::InitTTO() {
+void CFWL_WidgetTP::EnsureTTOInitialized() {
   if (m_pTextOut)
     return;
 
@@ -96,97 +92,68 @@
   m_pTextOut->SetTextColor(FWLTHEME_CAPACITY_TextColor);
 }
 
-void CFWL_WidgetTP::FinalizeTTO() {
-  m_pTextOut.reset();
-}
-
 void CFWL_WidgetTP::DrawBorder(CXFA_Graphics* pGraphics,
-                               const CFX_RectF* pRect,
-                               CFX_Matrix* pMatrix) {
-  if (!pGraphics || !pRect)
+                               const CFX_RectF& rect,
+                               const CFX_Matrix& matrix) {
+  if (!pGraphics)
     return;
 
   CXFA_GEPath path;
-  path.AddRectangle(pRect->left, pRect->top, pRect->width, pRect->height);
-  path.AddRectangle(pRect->left + 1, pRect->top + 1, pRect->width - 2,
-                    pRect->height - 2);
+  path.AddRectangle(rect.left, rect.top, rect.width, rect.height);
+  path.AddRectangle(rect.left + 1, rect.top + 1, rect.width - 2,
+                    rect.height - 2);
   pGraphics->SaveGraphState();
   pGraphics->SetFillColor(CXFA_GEColor(ArgbEncode(255, 0, 0, 0)));
-  pGraphics->FillPath(&path, FXFILL_ALTERNATE, pMatrix);
+  pGraphics->FillPath(&path, FXFILL_ALTERNATE, &matrix);
   pGraphics->RestoreGraphState();
 }
 
 void CFWL_WidgetTP::FillBackground(CXFA_Graphics* pGraphics,
-                                   const CFX_RectF* pRect,
-                                   CFX_Matrix* pMatrix) {
-  FillSoildRect(pGraphics, FWLTHEME_COLOR_Background, pRect, pMatrix);
+                                   const CFX_RectF& rect,
+                                   const CFX_Matrix& matrix) {
+  FillSolidRect(pGraphics, FWLTHEME_COLOR_Background, rect, matrix);
 }
 
-void CFWL_WidgetTP::FillSoildRect(CXFA_Graphics* pGraphics,
+void CFWL_WidgetTP::FillSolidRect(CXFA_Graphics* pGraphics,
                                   FX_ARGB fillColor,
-                                  const CFX_RectF* pRect,
-                                  CFX_Matrix* pMatrix) {
-  if (!pGraphics || !pRect)
+                                  const CFX_RectF& rect,
+                                  const CFX_Matrix& matrix) {
+  if (!pGraphics)
     return;
 
   CXFA_GEPath path;
-  path.AddRectangle(pRect->left, pRect->top, pRect->width, pRect->height);
+  path.AddRectangle(rect.left, rect.top, rect.width, rect.height);
   pGraphics->SaveGraphState();
   pGraphics->SetFillColor(CXFA_GEColor(fillColor));
-  pGraphics->FillPath(&path, FXFILL_WINDING, pMatrix);
-  pGraphics->RestoreGraphState();
-}
-
-void CFWL_WidgetTP::DrawAxialShading(CXFA_Graphics* pGraphics,
-                                     float fx1,
-                                     float fy1,
-                                     float fx2,
-                                     float fy2,
-                                     FX_ARGB beginColor,
-                                     FX_ARGB endColor,
-                                     CXFA_GEPath* path,
-                                     int32_t fillMode,
-                                     CFX_Matrix* pMatrix) {
-  if (!pGraphics || !path)
-    return;
-
-  CFX_PointF begPoint(fx1, fy1);
-  CFX_PointF endPoint(fx2, fy2);
-  CXFA_GEShading shading(begPoint, endPoint, false, false, beginColor,
-                         endColor);
-  pGraphics->SaveGraphState();
-  pGraphics->SetFillColor(CXFA_GEColor(&shading));
-  pGraphics->FillPath(path, fillMode, pMatrix);
+  pGraphics->FillPath(&path, FXFILL_WINDING, &matrix);
   pGraphics->RestoreGraphState();
 }
 
 void CFWL_WidgetTP::DrawFocus(CXFA_Graphics* pGraphics,
-                              const CFX_RectF* pRect,
-                              CFX_Matrix* pMatrix) {
-  if (!pGraphics || !pRect)
+                              const CFX_RectF& rect,
+                              const CFX_Matrix& matrix) {
+  if (!pGraphics)
     return;
 
-  float DashPattern[2] = {1, 1};
   CXFA_GEPath path;
-  path.AddRectangle(pRect->left, pRect->top, pRect->width, pRect->height);
+  path.AddRectangle(rect.left, rect.top, rect.width, rect.height);
   pGraphics->SaveGraphState();
   pGraphics->SetStrokeColor(CXFA_GEColor(0xFF000000));
-  pGraphics->SetLineDash(0.0f, DashPattern, 2);
-  pGraphics->StrokePath(&path, pMatrix);
+  static constexpr float kDashPattern[2] = {1, 1};
+  pGraphics->SetLineDash(0.0f, kDashPattern, FX_ArraySize(kDashPattern));
+  pGraphics->StrokePath(&path, &matrix);
   pGraphics->RestoreGraphState();
 }
 
 void CFWL_WidgetTP::DrawArrow(CXFA_Graphics* pGraphics,
-                              const CFX_RectF* pRect,
+                              const CFX_RectF& rect,
                               FWLTHEME_DIRECTION eDict,
                               FX_ARGB argSign,
-                              CFX_Matrix* pMatrix) {
+                              const CFX_Matrix& matrix) {
   bool bVert =
       (eDict == FWLTHEME_DIRECTION_Up || eDict == FWLTHEME_DIRECTION_Down);
-  float fLeft =
-      (float)(((pRect->width - (bVert ? 9 : 6)) / 2 + pRect->left) + 0.5);
-  float fTop =
-      (float)(((pRect->height - (bVert ? 6 : 9)) / 2 + pRect->top) + 0.5);
+  float fLeft = ((rect.width - (bVert ? 9 : 6)) / 2 + rect.left) + 0.5f;
+  float fTop = ((rect.height - (bVert ? 6 : 9)) / 2 + rect.top) + 0.5f;
   CXFA_GEPath path;
   switch (eDict) {
     case FWLTHEME_DIRECTION_Down: {
@@ -227,52 +194,44 @@
     }
   }
   pGraphics->SetFillColor(CXFA_GEColor(argSign));
-  pGraphics->FillPath(&path, FXFILL_WINDING, pMatrix);
+  pGraphics->FillPath(&path, FXFILL_WINDING, &matrix);
 }
 
 void CFWL_WidgetTP::DrawBtn(CXFA_Graphics* pGraphics,
-                            const CFX_RectF* pRect,
+                            const CFX_RectF& rect,
                             FWLTHEME_STATE eState,
-                            CFX_Matrix* pMatrix) {
+                            const CFX_Matrix& matrix) {
   InitializeArrowColorData();
+  FillSolidRect(pGraphics, m_pColorData->clrEnd[eState - 1], rect, matrix);
 
   CXFA_GEPath path;
-  float fRight = pRect->right();
-  float fBottom = pRect->bottom();
-  path.AddRectangle(pRect->left, pRect->top, pRect->width, pRect->height);
-  DrawAxialShading(pGraphics, pRect->left, pRect->top, fRight, fBottom,
-                   m_pColorData->clrStart[eState - 1],
-                   m_pColorData->clrEnd[eState - 1], &path, FXFILL_WINDING,
-                   pMatrix);
-
+  path.AddRectangle(rect.left, rect.top, rect.width, rect.height);
   pGraphics->SetStrokeColor(CXFA_GEColor(m_pColorData->clrBorder[eState - 1]));
-  pGraphics->StrokePath(&path, pMatrix);
+  pGraphics->StrokePath(&path, &matrix);
 }
 
 void CFWL_WidgetTP::DrawArrowBtn(CXFA_Graphics* pGraphics,
-                                 const CFX_RectF* pRect,
+                                 const CFX_RectF& rect,
                                  FWLTHEME_DIRECTION eDict,
                                  FWLTHEME_STATE eState,
-                                 CFX_Matrix* pMatrix) {
-  DrawBtn(pGraphics, pRect, eState, pMatrix);
-
+                                 const CFX_Matrix& matrix) {
+  DrawBtn(pGraphics, rect, eState, matrix);
   InitializeArrowColorData();
-  DrawArrow(pGraphics, pRect, eDict, m_pColorData->clrSign[eState - 1],
-            pMatrix);
+  DrawArrow(pGraphics, rect, eDict, m_pColorData->clrSign[eState - 1], matrix);
 }
 
 CFWL_FontData::CFWL_FontData() : m_dwStyles(0), m_dwCodePage(0) {}
 
 CFWL_FontData::~CFWL_FontData() {}
 
-bool CFWL_FontData::Equal(const WideStringView& wsFontFamily,
+bool CFWL_FontData::Equal(WideStringView wsFontFamily,
                           uint32_t dwFontStyles,
                           uint16_t wCodePage) {
   return m_wsFamily == wsFontFamily && m_dwStyles == dwFontStyles &&
          m_dwCodePage == wCodePage;
 }
 
-bool CFWL_FontData::LoadFont(const WideStringView& wsFontFamily,
+bool CFWL_FontData::LoadFont(WideStringView wsFontFamily,
                              uint32_t dwFontStyles,
                              uint16_t dwCodePage) {
   m_wsFamily = wsFontFamily;
@@ -294,26 +253,24 @@
   return m_pFont;
 }
 
-CFWL_FontManager* CFWL_FontManager::s_FontManager = nullptr;
 CFWL_FontManager* CFWL_FontManager::GetInstance() {
-  if (!s_FontManager)
-    s_FontManager = new CFWL_FontManager;
-  return s_FontManager;
+  if (!g_FontManager)
+    g_FontManager = new CFWL_FontManager;
+  return g_FontManager;
 }
 
 void CFWL_FontManager::DestroyInstance() {
-  delete s_FontManager;
-  s_FontManager = nullptr;
+  delete g_FontManager;
+  g_FontManager = nullptr;
 }
 
-CFWL_FontManager::CFWL_FontManager() {}
+CFWL_FontManager::CFWL_FontManager() = default;
 
-CFWL_FontManager::~CFWL_FontManager() {}
+CFWL_FontManager::~CFWL_FontManager() = default;
 
-RetainPtr<CFGAS_GEFont> CFWL_FontManager::FindFont(
-    const WideStringView& wsFontFamily,
-    uint32_t dwFontStyles,
-    uint16_t wCodePage) {
+RetainPtr<CFGAS_GEFont> CFWL_FontManager::FindFont(WideStringView wsFontFamily,
+                                                   uint32_t dwFontStyles,
+                                                   uint16_t wCodePage) {
   for (const auto& pData : m_FontsArray) {
     if (pData->Equal(wsFontFamily, dwFontStyles, wCodePage))
       return pData->GetFont();
@@ -326,6 +283,3 @@
   return m_FontsArray.back()->GetFont();
 }
 
-void FWLTHEME_Release() {
-  CFWL_FontManager::DestroyInstance();
-}
diff --git a/xfa/fwl/theme/cfwl_widgettp.h b/xfa/fwl/theme/cfwl_widgettp.h
index 7813c08..c4fa61a 100644
--- a/xfa/fwl/theme/cfwl_widgettp.h
+++ b/xfa/fwl/theme/cfwl_widgettp.h
@@ -20,23 +20,14 @@
 class CFGAS_FontMgr;
 class CFGAS_GEFont;
 class CFWL_ThemeBackground;
-class CFWL_ThemePart;
 class CFWL_ThemeText;
-class CFWL_Widget;
-
-#if _FX_PLATFORM_ != _FX_PLATFORM_WINDOWS_
-class CFX_FontSourceEnum_File;
-#endif
 
 class CFWL_WidgetTP {
  public:
   virtual ~CFWL_WidgetTP();
 
-  virtual void Initialize();
-  virtual void Finalize();
-
-  virtual void DrawBackground(CFWL_ThemeBackground* pParams);
-  virtual void DrawText(CFWL_ThemeText* pParams);
+  virtual void DrawBackground(const CFWL_ThemeBackground& pParams);
+  virtual void DrawText(const CFWL_ThemeText& pParams);
 
   const RetainPtr<CFGAS_GEFont>& GetFont() const;
 
@@ -51,64 +42,50 @@
   CFWL_WidgetTP();
 
   void InitializeArrowColorData();
-  void InitTTO();
-  void FinalizeTTO();
+  void EnsureTTOInitialized();
 
   void DrawBorder(CXFA_Graphics* pGraphics,
-                  const CFX_RectF* pRect,
-                  CFX_Matrix* pMatrix = nullptr);
+                  const CFX_RectF& rect,
+                  const CFX_Matrix& matrix);
   void FillBackground(CXFA_Graphics* pGraphics,
-                      const CFX_RectF* pRect,
-                      CFX_Matrix* pMatrix = nullptr);
-  void FillSoildRect(CXFA_Graphics* pGraphics,
+                      const CFX_RectF& rect,
+                      const CFX_Matrix& matrix);
+  void FillSolidRect(CXFA_Graphics* pGraphics,
                      FX_ARGB fillColor,
-                     const CFX_RectF* pRect,
-                     CFX_Matrix* pMatrix = nullptr);
-  void DrawAxialShading(CXFA_Graphics* pGraphics,
-                        float fx1,
-                        float fy1,
-                        float fx2,
-                        float fy2,
-                        FX_ARGB beginColor,
-                        FX_ARGB endColor,
-                        CXFA_GEPath* path,
-                        int32_t fillMode = FXFILL_WINDING,
-                        CFX_Matrix* pMatrix = nullptr);
+                     const CFX_RectF& rect,
+                     const CFX_Matrix& matrix);
   void DrawFocus(CXFA_Graphics* pGraphics,
-                 const CFX_RectF* pRect,
-                 CFX_Matrix* pMatrix = nullptr);
+                 const CFX_RectF& rect,
+                 const CFX_Matrix& matrix);
   void DrawArrow(CXFA_Graphics* pGraphics,
-                 const CFX_RectF* pRect,
+                 const CFX_RectF& rect,
                  FWLTHEME_DIRECTION eDict,
                  FX_ARGB argSign,
-                 CFX_Matrix* pMatrix = nullptr);
+                 const CFX_Matrix& matrix);
   void DrawBtn(CXFA_Graphics* pGraphics,
-               const CFX_RectF* pRect,
+               const CFX_RectF& rect,
                FWLTHEME_STATE eState,
-               CFX_Matrix* pMatrix = nullptr);
+               const CFX_Matrix& matrix);
   void DrawArrowBtn(CXFA_Graphics* pGraphics,
-                    const CFX_RectF* pRect,
+                    const CFX_RectF& rect,
                     FWLTHEME_DIRECTION eDict,
                     FWLTHEME_STATE eState,
-                    CFX_Matrix* pMatrix = nullptr);
+                    const CFX_Matrix& matrix);
 
-  uint32_t m_dwRefCount;
   std::unique_ptr<CFDE_TextOut> m_pTextOut;
   RetainPtr<CFGAS_GEFont> m_pFDEFont;
   std::unique_ptr<CColorData> m_pColorData;
 };
 
-void FWLTHEME_Release();
-
-class CFWL_FontData {
+class CFWL_FontData final {
  public:
   CFWL_FontData();
-  virtual ~CFWL_FontData();
+  ~CFWL_FontData();
 
-  bool Equal(const WideStringView& wsFontFamily,
+  bool Equal(WideStringView wsFontFamily,
              uint32_t dwFontStyles,
              uint16_t wCodePage);
-  bool LoadFont(const WideStringView& wsFontFamily,
+  bool LoadFont(WideStringView wsFontFamily,
                 uint32_t dwFontStyles,
                 uint16_t wCodePage);
   RetainPtr<CFGAS_GEFont> GetFont() const;
@@ -121,20 +98,19 @@
   RetainPtr<CFGAS_GEFont> m_pFont;
 };
 
-class CFWL_FontManager {
+class CFWL_FontManager final {
  public:
   static CFWL_FontManager* GetInstance();
   static void DestroyInstance();
 
-  RetainPtr<CFGAS_GEFont> FindFont(const WideStringView& wsFontFamily,
+  RetainPtr<CFGAS_GEFont> FindFont(WideStringView wsFontFamily,
                                    uint32_t dwFontStyles,
                                    uint16_t dwCodePage);
 
- protected:
+ private:
   CFWL_FontManager();
-  virtual ~CFWL_FontManager();
+  ~CFWL_FontManager();
 
-  static CFWL_FontManager* s_FontManager;
   std::vector<std::unique_ptr<CFWL_FontData>> m_FontsArray;
 };
 
diff --git a/xfa/fxfa/BUILD.gn b/xfa/fxfa/BUILD.gn
new file mode 100644
index 0000000..8490abe
--- /dev/null
+++ b/xfa/fxfa/BUILD.gn
@@ -0,0 +1,134 @@
+# Copyright 2018 The 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.
+
+import("../../pdfium.gni")
+import("../../testing/test.gni")
+
+assert(pdf_enable_xfa)
+
+source_set("fxfa") {
+  sources = [
+    "cxfa_eventparam.cpp",
+    "cxfa_eventparam.h",
+    "cxfa_ffapp.cpp",
+    "cxfa_ffapp.h",
+    "cxfa_ffarc.cpp",
+    "cxfa_ffarc.h",
+    "cxfa_ffbarcode.cpp",
+    "cxfa_ffbarcode.h",
+    "cxfa_ffcheckbutton.cpp",
+    "cxfa_ffcheckbutton.h",
+    "cxfa_ffcombobox.cpp",
+    "cxfa_ffcombobox.h",
+    "cxfa_ffdatetimeedit.cpp",
+    "cxfa_ffdatetimeedit.h",
+    "cxfa_ffdoc.cpp",
+    "cxfa_ffdoc.h",
+    "cxfa_ffdocview.cpp",
+    "cxfa_ffdocview.h",
+    "cxfa_ffdropdown.cpp",
+    "cxfa_ffdropdown.h",
+    "cxfa_ffexclgroup.cpp",
+    "cxfa_ffexclgroup.h",
+    "cxfa_fffield.cpp",
+    "cxfa_fffield.h",
+    "cxfa_ffimage.cpp",
+    "cxfa_ffimage.h",
+    "cxfa_ffimageedit.cpp",
+    "cxfa_ffimageedit.h",
+    "cxfa_ffline.cpp",
+    "cxfa_ffline.h",
+    "cxfa_fflistbox.cpp",
+    "cxfa_fflistbox.h",
+    "cxfa_ffnotify.cpp",
+    "cxfa_ffnotify.h",
+    "cxfa_ffnumericedit.cpp",
+    "cxfa_ffnumericedit.h",
+    "cxfa_ffpageview.cpp",
+    "cxfa_ffpageview.h",
+    "cxfa_ffpasswordedit.cpp",
+    "cxfa_ffpasswordedit.h",
+    "cxfa_ffpushbutton.cpp",
+    "cxfa_ffpushbutton.h",
+    "cxfa_ffrectangle.cpp",
+    "cxfa_ffrectangle.h",
+    "cxfa_ffsignature.cpp",
+    "cxfa_ffsignature.h",
+    "cxfa_fftext.cpp",
+    "cxfa_fftext.h",
+    "cxfa_fftextedit.cpp",
+    "cxfa_fftextedit.h",
+    "cxfa_ffwidget.cpp",
+    "cxfa_ffwidget.h",
+    "cxfa_ffwidgethandler.cpp",
+    "cxfa_ffwidgethandler.h",
+    "cxfa_fontmgr.cpp",
+    "cxfa_fontmgr.h",
+    "cxfa_fwladapterwidgetmgr.cpp",
+    "cxfa_fwladapterwidgetmgr.h",
+    "cxfa_fwltheme.cpp",
+    "cxfa_fwltheme.h",
+    "cxfa_imagerenderer.cpp",
+    "cxfa_imagerenderer.h",
+    "cxfa_loadercontext.cpp",
+    "cxfa_loadercontext.h",
+    "cxfa_pieceline.cpp",
+    "cxfa_pieceline.h",
+    "cxfa_readynodeiterator.cpp",
+    "cxfa_readynodeiterator.h",
+    "cxfa_rendercontext.cpp",
+    "cxfa_rendercontext.h",
+    "cxfa_textlayout.cpp",
+    "cxfa_textlayout.h",
+    "cxfa_textparsecontext.cpp",
+    "cxfa_textparsecontext.h",
+    "cxfa_textparser.cpp",
+    "cxfa_textparser.h",
+    "cxfa_textpiece.cpp",
+    "cxfa_textpiece.h",
+    "cxfa_textprovider.cpp",
+    "cxfa_textprovider.h",
+    "cxfa_texttabstopscontext.cpp",
+    "cxfa_texttabstopscontext.h",
+    "fxfa.h",
+    "fxfa_basic.h",
+  ]
+  deps = [
+    "../../core/fpdfapi/parser",
+    "../../core/fpdfdoc",
+    "../../core/fxcodec",
+    "../../core/fxcrt",
+    "../../core/fxcrt/css",
+    "../../core/fxge",
+    "../../fxbarcode",
+    "../../fxjs",
+    "../fde",
+    "../fgas",
+    "../fgas/layout",
+    "../fwl",
+    "../fxgraphics",
+    "layout",
+    "parser",
+  ]
+  allow_circular_includes_from = [
+    "../../fxjs",
+    "layout",
+    "parser",
+  ]
+  configs += [
+    "../../:pdfium_core_config",
+    "../:xfa_warnings",
+  ]
+  visibility = [ "../../*" ]
+}
+
+pdfium_unittest_source_set("unittests") {
+  sources = [
+    "cxfa_ffbarcode_unittest.cpp",
+    "cxfa_textparser_unittest.cpp",
+    "fxfa_basic_unittest.cpp",
+  ]
+  deps = [ ":fxfa" ]
+  pdfium_root_dir = "../../"
+}
diff --git a/xfa/fxfa/DEPS b/xfa/fxfa/DEPS
index 886ee8e..cd0aa8d 100644
--- a/xfa/fxfa/DEPS
+++ b/xfa/fxfa/DEPS
@@ -1,3 +1,6 @@
 include_rules = [
   '+fxjs',
+
+  # xfa/fwl should be standalone. https://crbug.com/pdfium/507
+  '+xfa/fwl',
 ]
diff --git a/xfa/fxfa/README.md b/xfa/fxfa/README.md
index b554ce0..8845474 100644
--- a/xfa/fxfa/README.md
+++ b/xfa/fxfa/README.md
@@ -3,15 +3,15 @@
 The main hierarchy in this directory are the form elements:
 
 * CXFA_LayoutItem
-    * CXFA_ContentLayoutItem
+    * CXFA_ContainerLayoutItem
         * CXFA_FFPageView
+    * CXFA_ContentLayoutItem
         * CXFA_FFWidget
-            * CXFA_FFDraw
-                * CXFA_FFArc
-                * CXFA_FFImage
-                * CXFA_FFLine
-                * CXFA_FFRectangle
-                * CXFA_FFText
+            * CXFA_FFArc
+            * CXFA_FFImage
+            * CXFA_FFLine
+            * CXFA_FFRectangle
+            * CXFA_FFText
             * CXFA_FFExclGroup
             * CXFA_FFField
                 * CXFA_FFCheckButton
@@ -25,9 +25,6 @@
                     * CXFA_FFDateTimeEdit
                     * CXFA_FFNumericEdit
                     * CXFA_FFPasswordEdit
-            * CXFA_FFSubform
-
-CXFA_FFDraw is the base class for static elements like text and images.
 
 CXFA_FFField is the base class for widgets. It owns a lower level CFWL widget
 instance from xfa/fwl. The correspondence is:
diff --git a/xfa/fxfa/cxfa_eventparam.cpp b/xfa/fxfa/cxfa_eventparam.cpp
index bd6742f..c3f229d 100644
--- a/xfa/fxfa/cxfa_eventparam.cpp
+++ b/xfa/fxfa/cxfa_eventparam.cpp
@@ -8,39 +8,18 @@
 
 #include "xfa/fxfa/fxfa.h"
 
-CXFA_EventParam::CXFA_EventParam()
-    : m_pTarget(nullptr),
-      m_eType(XFA_EVENT_Unknown),
-      m_bCancelAction(false),
-      m_iCommitKey(0),
-      m_bKeyDown(false),
-      m_bModifier(false),
-      m_bReenter(false),
-      m_iSelEnd(0),
-      m_iSelStart(0),
-      m_bShift(false),
-      m_bIsFormReady(false) {}
-
-CXFA_EventParam::~CXFA_EventParam() {}
+CXFA_EventParam::CXFA_EventParam() = default;
 
 CXFA_EventParam::CXFA_EventParam(const CXFA_EventParam& other) = default;
 
-void CXFA_EventParam::Reset() {
-  m_wsChange.clear();
-  m_bCancelAction = false;
-  m_iCommitKey = 0;
-  m_wsFullText.clear();
-  m_bKeyDown = false;
-  m_bModifier = false;
-  m_wsNewContentType.clear();
-  m_wsNewText.clear();
-  m_wsPrevContentType.clear();
-  m_wsPrevText.clear();
-  m_bReenter = false;
-  m_iSelEnd = 0;
-  m_iSelStart = 0;
-  m_bShift = false;
-  m_wsSoapFaultCode.clear();
-  m_wsSoapFaultString.clear();
-  m_bIsFormReady = false;
+CXFA_EventParam::~CXFA_EventParam() = default;
+
+CXFA_EventParam& CXFA_EventParam::operator=(const CXFA_EventParam& other) =
+    default;
+
+CXFA_EventParam& CXFA_EventParam::operator=(CXFA_EventParam&& other) = default;
+
+WideString CXFA_EventParam::GetNewText() const {
+  return m_wsPrevText.First(m_iSelStart) + m_wsChange +
+         m_wsPrevText.Last(m_wsPrevText.GetLength() - m_iSelEnd);
 }
diff --git a/xfa/fxfa/cxfa_eventparam.h b/xfa/fxfa/cxfa_eventparam.h
index eafd76c..a670263 100644
--- a/xfa/fxfa/cxfa_eventparam.h
+++ b/xfa/fxfa/cxfa_eventparam.h
@@ -7,11 +7,13 @@
 #ifndef XFA_FXFA_CXFA_EVENTPARAM_H_
 #define XFA_FXFA_CXFA_EVENTPARAM_H_
 
+#include "core/fxcrt/fx_string.h"
+#include "core/fxcrt/unowned_ptr.h"
 #include "xfa/fxfa/fxfa_basic.h"
 
-class CXFA_WidgetAcc;
+class CXFA_Node;
 
-enum XFA_EVENTTYPE {
+enum XFA_EVENTTYPE : uint8_t {
   XFA_EVENT_Click,
   XFA_EVENT_Change,
   XFA_EVENT_DocClose,
@@ -48,31 +50,33 @@
 class CXFA_EventParam {
  public:
   CXFA_EventParam();
-  ~CXFA_EventParam();
   CXFA_EventParam(const CXFA_EventParam& other);
+  ~CXFA_EventParam();
 
-  void Reset();
+  CXFA_EventParam& operator=(const CXFA_EventParam& other);
+  CXFA_EventParam& operator=(CXFA_EventParam&& other);
 
-  CXFA_WidgetAcc* m_pTarget;
-  XFA_EVENTTYPE m_eType;
+  WideString GetNewText() const;
+
+  XFA_EVENTTYPE m_eType = XFA_EVENT_Unknown;
+  bool m_bCancelAction = false;
+  bool m_bKeyDown = false;
+  bool m_bModifier = false;
+  bool m_bReenter = false;
+  bool m_bShift = false;
+  bool m_bIsFormReady = false;
+  int32_t m_iCommitKey = 0;
+  int32_t m_iSelEnd = 0;
+  int32_t m_iSelStart = 0;
+  UnownedPtr<CXFA_Node> m_pTarget;
   WideString m_wsResult;
-  bool m_bCancelAction;
-  int32_t m_iCommitKey;
-  bool m_bKeyDown;
-  bool m_bModifier;
-  bool m_bReenter;
-  int32_t m_iSelEnd;
-  int32_t m_iSelStart;
-  bool m_bShift;
   WideString m_wsChange;
   WideString m_wsFullText;
   WideString m_wsNewContentType;
-  WideString m_wsNewText;
   WideString m_wsPrevContentType;
   WideString m_wsPrevText;
   WideString m_wsSoapFaultCode;
   WideString m_wsSoapFaultString;
-  bool m_bIsFormReady;
 };
 
 #endif  // XFA_FXFA_CXFA_EVENTPARAM_H_
diff --git a/xfa/fxfa/cxfa_ffapp.cpp b/xfa/fxfa/cxfa_ffapp.cpp
index 4cb9deb..656b559 100644
--- a/xfa/fxfa/cxfa_ffapp.cpp
+++ b/xfa/fxfa/cxfa_ffapp.cpp
@@ -12,7 +12,6 @@
 #include <vector>
 
 #include "third_party/base/ptr_util.h"
-#include "third_party/base/stl_util.h"
 #include "xfa/fgas/font/cfgas_fontmgr.h"
 #include "xfa/fwl/cfwl_notedriver.h"
 #include "xfa/fwl/cfwl_widgetmgr.h"
@@ -22,6 +21,17 @@
 #include "xfa/fxfa/cxfa_fwladapterwidgetmgr.h"
 #include "xfa/fxfa/cxfa_fwltheme.h"
 
+namespace {
+
+bool g_skipFontLoadForTesting = false;
+
+}  // namespace
+
+// static
+void CXFA_FFApp::SkipFontLoadForTesting(bool skip) {
+  g_skipFontLoadForTesting = skip;
+}
+
 CXFA_FFApp::CXFA_FFApp(IXFA_AppProvider* pProvider) : m_pProvider(pProvider) {
   // Ensure fully initialized before making an app based on |this|.
   m_pFWLApp = pdfium::MakeUnique<CFWL_App>(this);
@@ -29,53 +39,34 @@
 
 CXFA_FFApp::~CXFA_FFApp() {}
 
-std::unique_ptr<CXFA_FFDoc> CXFA_FFApp::CreateDoc(
-    IXFA_DocEnvironment* pDocEnvironment,
-    CPDF_Document* pPDFDoc) {
-  if (!pPDFDoc)
-    return nullptr;
-
-  auto pDoc = pdfium::MakeUnique<CXFA_FFDoc>(this, pDocEnvironment);
-  if (!pDoc->OpenDoc(pPDFDoc))
-    return nullptr;
-
-  return pDoc;
-}
-
-void CXFA_FFApp::SetDefaultFontMgr(
-    std::unique_ptr<CFGAS_DefaultFontManager> pFontMgr) {
-  if (!m_pFontMgr)
-    m_pFontMgr = pdfium::MakeUnique<CXFA_FontMgr>();
-  m_pFontMgr->SetDefFontMgr(std::move(pFontMgr));
-}
-
-CXFA_FontMgr* CXFA_FFApp::GetXFAFontMgr() const {
-  return m_pFontMgr.get();
-}
-
 CFGAS_FontMgr* CXFA_FFApp::GetFDEFontMgr() {
   if (!m_pFDEFontMgr) {
     m_pFDEFontMgr = pdfium::MakeUnique<CFGAS_FontMgr>();
-    if (!m_pFDEFontMgr->EnumFonts())
-      m_pFDEFontMgr = nullptr;
+    if (!g_skipFontLoadForTesting) {
+      if (!m_pFDEFontMgr->EnumFonts())
+        m_pFDEFontMgr = nullptr;
+    }
   }
   return m_pFDEFontMgr.get();
 }
 
-CXFA_FWLTheme* CXFA_FFApp::GetFWLTheme() {
-  if (!m_pFWLTheme)
-    m_pFWLTheme = pdfium::MakeUnique<CXFA_FWLTheme>(this);
+CXFA_FWLTheme* CXFA_FFApp::GetFWLTheme(CXFA_FFDoc* doc) {
+  if (!m_pFWLTheme) {
+    auto fwl_theme = pdfium::MakeUnique<CXFA_FWLTheme>(this);
+    if (fwl_theme->LoadCalendarFont(doc))
+      m_pFWLTheme = std::move(fwl_theme);
+  }
   return m_pFWLTheme.get();
 }
 
-CXFA_FWLAdapterWidgetMgr* CXFA_FFApp::GetFWLAdapterWidgetMgr() {
+CFWL_WidgetMgr::AdapterIface* CXFA_FFApp::GetWidgetMgrAdapter() {
   if (!m_pAdapterWidgetMgr)
     m_pAdapterWidgetMgr = pdfium::MakeUnique<CXFA_FWLAdapterWidgetMgr>();
   return m_pAdapterWidgetMgr.get();
 }
 
-IFWL_AdapterTimerMgr* CXFA_FFApp::GetTimerMgr() const {
-  return m_pProvider->GetTimerMgr();
+TimerHandlerIface* CXFA_FFApp::GetTimerHandler() {
+  return m_pProvider->GetTimerHandler();
 }
 
 void CXFA_FFApp::ClearEventTargets() {
diff --git a/xfa/fxfa/cxfa_ffapp.h b/xfa/fxfa/cxfa_ffapp.h
index 8ffd657..b01ba2f 100644
--- a/xfa/fxfa/cxfa_ffapp.h
+++ b/xfa/fxfa/cxfa_ffapp.h
@@ -8,44 +8,35 @@
 #define XFA_FXFA_CXFA_FFAPP_H_
 
 #include <memory>
-#include <vector>
 
-#include "core/fpdfapi/parser/cpdf_stream.h"
-#include "core/fpdfapi/parser/cpdf_stream_acc.h"
-#include "core/fxcrt/retain_ptr.h"
 #include "core/fxcrt/unowned_ptr.h"
 #include "xfa/fwl/cfwl_app.h"
+#include "xfa/fxfa/cxfa_fontmgr.h"
 #include "xfa/fxfa/fxfa.h"
 
-class CFGAS_DefaultFontManager;
 class CFGAS_FontMgr;
 class CFWL_WidgetMgr;
-class CPDF_Document;
-class CXFA_FFDocHandler;
-class CXFA_FontMgr;
 class CXFA_FWLAdapterWidgetMgr;
 class CXFA_FWLTheme;
-class IFWL_AdapterTimerMgr;
 
-class CXFA_FFApp {
+class CXFA_FFApp : public CFWL_App::AdapterIface {
  public:
+  static void SkipFontLoadForTesting(bool skip);
+
   explicit CXFA_FFApp(IXFA_AppProvider* pProvider);
-  ~CXFA_FFApp();
+  ~CXFA_FFApp() override;
 
-  std::unique_ptr<CXFA_FFDoc> CreateDoc(IXFA_DocEnvironment* pDocEnvironment,
-                                        CPDF_Document* pPDFDoc);
-  void SetDefaultFontMgr(std::unique_ptr<CFGAS_DefaultFontManager> pFontMgr);
+  // CFWL_App::AdapterIface:
+  CFWL_WidgetMgr::AdapterIface* GetWidgetMgrAdapter() override;
+  TimerHandlerIface* GetTimerHandler() override;
 
-  CXFA_FWLAdapterWidgetMgr* GetFWLAdapterWidgetMgr();
   CFWL_WidgetMgr* GetFWLWidgetMgr() const { return m_pFWLApp->GetWidgetMgr(); }
-
   CFGAS_FontMgr* GetFDEFontMgr();
-  CXFA_FWLTheme* GetFWLTheme();
+  CXFA_FWLTheme* GetFWLTheme(CXFA_FFDoc* doc);
 
   IXFA_AppProvider* GetAppProvider() const { return m_pProvider.Get(); }
   const CFWL_App* GetFWLApp() const { return m_pFWLApp.get(); }
-  IFWL_AdapterTimerMgr* GetTimerMgr() const;
-  CXFA_FontMgr* GetXFAFontMgr() const;
+  CXFA_FontMgr* GetXFAFontMgr() { return &m_pFontMgr; }
 
   void ClearEventTargets();
 
@@ -56,14 +47,14 @@
   // font manager. The GEFont::LoadFont call takes the manager as a param and
   // stores it internally. When you destroy the GEFont it tries to unregister
   // from the font manager and if the default font manager was destroyed first
-  // get get a use-after-free. The m_pFWLTheme can try to cleanup a GEFont
+  // you get a use-after-free. The m_pFWLTheme can try to cleanup a GEFont
   // when it frees, so make sure it gets cleaned up first. That requires
   // m_pFWLApp to be cleaned up as well.
   //
   // TODO(dsinclair): The GEFont should have the FontMgr as the pointer instead
   // of the DEFFontMgr so this goes away. Bug 561.
   std::unique_ptr<CFGAS_FontMgr> m_pFDEFontMgr;
-  std::unique_ptr<CXFA_FontMgr> m_pFontMgr;
+  CXFA_FontMgr m_pFontMgr;
 
   std::unique_ptr<CXFA_FWLAdapterWidgetMgr> m_pAdapterWidgetMgr;
 
diff --git a/xfa/fxfa/cxfa_ffarc.cpp b/xfa/fxfa/cxfa_ffarc.cpp
index 64a4f70..5b26e92 100644
--- a/xfa/fxfa/cxfa_ffarc.cpp
+++ b/xfa/fxfa/cxfa_ffarc.cpp
@@ -9,14 +9,14 @@
 #include "xfa/fxfa/parser/cxfa_arc.h"
 #include "xfa/fxfa/parser/cxfa_value.h"
 
-CXFA_FFArc::CXFA_FFArc(CXFA_Node* pNode) : CXFA_FFDraw(pNode) {}
+CXFA_FFArc::CXFA_FFArc(CXFA_Node* pNode) : CXFA_FFWidget(pNode) {}
 
 CXFA_FFArc::~CXFA_FFArc() {}
 
 void CXFA_FFArc::RenderWidget(CXFA_Graphics* pGS,
                               const CFX_Matrix& matrix,
-                              uint32_t dwStatus) {
-  if (!IsMatchVisibleStatus(dwStatus))
+                              HighlightOption highlight) {
+  if (!HasVisibleStatus())
     return;
 
   CXFA_Value* value = m_pNode->GetFormValueIfExists();
@@ -25,11 +25,9 @@
 
   CFX_RectF rtArc = GetRectWithoutRotate();
   CXFA_Margin* margin = m_pNode->GetMarginIfExists();
-  if (margin)
-    XFA_RectWithoutMargin(rtArc, margin);
+  XFA_RectWithoutMargin(&rtArc, margin);
 
   CFX_Matrix mtRotate = GetRotateMatrix();
   mtRotate.Concat(matrix);
-
   DrawBorder(pGS, value->GetArcIfExists(), rtArc, mtRotate);
 }
diff --git a/xfa/fxfa/cxfa_ffarc.h b/xfa/fxfa/cxfa_ffarc.h
index f765119..022e25e 100644
--- a/xfa/fxfa/cxfa_ffarc.h
+++ b/xfa/fxfa/cxfa_ffarc.h
@@ -7,9 +7,9 @@
 #ifndef XFA_FXFA_CXFA_FFARC_H_
 #define XFA_FXFA_CXFA_FFARC_H_
 
-#include "xfa/fxfa/cxfa_ffdraw.h"
+#include "xfa/fxfa/cxfa_ffwidget.h"
 
-class CXFA_FFArc : public CXFA_FFDraw {
+class CXFA_FFArc final : public CXFA_FFWidget {
  public:
   explicit CXFA_FFArc(CXFA_Node* pnode);
   ~CXFA_FFArc() override;
@@ -17,7 +17,7 @@
   // CXFA_FFWidget
   void RenderWidget(CXFA_Graphics* pGS,
                     const CFX_Matrix& matrix,
-                    uint32_t dwStatus) override;
+                    HighlightOption highlight) override;
 };
 
 #endif  // XFA_FXFA_CXFA_FFARC_H_
diff --git a/xfa/fxfa/cxfa_ffbarcode.cpp b/xfa/fxfa/cxfa_ffbarcode.cpp
index 3ed57b9..1c541ec 100644
--- a/xfa/fxfa/cxfa_ffbarcode.cpp
+++ b/xfa/fxfa/cxfa_ffbarcode.cpp
@@ -17,81 +17,103 @@
 #include "xfa/fxfa/cxfa_ffpageview.h"
 #include "xfa/fxfa/cxfa_ffwidget.h"
 #include "xfa/fxfa/cxfa_fwladapterwidgetmgr.h"
+#include "xfa/fxfa/parser/cxfa_barcode.h"
 #include "xfa/fxfa/parser/cxfa_border.h"
 
 namespace {
 
 const BarCodeInfo g_BarCodeData[] = {
-    {0x7fb4a18, L"ean13", BarcodeType::ean13, BC_EAN13},
-    {0x8d13a3d, L"code11", BarcodeType::code11, BC_UNKNOWN},
-    {0x8d149a8, L"code49", BarcodeType::code49, BC_UNKNOWN},
-    {0x8d16347, L"code93", BarcodeType::code93, BC_UNKNOWN},
-    {0x91a92e2, L"upsMaxicode", BarcodeType::upsMaxicode, BC_UNKNOWN},
-    {0xa7d48dc, L"fim", BarcodeType::fim, BC_UNKNOWN},
-    {0xb359fe9, L"msi", BarcodeType::msi, BC_UNKNOWN},
-    {0x121f738c, L"code2Of5Matrix", BarcodeType::code2Of5Matrix, BC_UNKNOWN},
-    {0x15358616, L"ucc128", BarcodeType::ucc128, BC_UNKNOWN},
-    {0x1f4bfa05, L"rfid", BarcodeType::rfid, BC_UNKNOWN},
-    {0x1fda71bc, L"rss14Stacked", BarcodeType::rss14Stacked, BC_UNKNOWN},
-    {0x22065087, L"ean8add2", BarcodeType::ean8add2, BC_UNKNOWN},
-    {0x2206508a, L"ean8add5", BarcodeType::ean8add5, BC_UNKNOWN},
-    {0x2278366c, L"codabar", BarcodeType::codabar, BC_CODABAR},
-    {0x2a039a8d, L"telepen", BarcodeType::telepen, BC_UNKNOWN},
-    {0x323ed337, L"upcApwcd", BarcodeType::upcApwcd, BC_UNKNOWN},
-    {0x347a1846, L"postUSIMB", BarcodeType::postUSIMB, BC_UNKNOWN},
-    {0x391bb836, L"code128", BarcodeType::code128, BC_CODE128},
-    {0x398eddaf, L"dataMatrix", BarcodeType::dataMatrix, BC_DATAMATRIX},
-    {0x3cff60a8, L"upcEadd2", BarcodeType::upcEadd2, BC_UNKNOWN},
-    {0x3cff60ab, L"upcEadd5", BarcodeType::upcEadd5, BC_UNKNOWN},
-    {0x402cb188, L"code2Of5Standard", BarcodeType::code2Of5Standard,
+    {0x7fb4a18, "ean13", BarcodeType::ean13, BC_EAN13},
+    {0x8d13a3d, "code11", BarcodeType::code11, BC_UNKNOWN},
+    {0x8d149a8, "code49", BarcodeType::code49, BC_UNKNOWN},
+    {0x8d16347, "code93", BarcodeType::code93, BC_UNKNOWN},
+    {0x91a92e2, "upsMaxicode", BarcodeType::upsMaxicode, BC_UNKNOWN},
+    {0xa7d48dc, "fim", BarcodeType::fim, BC_UNKNOWN},
+    {0xb359fe9, "msi", BarcodeType::msi, BC_UNKNOWN},
+    {0x121f738c, "code2Of5Matrix", BarcodeType::code2Of5Matrix, BC_UNKNOWN},
+    {0x15358616, "ucc128", BarcodeType::ucc128, BC_UNKNOWN},
+    {0x1f4bfa05, "rfid", BarcodeType::rfid, BC_UNKNOWN},
+    {0x1fda71bc, "rss14Stacked", BarcodeType::rss14Stacked, BC_UNKNOWN},
+    {0x22065087, "ean8add2", BarcodeType::ean8add2, BC_UNKNOWN},
+    {0x2206508a, "ean8add5", BarcodeType::ean8add5, BC_UNKNOWN},
+    {0x2278366c, "codabar", BarcodeType::codabar, BC_CODABAR},
+    {0x2a039a8d, "telepen", BarcodeType::telepen, BC_UNKNOWN},
+    {0x323ed337, "upcApwcd", BarcodeType::upcApwcd, BC_UNKNOWN},
+    {0x347a1846, "postUSIMB", BarcodeType::postUSIMB, BC_UNKNOWN},
+    {0x391bb836, "code128", BarcodeType::code128, BC_CODE128},
+    {0x398eddaf, "dataMatrix", BarcodeType::dataMatrix, BC_DATAMATRIX},
+    {0x3cff60a8, "upcEadd2", BarcodeType::upcEadd2, BC_UNKNOWN},
+    {0x3cff60ab, "upcEadd5", BarcodeType::upcEadd5, BC_UNKNOWN},
+    {0x402cb188, "code2Of5Standard", BarcodeType::code2Of5Standard, BC_UNKNOWN},
+    {0x411764f7, "aztec", BarcodeType::aztec, BC_UNKNOWN},
+    {0x44d4e84c, "ean8", BarcodeType::ean8, BC_EAN8},
+    {0x48468902, "ucc128sscc", BarcodeType::ucc128sscc, BC_UNKNOWN},
+    {0x4880aea4, "upcAadd2", BarcodeType::upcAadd2, BC_UNKNOWN},
+    {0x4880aea7, "upcAadd5", BarcodeType::upcAadd5, BC_UNKNOWN},
+    {0x54f18256, "code2Of5Industrial", BarcodeType::code2Of5Industrial,
      BC_UNKNOWN},
-    {0x411764f7, L"aztec", BarcodeType::aztec, BC_UNKNOWN},
-    {0x44d4e84c, L"ean8", BarcodeType::ean8, BC_EAN8},
-    {0x48468902, L"ucc128sscc", BarcodeType::ucc128sscc, BC_UNKNOWN},
-    {0x4880aea4, L"upcAadd2", BarcodeType::upcAadd2, BC_UNKNOWN},
-    {0x4880aea7, L"upcAadd5", BarcodeType::upcAadd5, BC_UNKNOWN},
-    {0x54f18256, L"code2Of5Industrial", BarcodeType::code2Of5Industrial,
+    {0x58e15f25, "rss14Limited", BarcodeType::rss14Limited, BC_UNKNOWN},
+    {0x5c08d1b9, "postAUSReplyPaid", BarcodeType::postAUSReplyPaid, BC_UNKNOWN},
+    {0x5fa700bd, "rss14", BarcodeType::rss14, BC_UNKNOWN},
+    {0x631a7e35, "logmars", BarcodeType::logmars, BC_UNKNOWN},
+    {0x6a236236, "pdf417", BarcodeType::pdf417, BC_PDF417},
+    {0x6d098ece, "upcean2", BarcodeType::upcean2, BC_UNKNOWN},
+    {0x6d098ed1, "upcean5", BarcodeType::upcean5, BC_UNKNOWN},
+    {0x76b04eed, "code3Of9extended", BarcodeType::code3Of9extended, BC_UNKNOWN},
+    {0x7c7db84a, "maxicode", BarcodeType::maxicode, BC_UNKNOWN},
+    {0x8266f7f7, "ucc128random", BarcodeType::ucc128random, BC_UNKNOWN},
+    {0x83eca147, "postUSDPBC", BarcodeType::postUSDPBC, BC_UNKNOWN},
+    {0x8dd71de0, "postAUSStandard", BarcodeType::postAUSStandard, BC_UNKNOWN},
+    {0x98adad85, "plessey", BarcodeType::plessey, BC_UNKNOWN},
+    {0x9f84cce6, "ean13pwcd", BarcodeType::ean13pwcd, BC_UNKNOWN},
+    {0xb514fbe9, "upcA", BarcodeType::upcA, BC_UPCA},
+    {0xb514fbed, "upcE", BarcodeType::upcE, BC_UNKNOWN},
+    {0xb5c6a853, "ean13add2", BarcodeType::ean13add2, BC_UNKNOWN},
+    {0xb5c6a856, "ean13add5", BarcodeType::ean13add5, BC_UNKNOWN},
+    {0xb81fc512, "postUKRM4SCC", BarcodeType::postUKRM4SCC, BC_UNKNOWN},
+    {0xbad34b22, "code128SSCC", BarcodeType::code128SSCC, BC_UNKNOWN},
+    {0xbfbe0cf6, "postUS5Zip", BarcodeType::postUS5Zip, BC_UNKNOWN},
+    {0xc56618e8, "pdf417macro", BarcodeType::pdf417macro, BC_UNKNOWN},
+    {0xca730f8a, "code2Of5Interleaved", BarcodeType::code2Of5Interleaved,
      BC_UNKNOWN},
-    {0x58e15f25, L"rss14Limited", BarcodeType::rss14Limited, BC_UNKNOWN},
-    {0x5c08d1b9, L"postAUSReplyPaid", BarcodeType::postAUSReplyPaid,
-     BC_UNKNOWN},
-    {0x5fa700bd, L"rss14", BarcodeType::rss14, BC_UNKNOWN},
-    {0x631a7e35, L"logmars", BarcodeType::logmars, BC_UNKNOWN},
-    {0x6a236236, L"pdf417", BarcodeType::pdf417, BC_PDF417},
-    {0x6d098ece, L"upcean2", BarcodeType::upcean2, BC_UNKNOWN},
-    {0x6d098ed1, L"upcean5", BarcodeType::upcean5, BC_UNKNOWN},
-    {0x76b04eed, L"code3Of9extended", BarcodeType::code3Of9extended,
-     BC_UNKNOWN},
-    {0x7c7db84a, L"maxicode", BarcodeType::maxicode, BC_UNKNOWN},
-    {0x8266f7f7, L"ucc128random", BarcodeType::ucc128random, BC_UNKNOWN},
-    {0x83eca147, L"postUSDPBC", BarcodeType::postUSDPBC, BC_UNKNOWN},
-    {0x8dd71de0, L"postAUSStandard", BarcodeType::postAUSStandard, BC_UNKNOWN},
-    {0x98adad85, L"plessey", BarcodeType::plessey, BC_UNKNOWN},
-    {0x9f84cce6, L"ean13pwcd", BarcodeType::ean13pwcd, BC_UNKNOWN},
-    {0xb514fbe9, L"upcA", BarcodeType::upcA, BC_UPCA},
-    {0xb514fbed, L"upcE", BarcodeType::upcE, BC_UNKNOWN},
-    {0xb5c6a853, L"ean13add2", BarcodeType::ean13add2, BC_UNKNOWN},
-    {0xb5c6a856, L"ean13add5", BarcodeType::ean13add5, BC_UNKNOWN},
-    {0xb81fc512, L"postUKRM4SCC", BarcodeType::postUKRM4SCC, BC_UNKNOWN},
-    {0xbad34b22, L"code128SSCC", BarcodeType::code128SSCC, BC_UNKNOWN},
-    {0xbfbe0cf6, L"postUS5Zip", BarcodeType::postUS5Zip, BC_UNKNOWN},
-    {0xc56618e8, L"pdf417macro", BarcodeType::pdf417macro, BC_UNKNOWN},
-    {0xca730f8a, L"code2Of5Interleaved", BarcodeType::code2Of5Interleaved,
-     BC_UNKNOWN},
-    {0xd0097ac6, L"rss14Expanded", BarcodeType::rss14Expanded, BC_UNKNOWN},
-    {0xd25a0240, L"postAUSCust2", BarcodeType::postAUSCust2, BC_UNKNOWN},
-    {0xd25a0241, L"postAUSCust3", BarcodeType::postAUSCust3, BC_UNKNOWN},
-    {0xd53ed3e7, L"rss14Truncated", BarcodeType::rss14Truncated, BC_UNKNOWN},
-    {0xe72bcd57, L"code128A", BarcodeType::code128A, BC_UNKNOWN},
-    {0xe72bcd58, L"code128B", BarcodeType::code128B, BC_CODE128_B},
-    {0xe72bcd59, L"code128C", BarcodeType::code128C, BC_CODE128_C},
-    {0xee83c50f, L"rss14StackedOmni", BarcodeType::rss14StackedOmni,
-     BC_UNKNOWN},
-    {0xf2a18f7e, L"QRCode", BarcodeType::QRCode, BC_QR_CODE},
-    {0xfaeaf37f, L"postUSStandard", BarcodeType::postUSStandard, BC_UNKNOWN},
-    {0xfb48155c, L"code3Of9", BarcodeType::code3Of9, BC_CODE39},
+    {0xd0097ac6, "rss14Expanded", BarcodeType::rss14Expanded, BC_UNKNOWN},
+    {0xd25a0240, "postAUSCust2", BarcodeType::postAUSCust2, BC_UNKNOWN},
+    {0xd25a0241, "postAUSCust3", BarcodeType::postAUSCust3, BC_UNKNOWN},
+    {0xd53ed3e7, "rss14Truncated", BarcodeType::rss14Truncated, BC_UNKNOWN},
+    {0xe72bcd57, "code128A", BarcodeType::code128A, BC_UNKNOWN},
+    {0xe72bcd58, "code128B", BarcodeType::code128B, BC_CODE128_B},
+    {0xe72bcd59, "code128C", BarcodeType::code128C, BC_CODE128_C},
+    {0xee83c50f, "rss14StackedOmni", BarcodeType::rss14StackedOmni, BC_UNKNOWN},
+    {0xf2a18f7e, "QRCode", BarcodeType::QRCode, BC_QR_CODE},
+    {0xfaeaf37f, "postUSStandard", BarcodeType::postUSStandard, BC_UNKNOWN},
+    {0xfb48155c, "code3Of9", BarcodeType::code3Of9, BC_CODE39},
 };
 
+Optional<BC_CHAR_ENCODING> CharEncodingFromString(const WideString& value) {
+  if (value.CompareNoCase(L"UTF-16"))
+    return CHAR_ENCODING_UNICODE;
+  if (value.CompareNoCase(L"UTF-8"))
+    return CHAR_ENCODING_UTF8;
+  return {};
+}
+
+Optional<BC_TEXT_LOC> TextLocFromAttribute(XFA_AttributeValue value) {
+  switch (value) {
+    case XFA_AttributeValue::None:
+      return BC_TEXT_LOC_NONE;
+    case XFA_AttributeValue::Above:
+      return BC_TEXT_LOC_ABOVE;
+    case XFA_AttributeValue::Below:
+      return BC_TEXT_LOC_BELOW;
+    case XFA_AttributeValue::AboveEmbedded:
+      return BC_TEXT_LOC_ABOVEEMBED;
+    case XFA_AttributeValue::BelowEmbedded:
+      return BC_TEXT_LOC_BELOWEMBED;
+    default:
+      return {};
+  }
+}
+
 }  // namespace.
 
 // static
@@ -105,113 +127,117 @@
       FX_HashCode_GetW(wsName.AsStringView(), true),
       [](const BarCodeInfo& arg, uint32_t hash) { return arg.uHash < hash; });
 
-  if (it != std::end(g_BarCodeData) && wsName.AsStringView() == it->pName)
+  if (it != std::end(g_BarCodeData) && wsName.EqualsASCII(it->pName))
     return it;
 
   return nullptr;
 }
 
-CXFA_FFBarcode::CXFA_FFBarcode(CXFA_Node* pNode) : CXFA_FFTextEdit(pNode) {}
+CXFA_FFBarcode::CXFA_FFBarcode(CXFA_Node* pNode, CXFA_Barcode* barcode)
+    : CXFA_FFTextEdit(pNode), barcode_(barcode) {}
 
-CXFA_FFBarcode::~CXFA_FFBarcode() {}
+CXFA_FFBarcode::~CXFA_FFBarcode() = default;
 
 bool CXFA_FFBarcode::LoadWidget() {
+  ASSERT(!IsLoaded());
   auto pNew = pdfium::MakeUnique<CFWL_Barcode>(GetFWLApp());
   CFWL_Barcode* pFWLBarcode = pNew.get();
-  m_pNormalWidget = std::move(pNew);
-  m_pNormalWidget->SetLayoutItem(this);
+  SetNormalWidget(std::move(pNew));
+  pFWLBarcode->SetAdapterIface(this);
 
-  CFWL_NoteDriver* pNoteDriver =
-      m_pNormalWidget->GetOwnerApp()->GetNoteDriver();
-  pNoteDriver->RegisterEventTarget(m_pNormalWidget.get(),
-                                   m_pNormalWidget.get());
-  m_pOldDelegate = m_pNormalWidget->GetDelegate();
-  m_pNormalWidget->SetDelegate(this);
-  m_pNormalWidget->LockUpdate();
+  CFWL_NoteDriver* pNoteDriver = pFWLBarcode->GetOwnerApp()->GetNoteDriver();
+  pNoteDriver->RegisterEventTarget(pFWLBarcode, pFWLBarcode);
+  m_pOldDelegate = pFWLBarcode->GetDelegate();
+  pFWLBarcode->SetDelegate(this);
 
-  pFWLBarcode->SetText(
-      m_pNode->GetWidgetAcc()->GetValue(XFA_VALUEPICTURE_Display));
-  UpdateWidgetProperty();
-  m_pNormalWidget->UnlockUpdate();
+  {
+    CFWL_Widget::ScopedUpdateLock update_lock(pFWLBarcode);
+    pFWLBarcode->SetText(m_pNode->GetValue(XFA_VALUEPICTURE_Display));
+    UpdateWidgetProperty();
+  }
+
   return CXFA_FFField::LoadWidget();
 }
 
 void CXFA_FFBarcode::RenderWidget(CXFA_Graphics* pGS,
                                   const CFX_Matrix& matrix,
-                                  uint32_t dwStatus) {
-  if (!IsMatchVisibleStatus(dwStatus))
+                                  HighlightOption highlight) {
+  if (!HasVisibleStatus())
     return;
 
   CFX_Matrix mtRotate = GetRotateMatrix();
   mtRotate.Concat(matrix);
 
-  CXFA_FFWidget::RenderWidget(pGS, mtRotate, dwStatus);
-  DrawBorder(pGS, m_pNode->GetWidgetAcc()->GetUIBorder(), m_rtUI, mtRotate);
+  CXFA_FFWidget::RenderWidget(pGS, mtRotate, highlight);
+  DrawBorder(pGS, m_pNode->GetUIBorder(), m_rtUI, mtRotate);
   RenderCaption(pGS, &mtRotate);
-  CFX_RectF rtWidget = m_pNormalWidget->GetWidgetRect();
+  CFX_RectF rtWidget = GetNormalWidget()->GetWidgetRect();
 
   CFX_Matrix mt(1, 0, 0, 1, rtWidget.left, rtWidget.top);
   mt.Concat(mtRotate);
-  m_pNormalWidget->DrawWidget(pGS, mt);
+  GetNormalWidget()->DrawWidget(pGS, mt);
 }
 
 void CXFA_FFBarcode::UpdateWidgetProperty() {
   CXFA_FFTextEdit::UpdateWidgetProperty();
 
-  auto* node = GetNode();
-  const BarCodeInfo* info = GetBarcodeTypeByName(node->GetBarcodeType());
+  const BarCodeInfo* info = GetBarcodeTypeByName(barcode_->GetBarcodeType());
   if (!info)
     return;
 
-  auto* pBarCodeWidget = static_cast<CFWL_Barcode*>(m_pNormalWidget.get());
+  auto* pBarCodeWidget = static_cast<CFWL_Barcode*>(GetNormalWidget());
   pBarCodeWidget->SetType(info->eBCType);
 
-  Optional<BC_CHAR_ENCODING> encoding =
-      node->GetBarcodeAttribute_CharEncoding();
-  if (encoding)
-    pBarCodeWidget->SetCharEncoding(*encoding);
+  Optional<WideString> encoding_string = barcode_->GetCharEncoding();
+  if (encoding_string) {
+    Optional<BC_CHAR_ENCODING> encoding =
+        CharEncodingFromString(*encoding_string);
+    if (encoding)
+      pBarCodeWidget->SetCharEncoding(*encoding);
+  }
 
-  Optional<bool> calcChecksum = node->GetBarcodeAttribute_Checksum();
+  Optional<bool> calcChecksum = barcode_->GetChecksum();
   if (calcChecksum)
     pBarCodeWidget->SetCalChecksum(*calcChecksum);
 
-  Optional<int32_t> dataLen = node->GetBarcodeAttribute_DataLength();
+  Optional<int32_t> dataLen = barcode_->GetDataLength();
   if (dataLen)
     pBarCodeWidget->SetDataLength(*dataLen);
 
-  Optional<char> startChar = node->GetBarcodeAttribute_StartChar();
+  Optional<char> startChar = barcode_->GetStartChar();
   if (startChar)
     pBarCodeWidget->SetStartChar(*startChar);
 
-  Optional<char> endChar = node->GetBarcodeAttribute_EndChar();
+  Optional<char> endChar = barcode_->GetEndChar();
   if (endChar)
     pBarCodeWidget->SetEndChar(*endChar);
 
-  Optional<int32_t> ecLevel = node->GetBarcodeAttribute_ECLevel();
+  Optional<int32_t> ecLevel = barcode_->GetECLevel();
   if (ecLevel)
     pBarCodeWidget->SetErrorCorrectionLevel(*ecLevel);
 
-  Optional<int32_t> width = node->GetBarcodeAttribute_ModuleWidth();
+  Optional<int32_t> width = barcode_->GetModuleWidth();
   if (width)
     pBarCodeWidget->SetModuleWidth(*width);
 
-  Optional<int32_t> height = node->GetBarcodeAttribute_ModuleHeight();
+  Optional<int32_t> height = barcode_->GetModuleHeight();
   if (height)
     pBarCodeWidget->SetModuleHeight(*height);
 
-  Optional<bool> printCheck = node->GetBarcodeAttribute_PrintChecksum();
+  Optional<bool> printCheck = barcode_->GetPrintChecksum();
   if (printCheck)
     pBarCodeWidget->SetPrintChecksum(*printCheck);
 
-  Optional<BC_TEXT_LOC> textLoc = node->GetBarcodeAttribute_TextLocation();
-  if (textLoc)
-    pBarCodeWidget->SetTextLocation(*textLoc);
+  Optional<XFA_AttributeValue> text_attr = barcode_->GetTextLocation();
+  if (text_attr) {
+    Optional<BC_TEXT_LOC> textLoc = TextLocFromAttribute(*text_attr);
+    if (textLoc)
+      pBarCodeWidget->SetTextLocation(*textLoc);
+  }
 
-  Optional<bool> truncate = node->GetBarcodeAttribute_Truncate();
-  if (truncate)
-    pBarCodeWidget->SetTruncated(*truncate);
+  // Truncated is currently not a supported flag.
 
-  Optional<int8_t> ratio = node->GetBarcodeAttribute_WideNarrowRatio();
+  Optional<int8_t> ratio = barcode_->GetWideNarrowRatio();
   if (ratio)
     pBarCodeWidget->SetWideNarrowRatio(*ratio);
 
@@ -222,18 +248,14 @@
   }
 }
 
-bool CXFA_FFBarcode::OnLButtonDown(uint32_t dwFlags, const CFX_PointF& point) {
-  auto* pBarCodeWidget = static_cast<CFWL_Barcode*>(m_pNormalWidget.get());
+bool CXFA_FFBarcode::AcceptsFocusOnButtonDown(uint32_t dwFlags,
+                                              const CFX_PointF& point,
+                                              FWL_MouseCommand command) {
+  auto* pBarCodeWidget = static_cast<CFWL_Barcode*>(GetNormalWidget());
   if (!pBarCodeWidget || pBarCodeWidget->IsProtectedType())
     return false;
-  if (!m_pNode->IsOpenAccess())
+  if (command == FWL_MouseCommand::LeftButtonDown && !m_pNode->IsOpenAccess())
     return false;
-  return CXFA_FFTextEdit::OnLButtonDown(dwFlags, point);
-}
 
-bool CXFA_FFBarcode::OnRButtonDown(uint32_t dwFlags, const CFX_PointF& point) {
-  auto* pBarCodeWidget = static_cast<CFWL_Barcode*>(m_pNormalWidget.get());
-  if (!pBarCodeWidget || pBarCodeWidget->IsProtectedType())
-    return false;
-  return CXFA_FFTextEdit::OnRButtonDown(dwFlags, point);
+  return CXFA_FFTextEdit::AcceptsFocusOnButtonDown(dwFlags, point, command);
 }
diff --git a/xfa/fxfa/cxfa_ffbarcode.h b/xfa/fxfa/cxfa_ffbarcode.h
index 9398470..83e0884 100644
--- a/xfa/fxfa/cxfa_ffbarcode.h
+++ b/xfa/fxfa/cxfa_ffbarcode.h
@@ -7,6 +7,7 @@
 #ifndef XFA_FXFA_CXFA_FFBARCODE_H_
 #define XFA_FXFA_CXFA_FFBARCODE_H_
 
+#include "core/fxcrt/unowned_ptr.h"
 #include "fxbarcode/BC_Library.h"
 #include "xfa/fxfa/cxfa_ffpageview.h"
 #include "xfa/fxfa/cxfa_fftextedit.h"
@@ -77,27 +78,33 @@
 };
 
 struct BarCodeInfo {
-  uint32_t uHash;
-  const wchar_t* pName;
+  uint32_t uHash;     // |pName| hashed as if wide string.
+  const char* pName;  // Raw, POD struct.
   BarcodeType eName;
   BC_TYPE eBCType;
 };
 
-class CXFA_FFBarcode : public CXFA_FFTextEdit {
+class CXFA_Barcode;
+
+class CXFA_FFBarcode final : public CXFA_FFTextEdit {
  public:
   static const BarCodeInfo* GetBarcodeTypeByName(const WideString& wsName);
 
-  explicit CXFA_FFBarcode(CXFA_Node* pNode);
+  CXFA_FFBarcode(CXFA_Node* pNode, CXFA_Barcode* barcode);
   ~CXFA_FFBarcode() override;
 
   // CXFA_FFTextEdit
   bool LoadWidget() override;
   void RenderWidget(CXFA_Graphics* pGS,
                     const CFX_Matrix& matrix,
-                    uint32_t dwStatus) override;
+                    HighlightOption highlight) override;
   void UpdateWidgetProperty() override;
-  bool OnLButtonDown(uint32_t dwFlags, const CFX_PointF& point) override;
-  bool OnRButtonDown(uint32_t dwFlags, const CFX_PointF& point) override;
+  bool AcceptsFocusOnButtonDown(uint32_t dwFlags,
+                                const CFX_PointF& point,
+                                FWL_MouseCommand command) override;
+
+ private:
+  UnownedPtr<CXFA_Barcode> const barcode_;
 };
 
 #endif  // XFA_FXFA_CXFA_FFBARCODE_H_
diff --git a/xfa/fxfa/cxfa_ffbarcode_unittest.cpp b/xfa/fxfa/cxfa_ffbarcode_unittest.cpp
index 455b5a6..6236b10 100644
--- a/xfa/fxfa/cxfa_ffbarcode_unittest.cpp
+++ b/xfa/fxfa/cxfa_ffbarcode_unittest.cpp
@@ -5,7 +5,6 @@
 #include "xfa/fxfa/cxfa_ffbarcode.h"
 
 #include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/base/ptr_util.h"
 
 TEST(XFA_FFBarcode, GetBarcodeTypeByName) {
   EXPECT_EQ(nullptr, CXFA_FFBarcode::GetBarcodeTypeByName(L""));
diff --git a/xfa/fxfa/cxfa_ffcheckbutton.cpp b/xfa/fxfa/cxfa_ffcheckbutton.cpp
index 89af82c..1d39e2f 100644
--- a/xfa/fxfa/cxfa_ffcheckbutton.cpp
+++ b/xfa/fxfa/cxfa_ffcheckbutton.cpp
@@ -21,66 +21,69 @@
 #include "xfa/fxfa/cxfa_ffwidget.h"
 #include "xfa/fxfa/parser/cxfa_border.h"
 #include "xfa/fxfa/parser/cxfa_caption.h"
+#include "xfa/fxfa/parser/cxfa_checkbutton.h"
 #include "xfa/fxfa/parser/cxfa_para.h"
 
-CXFA_FFCheckButton::CXFA_FFCheckButton(CXFA_Node* pNode)
-    : CXFA_FFField(pNode), m_pOldDelegate(nullptr) {}
+CXFA_FFCheckButton::CXFA_FFCheckButton(CXFA_Node* pNode,
+                                       CXFA_CheckButton* button)
+    : CXFA_FFField(pNode), button_(button) {}
 
-CXFA_FFCheckButton::~CXFA_FFCheckButton() {}
+CXFA_FFCheckButton::~CXFA_FFCheckButton() = default;
 
 bool CXFA_FFCheckButton::LoadWidget() {
+  ASSERT(!IsLoaded());
   auto pNew = pdfium::MakeUnique<CFWL_CheckBox>(GetFWLApp());
   CFWL_CheckBox* pCheckBox = pNew.get();
-  m_pNormalWidget = std::move(pNew);
-  m_pNormalWidget->SetLayoutItem(this);
+  SetNormalWidget(std::move(pNew));
+  pCheckBox->SetAdapterIface(this);
 
-  CFWL_NoteDriver* pNoteDriver =
-      m_pNormalWidget->GetOwnerApp()->GetNoteDriver();
-  pNoteDriver->RegisterEventTarget(m_pNormalWidget.get(),
-                                   m_pNormalWidget.get());
-  m_pOldDelegate = m_pNormalWidget->GetDelegate();
-  m_pNormalWidget->SetDelegate(this);
-  if (m_pNode->GetWidgetAcc()->IsRadioButton())
+  CFWL_NoteDriver* pNoteDriver = pCheckBox->GetOwnerApp()->GetNoteDriver();
+  pNoteDriver->RegisterEventTarget(pCheckBox, pCheckBox);
+  m_pOldDelegate = pCheckBox->GetDelegate();
+  pCheckBox->SetDelegate(this);
+  if (m_pNode->IsRadioButton())
     pCheckBox->ModifyStylesEx(FWL_STYLEEXT_CKB_RadioButton, 0xFFFFFFFF);
 
-  m_pNormalWidget->LockUpdate();
-  UpdateWidgetProperty();
-  SetFWLCheckState(m_pNode->GetWidgetAcc()->GetCheckState());
-  m_pNormalWidget->UnlockUpdate();
+  {
+    CFWL_Widget::ScopedUpdateLock update_lock(pCheckBox);
+    UpdateWidgetProperty();
+    SetFWLCheckState(m_pNode->GetCheckState());
+  }
+
   return CXFA_FFField::LoadWidget();
 }
 
 void CXFA_FFCheckButton::UpdateWidgetProperty() {
-  auto* pCheckBox = static_cast<CFWL_CheckBox*>(m_pNormalWidget.get());
+  auto* pCheckBox = static_cast<CFWL_CheckBox*>(GetNormalWidget());
   if (!pCheckBox)
     return;
 
-  pCheckBox->SetBoxSize(m_pNode->GetWidgetAcc()->GetCheckButtonSize());
+  pCheckBox->SetBoxSize(m_pNode->GetCheckButtonSize());
   uint32_t dwStyleEx = FWL_STYLEEXT_CKB_SignShapeCross;
-  switch (m_pNode->GetWidgetAcc()->GetCheckButtonMark()) {
-    case XFA_AttributeEnum::Check:
+  switch (button_->GetMark()) {
+    case XFA_AttributeValue::Check:
       dwStyleEx = FWL_STYLEEXT_CKB_SignShapeCheck;
       break;
-    case XFA_AttributeEnum::Circle:
+    case XFA_AttributeValue::Circle:
       dwStyleEx = FWL_STYLEEXT_CKB_SignShapeCircle;
       break;
-    case XFA_AttributeEnum::Cross:
+    case XFA_AttributeValue::Cross:
       break;
-    case XFA_AttributeEnum::Diamond:
+    case XFA_AttributeValue::Diamond:
       dwStyleEx = FWL_STYLEEXT_CKB_SignShapeDiamond;
       break;
-    case XFA_AttributeEnum::Square:
+    case XFA_AttributeValue::Square:
       dwStyleEx = FWL_STYLEEXT_CKB_SignShapeSquare;
       break;
-    case XFA_AttributeEnum::Star:
+    case XFA_AttributeValue::Star:
       dwStyleEx = FWL_STYLEEXT_CKB_SignShapeStar;
       break;
     default: {
-      if (m_pNode->GetWidgetAcc()->IsCheckButtonRound())
+      if (button_->IsRound())
         dwStyleEx = FWL_STYLEEXT_CKB_SignShapeCircle;
     } break;
   }
-  if (m_pNode->GetWidgetAcc()->IsAllowNeutral())
+  if (button_->IsAllowNeutral())
     dwStyleEx |= FWL_STYLEEXT_CKB_3State;
 
   pCheckBox->ModifyStylesEx(
@@ -90,13 +93,12 @@
 bool CXFA_FFCheckButton::PerformLayout() {
   CXFA_FFWidget::PerformLayout();
 
-  float fCheckSize = m_pNode->GetWidgetAcc()->GetCheckButtonSize();
+  float fCheckSize = m_pNode->GetCheckButtonSize();
   CXFA_Margin* margin = m_pNode->GetMarginIfExists();
   CFX_RectF rtWidget = GetRectWithoutRotate();
-  if (margin)
-    XFA_RectWithoutMargin(rtWidget, margin);
+  XFA_RectWithoutMargin(&rtWidget, margin);
 
-  XFA_AttributeEnum iCapPlacement = XFA_AttributeEnum::Unknown;
+  XFA_AttributeValue iCapPlacement = XFA_AttributeValue::Unknown;
   float fCapReserve = 0;
   CXFA_Caption* caption = m_pNode->GetCaptionIfExists();
   if (caption && caption->IsVisible()) {
@@ -104,8 +106,8 @@
     iCapPlacement = caption->GetPlacementType();
     fCapReserve = caption->GetReserve();
     if (fCapReserve <= 0) {
-      if (iCapPlacement == XFA_AttributeEnum::Top ||
-          iCapPlacement == XFA_AttributeEnum::Bottom) {
+      if (iCapPlacement == XFA_AttributeValue::Top ||
+          iCapPlacement == XFA_AttributeValue::Bottom) {
         fCapReserve = rtWidget.height - fCheckSize;
       } else {
         fCapReserve = rtWidget.width - fCheckSize;
@@ -113,8 +115,8 @@
     }
   }
 
-  XFA_AttributeEnum iHorzAlign = XFA_AttributeEnum::Left;
-  XFA_AttributeEnum iVertAlign = XFA_AttributeEnum::Top;
+  XFA_AttributeValue iHorzAlign = XFA_AttributeValue::Left;
+  XFA_AttributeValue iVertAlign = XFA_AttributeValue::Top;
   CXFA_Para* para = m_pNode->GetParaIfExists();
   if (para) {
     iHorzAlign = para->GetHorizontalAlign();
@@ -124,74 +126,73 @@
   m_rtUI = rtWidget;
   CXFA_Margin* captionMargin = caption ? caption->GetMarginIfExists() : nullptr;
   switch (iCapPlacement) {
-    case XFA_AttributeEnum::Left: {
+    case XFA_AttributeValue::Left: {
       m_rtCaption.width = fCapReserve;
       CapLeftRightPlacement(captionMargin);
       m_rtUI.width -= fCapReserve;
       m_rtUI.left += fCapReserve;
       break;
     }
-    case XFA_AttributeEnum::Top: {
+    case XFA_AttributeValue::Top: {
       m_rtCaption.height = fCapReserve;
-      XFA_RectWithoutMargin(m_rtCaption, captionMargin);
+      XFA_RectWithoutMargin(&m_rtCaption, captionMargin);
       m_rtUI.height -= fCapReserve;
       m_rtUI.top += fCapReserve;
       break;
     }
-    case XFA_AttributeEnum::Right: {
+    case XFA_AttributeValue::Right: {
       m_rtCaption.left = m_rtCaption.right() - fCapReserve;
       m_rtCaption.width = fCapReserve;
       CapLeftRightPlacement(captionMargin);
       m_rtUI.width -= fCapReserve;
       break;
     }
-    case XFA_AttributeEnum::Bottom: {
+    case XFA_AttributeValue::Bottom: {
       m_rtCaption.top = m_rtCaption.bottom() - fCapReserve;
       m_rtCaption.height = fCapReserve;
-      XFA_RectWithoutMargin(m_rtCaption, captionMargin);
+      XFA_RectWithoutMargin(&m_rtCaption, captionMargin);
       m_rtUI.height -= fCapReserve;
       break;
     }
-    case XFA_AttributeEnum::Inline:
+    case XFA_AttributeValue::Inline:
       break;
     default:
-      iHorzAlign = XFA_AttributeEnum::Right;
+      iHorzAlign = XFA_AttributeValue::Right;
       break;
   }
 
-  if (iHorzAlign == XFA_AttributeEnum::Center)
+  if (iHorzAlign == XFA_AttributeValue::Center)
     m_rtUI.left += (m_rtUI.width - fCheckSize) / 2;
-  else if (iHorzAlign == XFA_AttributeEnum::Right)
+  else if (iHorzAlign == XFA_AttributeValue::Right)
     m_rtUI.left = m_rtUI.right() - fCheckSize;
 
-  if (iVertAlign == XFA_AttributeEnum::Middle)
+  if (iVertAlign == XFA_AttributeValue::Middle)
     m_rtUI.top += (m_rtUI.height - fCheckSize) / 2;
-  else if (iVertAlign == XFA_AttributeEnum::Bottom)
+  else if (iVertAlign == XFA_AttributeValue::Bottom)
     m_rtUI.top = m_rtUI.bottom() - fCheckSize;
 
   m_rtUI.width = fCheckSize;
   m_rtUI.height = fCheckSize;
   AddUIMargin(iCapPlacement);
   m_rtCheckBox = m_rtUI;
-  CXFA_Border* borderUI = m_pNode->GetWidgetAcc()->GetUIBorder();
+  CXFA_Border* borderUI = m_pNode->GetUIBorder();
   if (borderUI) {
     CXFA_Margin* borderMargin = borderUI->GetMarginIfExists();
-    if (borderMargin)
-      XFA_RectWithoutMargin(m_rtUI, borderMargin);
+    XFA_RectWithoutMargin(&m_rtUI, borderMargin);
   }
 
   m_rtUI.Normalize();
   LayoutCaption();
   SetFWLRect();
-  if (m_pNormalWidget)
-    m_pNormalWidget->Update();
+  if (GetNormalWidget())
+    GetNormalWidget()->Update();
 
   return true;
 }
 
 void CXFA_FFCheckButton::CapLeftRightPlacement(
     const CXFA_Margin* captionMargin) {
-  XFA_RectWithoutMargin(m_rtCaption, captionMargin);
+  XFA_RectWithoutMargin(&m_rtCaption, captionMargin);
   if (m_rtCaption.height < 0)
     m_rtCaption.top += m_rtCaption.height;
   if (m_rtCaption.width < 0) {
@@ -200,15 +201,15 @@
   }
 }
 
-void CXFA_FFCheckButton::AddUIMargin(XFA_AttributeEnum iCapPlacement) {
-  CFX_RectF rtUIMargin = m_pNode->GetWidgetAcc()->GetUIMargin();
+void CXFA_FFCheckButton::AddUIMargin(XFA_AttributeValue iCapPlacement) {
+  CFX_RectF rtUIMargin = m_pNode->GetUIMargin();
   m_rtUI.top -= rtUIMargin.top / 2 - rtUIMargin.height / 2;
 
   float fLeftAddRight = rtUIMargin.left + rtUIMargin.width;
   float fTopAddBottom = rtUIMargin.top + rtUIMargin.height;
   if (m_rtUI.width < fLeftAddRight) {
-    if (iCapPlacement == XFA_AttributeEnum::Right ||
-        iCapPlacement == XFA_AttributeEnum::Left) {
+    if (iCapPlacement == XFA_AttributeValue::Right ||
+        iCapPlacement == XFA_AttributeValue::Left) {
       m_rtUI.left -= fLeftAddRight - m_rtUI.width;
     } else {
       m_rtUI.left -= 2 * (fLeftAddRight - m_rtUI.width);
@@ -216,7 +217,7 @@
     m_rtUI.width += 2 * (fLeftAddRight - m_rtUI.width);
   }
   if (m_rtUI.height < fTopAddBottom) {
-    if (iCapPlacement == XFA_AttributeEnum::Right)
+    if (iCapPlacement == XFA_AttributeValue::Right)
       m_rtUI.left -= fTopAddBottom - m_rtUI.height;
 
     m_rtUI.top -= fTopAddBottom - m_rtUI.height;
@@ -226,40 +227,40 @@
 
 void CXFA_FFCheckButton::RenderWidget(CXFA_Graphics* pGS,
                                       const CFX_Matrix& matrix,
-                                      uint32_t dwStatus) {
-  if (!IsMatchVisibleStatus(dwStatus))
+                                      HighlightOption highlight) {
+  if (!HasVisibleStatus())
     return;
 
   CFX_Matrix mtRotate = GetRotateMatrix();
   mtRotate.Concat(matrix);
 
-  CXFA_FFWidget::RenderWidget(pGS, mtRotate, dwStatus);
-  DrawBorderWithFlag(pGS, m_pNode->GetWidgetAcc()->GetUIBorder(), m_rtUI,
-                     mtRotate, m_pNode->GetWidgetAcc()->IsCheckButtonRound());
+  CXFA_FFWidget::RenderWidget(pGS, mtRotate, highlight);
+  DrawBorderWithFlag(pGS, m_pNode->GetUIBorder(), m_rtUI, mtRotate,
+                     button_->IsRound());
   RenderCaption(pGS, &mtRotate);
-  DrawHighlight(pGS, &mtRotate, dwStatus,
-                m_pNode->GetWidgetAcc()->IsCheckButtonRound());
+  DrawHighlight(pGS, &mtRotate, highlight,
+                button_->IsRound() ? kRoundShape : kSquareShape);
   CFX_Matrix mt(1, 0, 0, 1, m_rtCheckBox.left, m_rtCheckBox.top);
   mt.Concat(mtRotate);
-  GetApp()->GetFWLWidgetMgr()->OnDrawWidget(m_pNormalWidget.get(), pGS, mt);
+  GetApp()->GetFWLWidgetMgr()->OnDrawWidget(GetNormalWidget(), pGS, mt);
 }
 
 bool CXFA_FFCheckButton::OnLButtonUp(uint32_t dwFlags,
                                      const CFX_PointF& point) {
-  if (!m_pNormalWidget || !IsButtonDown())
+  if (!GetNormalWidget() || !IsButtonDown())
     return false;
 
+  ObservedPtr<CXFA_FFCheckButton> pWatched(this);
   SetButtonDown(false);
-  CFWL_MessageMouse ms(nullptr, m_pNormalWidget.get());
-  ms.m_dwCmd = FWL_MouseCommand::LeftButtonUp;
-  ms.m_dwFlags = dwFlags;
-  ms.m_pos = FWLToClient(point);
-  TranslateFWLMessage(&ms);
-  return true;
+  SendMessageToFWLWidget(pdfium::MakeUnique<CFWL_MessageMouse>(
+      GetNormalWidget(), FWL_MouseCommand::LeftButtonUp, dwFlags,
+      FWLToClient(point)));
+
+  return !!pWatched;
 }
 
 XFA_CHECKSTATE CXFA_FFCheckButton::FWLState2XFAState() {
-  uint32_t dwState = m_pNormalWidget->GetStates();
+  uint32_t dwState = GetNormalWidget()->GetStates();
   if (dwState & FWL_STATE_CKB_Checked)
     return XFA_CHECKSTATE_On;
   if (dwState & FWL_STATE_CKB_Neutral)
@@ -269,31 +270,31 @@
 
 bool CXFA_FFCheckButton::CommitData() {
   XFA_CHECKSTATE eCheckState = FWLState2XFAState();
-  m_pNode->GetWidgetAcc()->SetCheckState(eCheckState, true);
+  m_pNode->SetCheckState(eCheckState, true);
   return true;
 }
 
 bool CXFA_FFCheckButton::IsDataChanged() {
   XFA_CHECKSTATE eCheckState = FWLState2XFAState();
-  return m_pNode->GetWidgetAcc()->GetCheckState() != eCheckState;
+  return m_pNode->GetCheckState() != eCheckState;
 }
 
 void CXFA_FFCheckButton::SetFWLCheckState(XFA_CHECKSTATE eCheckState) {
   if (eCheckState == XFA_CHECKSTATE_Neutral)
-    m_pNormalWidget->SetStates(FWL_STATE_CKB_Neutral);
+    GetNormalWidget()->SetStates(FWL_STATE_CKB_Neutral);
   else if (eCheckState == XFA_CHECKSTATE_On)
-    m_pNormalWidget->SetStates(FWL_STATE_CKB_Checked);
+    GetNormalWidget()->SetStates(FWL_STATE_CKB_Checked);
   else
-    m_pNormalWidget->RemoveStates(FWL_STATE_CKB_Checked);
+    GetNormalWidget()->RemoveStates(FWL_STATE_CKB_Checked);
 }
 
 bool CXFA_FFCheckButton::UpdateFWLData() {
-  if (!m_pNormalWidget)
+  if (!GetNormalWidget())
     return false;
 
-  XFA_CHECKSTATE eState = m_pNode->GetWidgetAcc()->GetCheckState();
+  XFA_CHECKSTATE eState = m_pNode->GetCheckState();
   SetFWLCheckState(eState);
-  m_pNormalWidget->Update();
+  GetNormalWidget()->Update();
   return true;
 }
 
@@ -307,29 +308,30 @@
     case CFWL_Event::Type::CheckStateChanged: {
       CXFA_EventParam eParam;
       eParam.m_eType = XFA_EVENT_Change;
-      eParam.m_wsNewText =
-          m_pNode->GetWidgetAcc()->GetValue(XFA_VALUEPICTURE_Raw);
+      eParam.m_wsPrevText = m_pNode->GetValue(XFA_VALUEPICTURE_Raw);
 
       CXFA_Node* exclNode = m_pNode->GetExclGroupIfExists();
       if (ProcessCommittedData()) {
-        eParam.m_pTarget = exclNode ? exclNode->GetWidgetAcc() : nullptr;
+        eParam.m_pTarget = exclNode;
         if (exclNode) {
-          m_pDocView->AddValidateWidget(exclNode->GetWidgetAcc());
-          m_pDocView->AddCalculateWidgetAcc(exclNode->GetWidgetAcc());
-          exclNode->ProcessEvent(GetDocView(), XFA_AttributeEnum::Change,
+          m_pDocView->AddValidateNode(exclNode);
+          m_pDocView->AddCalculateNode(exclNode);
+          exclNode->ProcessEvent(GetDocView(), XFA_AttributeValue::Change,
                                  &eParam);
         }
-        eParam.m_pTarget = m_pNode->GetWidgetAcc();
-        m_pNode->ProcessEvent(GetDocView(), XFA_AttributeEnum::Change, &eParam);
+        eParam.m_pTarget = m_pNode.Get();
+        m_pNode->ProcessEvent(GetDocView(), XFA_AttributeValue::Change,
+                              &eParam);
       } else {
-        SetFWLCheckState(m_pNode->GetWidgetAcc()->GetCheckState());
+        SetFWLCheckState(m_pNode->GetCheckState());
       }
       if (exclNode) {
-        eParam.m_pTarget = exclNode->GetWidgetAcc();
-        exclNode->ProcessEvent(GetDocView(), XFA_AttributeEnum::Click, &eParam);
+        eParam.m_pTarget = exclNode;
+        exclNode->ProcessEvent(GetDocView(), XFA_AttributeValue::Click,
+                               &eParam);
       }
-      eParam.m_pTarget = m_pNode->GetWidgetAcc();
-      m_pNode->ProcessEvent(GetDocView(), XFA_AttributeEnum::Click, &eParam);
+      eParam.m_pTarget = m_pNode.Get();
+      m_pNode->ProcessEvent(GetDocView(), XFA_AttributeValue::Click, &eParam);
       break;
     }
     default:
diff --git a/xfa/fxfa/cxfa_ffcheckbutton.h b/xfa/fxfa/cxfa_ffcheckbutton.h
index f841d78..3e5a723 100644
--- a/xfa/fxfa/cxfa_ffcheckbutton.h
+++ b/xfa/fxfa/cxfa_ffcheckbutton.h
@@ -7,18 +7,22 @@
 #ifndef XFA_FXFA_CXFA_FFCHECKBUTTON_H_
 #define XFA_FXFA_CXFA_FFCHECKBUTTON_H_
 
+#include "core/fxcrt/unowned_ptr.h"
 #include "xfa/fxfa/cxfa_fffield.h"
 #include "xfa/fxfa/cxfa_ffpageview.h"
+#include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_FFCheckButton : public CXFA_FFField {
+class CXFA_CheckButton;
+
+class CXFA_FFCheckButton final : public CXFA_FFField {
  public:
-  explicit CXFA_FFCheckButton(CXFA_Node* pNode);
+  CXFA_FFCheckButton(CXFA_Node* pNode, CXFA_CheckButton* button);
   ~CXFA_FFCheckButton() override;
 
   // CXFA_FFField
   void RenderWidget(CXFA_Graphics* pGS,
                     const CFX_Matrix& matrix,
-                    uint32_t dwStatus) override;
+                    HighlightOption highlight) override;
 
   bool LoadWidget() override;
   bool PerformLayout() override;
@@ -37,11 +41,12 @@
   bool CommitData() override;
   bool IsDataChanged() override;
   void CapLeftRightPlacement(const CXFA_Margin* captionMargin);
-  void AddUIMargin(XFA_AttributeEnum iCapPlacement);
+  void AddUIMargin(XFA_AttributeValue iCapPlacement);
   XFA_CHECKSTATE FWLState2XFAState();
 
-  IFWL_WidgetDelegate* m_pOldDelegate;
+  UnownedPtr<IFWL_WidgetDelegate> m_pOldDelegate;
   CFX_RectF m_rtCheckBox;
+  UnownedPtr<CXFA_CheckButton> const button_;
 };
 
 #endif  // XFA_FXFA_CXFA_FFCHECKBUTTON_H_
diff --git a/xfa/fxfa/cxfa_ffcombobox.cpp b/xfa/fxfa/cxfa_ffcombobox.cpp
index 4c024fb..61fa659 100644
--- a/xfa/fxfa/cxfa_ffcombobox.cpp
+++ b/xfa/fxfa/cxfa_ffcombobox.cpp
@@ -9,6 +9,7 @@
 #include <utility>
 #include <vector>
 
+#include "third_party/base/ptr_util.h"
 #include "xfa/fwl/cfwl_combobox.h"
 #include "xfa/fwl/cfwl_eventselectchanged.h"
 #include "xfa/fwl/cfwl_notedriver.h"
@@ -22,61 +23,69 @@
   return static_cast<CFWL_ComboBox*>(widget);
 }
 
+const CFWL_ComboBox* ToComboBox(const CFWL_Widget* widget) {
+  return static_cast<const CFWL_ComboBox*>(widget);
+}
+
 }  // namespace
 
-CXFA_FFComboBox::CXFA_FFComboBox(CXFA_Node* pNode)
-    : CXFA_FFField(pNode), m_pOldDelegate(nullptr) {}
+CXFA_FFComboBox::CXFA_FFComboBox(CXFA_Node* pNode) : CXFA_FFDropDown(pNode) {}
 
-CXFA_FFComboBox::~CXFA_FFComboBox() {}
+CXFA_FFComboBox::~CXFA_FFComboBox() = default;
 
-CFX_RectF CXFA_FFComboBox::GetBBox(uint32_t dwStatus, bool bDrawFocus) {
-  return bDrawFocus ? CFX_RectF() : CXFA_FFWidget::GetBBox(dwStatus);
+CXFA_FFComboBox* CXFA_FFComboBox::AsComboBox() {
+  return this;
+}
+
+CFX_RectF CXFA_FFComboBox::GetBBox(FocusOption focus) {
+  if (focus == kDrawFocus)
+    return CFX_RectF();
+  return CXFA_FFWidget::GetBBox(kDoNotDrawFocus);
 }
 
 bool CXFA_FFComboBox::PtInActiveRect(const CFX_PointF& point) {
-  auto* pComboBox = ToComboBox(m_pNormalWidget.get());
+  auto* pComboBox = ToComboBox(GetNormalWidget());
   return pComboBox && pComboBox->GetBBox().Contains(point);
 }
 
 bool CXFA_FFComboBox::LoadWidget() {
+  ASSERT(!IsLoaded());
   auto pNew = pdfium::MakeUnique<CFWL_ComboBox>(GetFWLApp());
   CFWL_ComboBox* pComboBox = pNew.get();
-  m_pNormalWidget = std::move(pNew);
-  m_pNormalWidget->SetLayoutItem(this);
+  SetNormalWidget(std::move(pNew));
+  pComboBox->SetAdapterIface(this);
 
-  CFWL_NoteDriver* pNoteDriver =
-      m_pNormalWidget->GetOwnerApp()->GetNoteDriver();
-  pNoteDriver->RegisterEventTarget(m_pNormalWidget.get(),
-                                   m_pNormalWidget.get());
-  m_pOldDelegate = m_pNormalWidget->GetDelegate();
-  m_pNormalWidget->SetDelegate(this);
-  m_pNormalWidget->LockUpdate();
+  CFWL_NoteDriver* pNoteDriver = pComboBox->GetOwnerApp()->GetNoteDriver();
+  pNoteDriver->RegisterEventTarget(pComboBox, pComboBox);
+  m_pOldDelegate = pComboBox->GetDelegate();
+  pComboBox->SetDelegate(this);
 
-  for (const auto& label : m_pNode->GetWidgetAcc()->GetChoiceListItems(false))
-    pComboBox->AddString(label.AsStringView());
+  {
+    CFWL_Widget::ScopedUpdateLock update_lock(pComboBox);
+    for (const auto& label : m_pNode->GetChoiceListItems(false))
+      pComboBox->AddString(label);
 
-  std::vector<int32_t> iSelArray = m_pNode->GetWidgetAcc()->GetSelectedItems();
-  if (iSelArray.empty()) {
-    pComboBox->SetEditText(
-        m_pNode->GetWidgetAcc()->GetValue(XFA_VALUEPICTURE_Raw));
-  } else {
-    pComboBox->SetCurSel(iSelArray.front());
+    std::vector<int32_t> iSelArray = m_pNode->GetSelectedItems();
+    if (iSelArray.empty())
+      pComboBox->SetEditText(m_pNode->GetValue(XFA_VALUEPICTURE_Raw));
+    else
+      pComboBox->SetCurSel(iSelArray.front());
+
+    UpdateWidgetProperty();
   }
 
-  UpdateWidgetProperty();
-  m_pNormalWidget->UnlockUpdate();
   return CXFA_FFField::LoadWidget();
 }
 
 void CXFA_FFComboBox::UpdateWidgetProperty() {
-  auto* pComboBox = ToComboBox(m_pNormalWidget.get());
+  auto* pComboBox = ToComboBox(GetNormalWidget());
   if (!pComboBox)
     return;
 
   uint32_t dwExtendedStyle = 0;
   uint32_t dwEditStyles = FWL_STYLEEXT_EDT_ReadOnly;
   dwExtendedStyle |= UpdateUIProperty();
-  if (m_pNode->GetWidgetAcc()->IsChoiceListAllowTextEntry()) {
+  if (m_pNode->IsChoiceListAllowTextEntry()) {
     dwEditStyles &= ~FWL_STYLEEXT_EDT_ReadOnly;
     dwExtendedStyle |= FWL_STYLEEXT_CMB_DropDown;
   }
@@ -85,9 +94,9 @@
     dwExtendedStyle |= FWL_STYLEEXT_CMB_ReadOnly;
   }
   dwExtendedStyle |= GetAlignment();
-  m_pNormalWidget->ModifyStylesEx(dwExtendedStyle, 0xFFFFFFFF);
+  GetNormalWidget()->ModifyStylesEx(dwExtendedStyle, 0xFFFFFFFF);
 
-  if (!m_pNode->GetWidgetAcc()->IsHorizontalScrollPolicyOff())
+  if (!m_pNode->IsHorizontalScrollPolicyOff())
     dwEditStyles |= FWL_STYLEEXT_EDT_AutoHScroll;
 
   pComboBox->EditModifyStylesEx(dwEditStyles, 0xFFFFFFFF);
@@ -102,44 +111,49 @@
 }
 
 bool CXFA_FFComboBox::OnKillFocus(CXFA_FFWidget* pNewWidget) {
+  ObservedPtr<CXFA_FFWidget> pWatched(this);
+  ObservedPtr<CXFA_FFWidget> pNewWatched(pNewWidget);
   if (!ProcessCommittedData())
     UpdateFWLData();
 
-  CXFA_FFField::OnKillFocus(pNewWidget);
-  return true;
+  return pWatched && pNewWatched &&
+         CXFA_FFField::OnKillFocus(pNewWatched.Get());
 }
 
 void CXFA_FFComboBox::OpenDropDownList() {
-  ToComboBox(m_pNormalWidget.get())->OpenDropDownList(true);
+  ToComboBox(GetNormalWidget())->OpenDropDownList(true);
 }
 
 bool CXFA_FFComboBox::CommitData() {
-  return m_pNode->GetWidgetAcc()->SetValue(XFA_VALUEPICTURE_Raw, m_wsNewValue);
+  return m_pNode->SetValue(XFA_VALUEPICTURE_Raw, m_wsNewValue);
 }
 
 bool CXFA_FFComboBox::IsDataChanged() {
-  auto* pFWLcombobox = ToComboBox(m_pNormalWidget.get());
-  WideString wsText = pFWLcombobox->GetEditText();
-  int32_t iCursel = pFWLcombobox->GetCurSel();
-  if (iCursel >= 0) {
-    WideString wsSel = pFWLcombobox->GetTextByIndex(iCursel);
-    if (wsSel == wsText)
-      wsText = m_pNode->GetWidgetAcc()
-                   ->GetChoiceListItem(iCursel, true)
-                   .value_or(L"");
-  }
-  if (m_pNode->GetWidgetAcc()->GetValue(XFA_VALUEPICTURE_Raw) == wsText)
+  WideString wsText = GetCurrentText();
+  if (m_pNode->GetValue(XFA_VALUEPICTURE_Raw) == wsText)
     return false;
 
-  m_wsNewValue = wsText;
+  m_wsNewValue = std::move(wsText);
   return true;
 }
 
 void CXFA_FFComboBox::FWLEventSelChange(CXFA_EventParam* pParam) {
   pParam->m_eType = XFA_EVENT_Change;
-  pParam->m_pTarget = m_pNode->GetWidgetAcc();
-  pParam->m_wsNewText = ToComboBox(m_pNormalWidget.get())->GetEditText();
-  m_pNode->ProcessEvent(GetDocView(), XFA_AttributeEnum::Change, pParam);
+  pParam->m_pTarget = m_pNode.Get();
+  pParam->m_wsPrevText = ToComboBox(GetNormalWidget())->GetEditText();
+  m_pNode->ProcessEvent(GetDocView(), XFA_AttributeValue::Change, pParam);
+}
+
+WideString CXFA_FFComboBox::GetCurrentText() const {
+  auto* pFWLcombobox = ToComboBox(GetNormalWidget());
+  WideString wsText = pFWLcombobox->GetEditText();
+  int32_t iCursel = pFWLcombobox->GetCurSel();
+  if (iCursel >= 0) {
+    WideString wsSel = pFWLcombobox->GetTextByIndex(iCursel);
+    if (wsSel == wsText)
+      wsText = m_pNode->GetChoiceListItem(iCursel, true).value_or(L"");
+  }
+  return wsText;
 }
 
 uint32_t CXFA_FFComboBox::GetAlignment() {
@@ -149,18 +163,18 @@
 
   uint32_t dwExtendedStyle = 0;
   switch (para->GetHorizontalAlign()) {
-    case XFA_AttributeEnum::Center:
+    case XFA_AttributeValue::Center:
       dwExtendedStyle |=
           FWL_STYLEEXT_CMB_EditHCenter | FWL_STYLEEXT_CMB_ListItemCenterAlign;
       break;
-    case XFA_AttributeEnum::Justify:
+    case XFA_AttributeValue::Justify:
       dwExtendedStyle |= FWL_STYLEEXT_CMB_EditJustified;
       break;
-    case XFA_AttributeEnum::JustifyAll:
+    case XFA_AttributeValue::JustifyAll:
       break;
-    case XFA_AttributeEnum::Radix:
+    case XFA_AttributeValue::Radix:
       break;
-    case XFA_AttributeEnum::Right:
+    case XFA_AttributeValue::Right:
       break;
     default:
       dwExtendedStyle |=
@@ -169,10 +183,10 @@
   }
 
   switch (para->GetVerticalAlign()) {
-    case XFA_AttributeEnum::Middle:
+    case XFA_AttributeValue::Middle:
       dwExtendedStyle |= FWL_STYLEEXT_CMB_EditVCenter;
       break;
-    case XFA_AttributeEnum::Bottom:
+    case XFA_AttributeValue::Bottom:
       dwExtendedStyle |= FWL_STYLEEXT_CMB_EditVFar;
       break;
     default:
@@ -183,87 +197,88 @@
 }
 
 bool CXFA_FFComboBox::UpdateFWLData() {
-  auto* pComboBox = ToComboBox(m_pNormalWidget.get());
+  auto* pComboBox = ToComboBox(GetNormalWidget());
   if (!pComboBox)
     return false;
 
-  std::vector<int32_t> iSelArray = m_pNode->GetWidgetAcc()->GetSelectedItems();
+  std::vector<int32_t> iSelArray = m_pNode->GetSelectedItems();
   if (!iSelArray.empty()) {
     pComboBox->SetCurSel(iSelArray.front());
   } else {
     pComboBox->SetCurSel(-1);
-    pComboBox->SetEditText(
-        m_pNode->GetWidgetAcc()->GetValue(XFA_VALUEPICTURE_Raw));
+    pComboBox->SetEditText(m_pNode->GetValue(XFA_VALUEPICTURE_Raw));
   }
   pComboBox->Update();
   return true;
 }
 
 bool CXFA_FFComboBox::CanUndo() {
-  return m_pNode->GetWidgetAcc()->IsChoiceListAllowTextEntry() &&
-         ToComboBox(m_pNormalWidget.get())->EditCanUndo();
+  return m_pNode->IsChoiceListAllowTextEntry() &&
+         ToComboBox(GetNormalWidget())->EditCanUndo();
 }
 
 bool CXFA_FFComboBox::CanRedo() {
-  return m_pNode->GetWidgetAcc()->IsChoiceListAllowTextEntry() &&
-         ToComboBox(m_pNormalWidget.get())->EditCanRedo();
+  return m_pNode->IsChoiceListAllowTextEntry() &&
+         ToComboBox(GetNormalWidget())->EditCanRedo();
 }
 
 bool CXFA_FFComboBox::Undo() {
-  return m_pNode->GetWidgetAcc()->IsChoiceListAllowTextEntry() &&
-         ToComboBox(m_pNormalWidget.get())->EditUndo();
+  return m_pNode->IsChoiceListAllowTextEntry() &&
+         ToComboBox(GetNormalWidget())->EditUndo();
 }
 
 bool CXFA_FFComboBox::Redo() {
-  return m_pNode->GetWidgetAcc()->IsChoiceListAllowTextEntry() &&
-         ToComboBox(m_pNormalWidget.get())->EditRedo();
+  return m_pNode->IsChoiceListAllowTextEntry() &&
+         ToComboBox(GetNormalWidget())->EditRedo();
 }
 
 bool CXFA_FFComboBox::CanCopy() {
-  return ToComboBox(m_pNormalWidget.get())->EditCanCopy();
+  return ToComboBox(GetNormalWidget())->EditCanCopy();
 }
 
 bool CXFA_FFComboBox::CanCut() {
-  return m_pNode->IsOpenAccess() &&
-         m_pNode->GetWidgetAcc()->IsChoiceListAllowTextEntry() &&
-         ToComboBox(m_pNormalWidget.get())->EditCanCut();
+  return m_pNode->IsOpenAccess() && m_pNode->IsChoiceListAllowTextEntry() &&
+         ToComboBox(GetNormalWidget())->EditCanCut();
 }
 
 bool CXFA_FFComboBox::CanPaste() {
-  return m_pNode->GetWidgetAcc()->IsChoiceListAllowTextEntry() &&
-         m_pNode->IsOpenAccess();
+  return m_pNode->IsChoiceListAllowTextEntry() && m_pNode->IsOpenAccess();
 }
 
 bool CXFA_FFComboBox::CanSelectAll() {
-  return ToComboBox(m_pNormalWidget.get())->EditCanSelectAll();
+  return ToComboBox(GetNormalWidget())->EditCanSelectAll();
 }
 
 Optional<WideString> CXFA_FFComboBox::Copy() {
-  return ToComboBox(m_pNormalWidget.get())->EditCopy();
+  return ToComboBox(GetNormalWidget())->EditCopy();
 }
 
 Optional<WideString> CXFA_FFComboBox::Cut() {
-  if (!m_pNode->GetWidgetAcc()->IsChoiceListAllowTextEntry())
+  if (!m_pNode->IsChoiceListAllowTextEntry())
     return {};
 
-  return ToComboBox(m_pNormalWidget.get())->EditCut();
+  return ToComboBox(GetNormalWidget())->EditCut();
 }
 
 bool CXFA_FFComboBox::Paste(const WideString& wsPaste) {
-  return m_pNode->GetWidgetAcc()->IsChoiceListAllowTextEntry() &&
-         ToComboBox(m_pNormalWidget.get())->EditPaste(wsPaste);
+  return m_pNode->IsChoiceListAllowTextEntry() &&
+         ToComboBox(GetNormalWidget())->EditPaste(wsPaste);
 }
 
 void CXFA_FFComboBox::SelectAll() {
-  ToComboBox(m_pNormalWidget.get())->EditSelectAll();
+  ToComboBox(GetNormalWidget())->EditSelectAll();
 }
 
 void CXFA_FFComboBox::Delete() {
-  ToComboBox(m_pNormalWidget.get())->EditDelete();
+  ToComboBox(GetNormalWidget())->EditDelete();
 }
 
 void CXFA_FFComboBox::DeSelect() {
-  ToComboBox(m_pNormalWidget.get())->EditDeSelect();
+  ToComboBox(GetNormalWidget())->EditDeSelect();
+}
+
+WideString CXFA_FFComboBox::GetText() {
+  return GetCurrentText();
 }
 
 FormFieldType CXFA_FFComboBox::GetFormFieldType() {
@@ -271,56 +286,59 @@
 }
 
 void CXFA_FFComboBox::SetItemState(int32_t nIndex, bool bSelected) {
-  ToComboBox(m_pNormalWidget.get())->SetCurSel(bSelected ? nIndex : -1);
-  m_pNormalWidget->Update();
-  AddInvalidateRect();
+  ToComboBox(GetNormalWidget())->SetCurSel(bSelected ? nIndex : -1);
+  GetNormalWidget()->Update();
+  InvalidateRect();
 }
 
-void CXFA_FFComboBox::InsertItem(const WideStringView& wsLabel,
-                                 int32_t nIndex) {
-  ToComboBox(m_pNormalWidget.get())->AddString(wsLabel);
-  m_pNormalWidget->Update();
-  AddInvalidateRect();
+void CXFA_FFComboBox::InsertItem(const WideString& wsLabel, int32_t nIndex) {
+  ToComboBox(GetNormalWidget())->AddString(wsLabel);
+  GetNormalWidget()->Update();
+  InvalidateRect();
 }
 
 void CXFA_FFComboBox::DeleteItem(int32_t nIndex) {
   if (nIndex < 0)
-    ToComboBox(m_pNormalWidget.get())->RemoveAll();
+    ToComboBox(GetNormalWidget())->RemoveAll();
   else
-    ToComboBox(m_pNormalWidget.get())->RemoveAt(nIndex);
+    ToComboBox(GetNormalWidget())->RemoveAt(nIndex);
 
-  m_pNormalWidget->Update();
-  AddInvalidateRect();
+  GetNormalWidget()->Update();
+  InvalidateRect();
 }
 
 void CXFA_FFComboBox::OnTextChanged(CFWL_Widget* pWidget,
                                     const WideString& wsChanged) {
   CXFA_EventParam eParam;
-  eParam.m_wsPrevText = m_pNode->GetWidgetAcc()->GetValue(XFA_VALUEPICTURE_Raw);
+  eParam.m_wsPrevText = m_pNode->GetValue(XFA_VALUEPICTURE_Raw);
   eParam.m_wsChange = wsChanged;
   FWLEventSelChange(&eParam);
 }
 
 void CXFA_FFComboBox::OnSelectChanged(CFWL_Widget* pWidget, bool bLButtonUp) {
+  ObservedPtr<CXFA_FFComboBox> watched(this);
   CXFA_EventParam eParam;
-  eParam.m_wsPrevText = m_pNode->GetWidgetAcc()->GetValue(XFA_VALUEPICTURE_Raw);
+  eParam.m_wsPrevText = m_pNode->GetValue(XFA_VALUEPICTURE_Raw);
   FWLEventSelChange(&eParam);
-  if (m_pNode->GetWidgetAcc()->IsChoiceListCommitOnSelect() && bLButtonUp)
-    m_pDocView->SetFocusWidgetAcc(nullptr);
+  if (!watched)
+    return;
+
+  if (m_pNode->IsChoiceListCommitOnSelect() && bLButtonUp)
+    m_pDocView->SetFocusNode(nullptr);
 }
 
 void CXFA_FFComboBox::OnPreOpen(CFWL_Widget* pWidget) {
   CXFA_EventParam eParam;
   eParam.m_eType = XFA_EVENT_PreOpen;
-  eParam.m_pTarget = m_pNode->GetWidgetAcc();
-  m_pNode->ProcessEvent(GetDocView(), XFA_AttributeEnum::PreOpen, &eParam);
+  eParam.m_pTarget = m_pNode.Get();
+  m_pNode->ProcessEvent(GetDocView(), XFA_AttributeValue::PreOpen, &eParam);
 }
 
 void CXFA_FFComboBox::OnPostOpen(CFWL_Widget* pWidget) {
   CXFA_EventParam eParam;
   eParam.m_eType = XFA_EVENT_PostOpen;
-  eParam.m_pTarget = m_pNode->GetWidgetAcc();
-  m_pNode->ProcessEvent(GetDocView(), XFA_AttributeEnum::PostOpen, &eParam);
+  eParam.m_pTarget = m_pNode.Get();
+  m_pNode->ProcessEvent(GetDocView(), XFA_AttributeValue::PostOpen, &eParam);
 }
 
 void CXFA_FFComboBox::OnProcessMessage(CFWL_Message* pMessage) {
@@ -328,30 +346,32 @@
 }
 
 void CXFA_FFComboBox::OnProcessEvent(CFWL_Event* pEvent) {
+  ObservedPtr<CXFA_FFComboBox> watched(this);
   CXFA_FFField::OnProcessEvent(pEvent);
   switch (pEvent->GetType()) {
     case CFWL_Event::Type::SelectChanged: {
       auto* postEvent = static_cast<CFWL_EventSelectChanged*>(pEvent);
-      OnSelectChanged(m_pNormalWidget.get(), postEvent->bLButtonUp);
+      OnSelectChanged(GetNormalWidget(), postEvent->bLButtonUp);
       break;
     }
     case CFWL_Event::Type::EditChanged: {
       WideString wsChanged;
-      OnTextChanged(m_pNormalWidget.get(), wsChanged);
+      OnTextChanged(GetNormalWidget(), wsChanged);
       break;
     }
     case CFWL_Event::Type::PreDropDown: {
-      OnPreOpen(m_pNormalWidget.get());
+      OnPreOpen(GetNormalWidget());
       break;
     }
     case CFWL_Event::Type::PostDropDown: {
-      OnPostOpen(m_pNormalWidget.get());
+      OnPostOpen(GetNormalWidget());
       break;
     }
     default:
       break;
   }
-  m_pOldDelegate->OnProcessEvent(pEvent);
+  if (watched)
+    m_pOldDelegate->OnProcessEvent(pEvent);
 }
 
 void CXFA_FFComboBox::OnDrawWidget(CXFA_Graphics* pGraphics,
diff --git a/xfa/fxfa/cxfa_ffcombobox.h b/xfa/fxfa/cxfa_ffcombobox.h
index a20319e..3813b6e 100644
--- a/xfa/fxfa/cxfa_ffcombobox.h
+++ b/xfa/fxfa/cxfa_ffcombobox.h
@@ -7,19 +7,25 @@
 #ifndef XFA_FXFA_CXFA_FFCOMBOBOX_H_
 #define XFA_FXFA_CXFA_FFCOMBOBOX_H_
 
-#include "xfa/fxfa/cxfa_fffield.h"
+#include "core/fxcrt/unowned_ptr.h"
+#include "xfa/fxfa/cxfa_ffdropdown.h"
 
-class CXFA_FFComboBox : public CXFA_FFField {
+class CXFA_EventParam;
+
+class CXFA_FFComboBox final : public CXFA_FFDropDown {
  public:
   explicit CXFA_FFComboBox(CXFA_Node* pNode);
   ~CXFA_FFComboBox() override;
 
+  // CXFA_FFDropDown:
+  CXFA_FFComboBox* AsComboBox() override;
+
   // CXFA_FFField
-  CFX_RectF GetBBox(uint32_t dwStatus, bool bDrawFocus = false) override;
+  CFX_RectF GetBBox(FocusOption focus) override;
   bool LoadWidget() override;
   void UpdateWidgetProperty() override;
   bool OnRButtonUp(uint32_t dwFlags, const CFX_PointF& point) override;
-  bool OnKillFocus(CXFA_FFWidget* pNewWidget) override;
+  bool OnKillFocus(CXFA_FFWidget* pNewWidget) override WARN_UNUSED_RESULT;
   bool CanUndo() override;
   bool CanRedo() override;
   bool Undo() override;
@@ -35,6 +41,7 @@
   void SelectAll() override;
   void Delete() override;
   void DeSelect() override;
+  WideString GetText() override;
   FormFieldType GetFormFieldType() override;
 
   // IFWL_WidgetDelegate
@@ -43,18 +50,20 @@
   void OnDrawWidget(CXFA_Graphics* pGraphics,
                     const CFX_Matrix& matrix) override;
 
-  virtual void OpenDropDownList();
+  // CXFA_FFDropDown
+  void InsertItem(const WideString& wsLabel, int32_t nIndex) override;
+  void DeleteItem(int32_t nIndex) override;
+
+  void OpenDropDownList();
 
   void OnTextChanged(CFWL_Widget* pWidget, const WideString& wsChanged);
   void OnSelectChanged(CFWL_Widget* pWidget, bool bLButtonUp);
   void OnPreOpen(CFWL_Widget* pWidget);
   void OnPostOpen(CFWL_Widget* pWidget);
   void SetItemState(int32_t nIndex, bool bSelected);
-  void InsertItem(const WideStringView& wsLabel, int32_t nIndex);
-  void DeleteItem(int32_t nIndex);
 
  private:
-  // CXFA_FFField
+  // CXFA_FFField:
   bool PtInActiveRect(const CFX_PointF& point) override;
   bool CommitData() override;
   bool UpdateFWLData() override;
@@ -62,9 +71,10 @@
 
   uint32_t GetAlignment();
   void FWLEventSelChange(CXFA_EventParam* pParam);
+  WideString GetCurrentText() const;
 
   WideString m_wsNewValue;
-  IFWL_WidgetDelegate* m_pOldDelegate;
+  UnownedPtr<IFWL_WidgetDelegate> m_pOldDelegate;
 };
 
 #endif  // XFA_FXFA_CXFA_FFCOMBOBOX_H_
diff --git a/xfa/fxfa/cxfa_ffdatetimeedit.cpp b/xfa/fxfa/cxfa_ffdatetimeedit.cpp
index d6bd096..d8d57f5 100644
--- a/xfa/fxfa/cxfa_ffdatetimeedit.cpp
+++ b/xfa/fxfa/cxfa_ffdatetimeedit.cpp
@@ -8,12 +8,14 @@
 
 #include <utility>
 
+#include "third_party/base/ptr_util.h"
 #include "xfa/fwl/cfwl_datetimepicker.h"
 #include "xfa/fwl/cfwl_eventselectchanged.h"
 #include "xfa/fwl/cfwl_notedriver.h"
 #include "xfa/fwl/cfwl_widget.h"
 #include "xfa/fxfa/cxfa_eventparam.h"
 #include "xfa/fxfa/cxfa_ffdoc.h"
+#include "xfa/fxfa/cxfa_ffdocview.h"
 #include "xfa/fxfa/parser/cxfa_localevalue.h"
 #include "xfa/fxfa/parser/cxfa_para.h"
 #include "xfa/fxfa/parser/cxfa_value.h"
@@ -22,80 +24,84 @@
 CXFA_FFDateTimeEdit::CXFA_FFDateTimeEdit(CXFA_Node* pNode)
     : CXFA_FFTextEdit(pNode) {}
 
-CXFA_FFDateTimeEdit::~CXFA_FFDateTimeEdit() {}
+CXFA_FFDateTimeEdit::~CXFA_FFDateTimeEdit() = default;
 
-CFX_RectF CXFA_FFDateTimeEdit::GetBBox(uint32_t dwStatus, bool bDrawFocus) {
-  if (bDrawFocus)
+CFWL_DateTimePicker* CXFA_FFDateTimeEdit::GetPickerWidget() {
+  return static_cast<CFWL_DateTimePicker*>(GetNormalWidget());
+}
+
+CFX_RectF CXFA_FFDateTimeEdit::GetBBox(FocusOption focus) {
+  if (focus == kDrawFocus)
     return CFX_RectF();
-  return CXFA_FFWidget::GetBBox(dwStatus);
+  return CXFA_FFWidget::GetBBox(kDoNotDrawFocus);
 }
 
 bool CXFA_FFDateTimeEdit::PtInActiveRect(const CFX_PointF& point) {
-  auto* pPicker = static_cast<CFWL_DateTimePicker*>(m_pNormalWidget.get());
+  CFWL_DateTimePicker* pPicker = GetPickerWidget();
   return pPicker && pPicker->GetBBox().Contains(point);
 }
 
 bool CXFA_FFDateTimeEdit::LoadWidget() {
+  ASSERT(!IsLoaded());
   auto pNewPicker = pdfium::MakeUnique<CFWL_DateTimePicker>(GetFWLApp());
   CFWL_DateTimePicker* pWidget = pNewPicker.get();
-  m_pNormalWidget = std::move(pNewPicker);
-  m_pNormalWidget->SetLayoutItem(this);
+  SetNormalWidget(std::move(pNewPicker));
+  pWidget->SetAdapterIface(this);
 
-  CFWL_NoteDriver* pNoteDriver =
-      m_pNormalWidget->GetOwnerApp()->GetNoteDriver();
-  pNoteDriver->RegisterEventTarget(m_pNormalWidget.get(),
-                                   m_pNormalWidget.get());
-  m_pOldDelegate = m_pNormalWidget->GetDelegate();
-  m_pNormalWidget->SetDelegate(this);
-  m_pNormalWidget->LockUpdate();
+  CFWL_NoteDriver* pNoteDriver = pWidget->GetOwnerApp()->GetNoteDriver();
+  pNoteDriver->RegisterEventTarget(pWidget, pWidget);
+  m_pOldDelegate = pWidget->GetDelegate();
+  pWidget->SetDelegate(this);
 
-  WideString wsText =
-      m_pNode->GetWidgetAcc()->GetValue(XFA_VALUEPICTURE_Display);
-  pWidget->SetEditText(wsText);
+  {
+    CFWL_Widget::ScopedUpdateLock update_lock(pWidget);
+    WideString wsText = m_pNode->GetValue(XFA_VALUEPICTURE_Display);
+    pWidget->SetEditText(wsText);
 
-  CXFA_Value* value = m_pNode->GetFormValueIfExists();
-  if (value) {
-    switch (value->GetChildValueClassID()) {
-      case XFA_Element::Date: {
-        if (!wsText.IsEmpty()) {
-          CXFA_LocaleValue lcValue = XFA_GetLocaleValue(m_pNode.Get());
-          CFX_DateTime date = lcValue.GetDate();
-          if (date.IsSet())
-            pWidget->SetCurSel(date.GetYear(), date.GetMonth(), date.GetDay());
-        }
-      } break;
-      default:
-        break;
+    CXFA_Value* value = m_pNode->GetFormValueIfExists();
+    if (value) {
+      switch (value->GetChildValueClassID()) {
+        case XFA_Element::Date: {
+          if (!wsText.IsEmpty()) {
+            CXFA_LocaleValue lcValue = XFA_GetLocaleValue(m_pNode.Get());
+            CFX_DateTime date = lcValue.GetDate();
+            if (date.IsSet())
+              pWidget->SetCurSel(date.GetYear(), date.GetMonth(),
+                                 date.GetDay());
+          }
+        } break;
+        default:
+          break;
+      }
     }
+    UpdateWidgetProperty();
   }
-  UpdateWidgetProperty();
-  m_pNormalWidget->UnlockUpdate();
+
   return CXFA_FFField::LoadWidget();
 }
 
 void CXFA_FFDateTimeEdit::UpdateWidgetProperty() {
-  CFWL_DateTimePicker* pWidget =
-      static_cast<CFWL_DateTimePicker*>(m_pNormalWidget.get());
-  if (!pWidget)
+  CFWL_DateTimePicker* pPicker = GetPickerWidget();
+  if (!pPicker)
     return;
 
   uint32_t dwExtendedStyle = FWL_STYLEEXT_DTP_ShortDateFormat;
   dwExtendedStyle |= UpdateUIProperty();
   dwExtendedStyle |= GetAlignment();
-  m_pNormalWidget->ModifyStylesEx(dwExtendedStyle, 0xFFFFFFFF);
+  GetNormalWidget()->ModifyStylesEx(dwExtendedStyle, 0xFFFFFFFF);
 
   uint32_t dwEditStyles = 0;
-  Optional<int32_t> numCells = m_pNode->GetWidgetAcc()->GetNumberOfCells();
+  Optional<int32_t> numCells = m_pNode->GetNumberOfCells();
   if (numCells && *numCells > 0) {
     dwEditStyles |= FWL_STYLEEXT_EDT_CombText;
-    pWidget->SetEditLimit(*numCells);
+    pPicker->SetEditLimit(*numCells);
   }
   if (!m_pNode->IsOpenAccess() || !GetDoc()->GetXFADoc()->IsInteractive())
     dwEditStyles |= FWL_STYLEEXT_EDT_ReadOnly;
-  if (!m_pNode->GetWidgetAcc()->IsHorizontalScrollPolicyOff())
+  if (!m_pNode->IsHorizontalScrollPolicyOff())
     dwEditStyles |= FWL_STYLEEXT_EDT_AutoHScroll;
 
-  pWidget->ModifyEditStylesEx(dwEditStyles, 0xFFFFFFFF);
+  pPicker->ModifyEditStylesEx(dwEditStyles, 0xFFFFFFFF);
 }
 
 uint32_t CXFA_FFDateTimeEdit::GetAlignment() {
@@ -105,16 +111,16 @@
 
   uint32_t dwExtendedStyle = 0;
   switch (para->GetHorizontalAlign()) {
-    case XFA_AttributeEnum::Center:
+    case XFA_AttributeValue::Center:
       dwExtendedStyle |= FWL_STYLEEXT_DTP_EditHCenter;
       break;
-    case XFA_AttributeEnum::Justify:
+    case XFA_AttributeValue::Justify:
       dwExtendedStyle |= FWL_STYLEEXT_DTP_EditJustified;
       break;
-    case XFA_AttributeEnum::JustifyAll:
-    case XFA_AttributeEnum::Radix:
+    case XFA_AttributeValue::JustifyAll:
+    case XFA_AttributeValue::Radix:
       break;
-    case XFA_AttributeEnum::Right:
+    case XFA_AttributeValue::Right:
       dwExtendedStyle |= FWL_STYLEEXT_DTP_EditHFar;
       break;
     default:
@@ -123,10 +129,10 @@
   }
 
   switch (para->GetVerticalAlign()) {
-    case XFA_AttributeEnum::Middle:
+    case XFA_AttributeValue::Middle:
       dwExtendedStyle |= FWL_STYLEEXT_DTP_EditVCenter;
       break;
-    case XFA_AttributeEnum::Bottom:
+    case XFA_AttributeValue::Bottom:
       dwExtendedStyle |= FWL_STYLEEXT_DTP_EditVFar;
       break;
     default:
@@ -137,80 +143,138 @@
 }
 
 bool CXFA_FFDateTimeEdit::CommitData() {
-  auto* pPicker = static_cast<CFWL_DateTimePicker*>(m_pNormalWidget.get());
-  if (!m_pNode->GetWidgetAcc()->SetValue(XFA_VALUEPICTURE_Edit,
-                                         pPicker->GetEditText())) {
+  CFWL_DateTimePicker* pPicker = GetPickerWidget();
+  if (!m_pNode->SetValue(XFA_VALUEPICTURE_Edit, pPicker->GetEditText()))
     return false;
-  }
 
-  m_pNode->GetWidgetAcc()->UpdateUIDisplay(GetDoc()->GetDocView(), this);
+  GetDoc()->GetDocView()->UpdateUIDisplay(m_pNode.Get(), this);
   return true;
 }
 
 bool CXFA_FFDateTimeEdit::UpdateFWLData() {
-  if (!m_pNormalWidget)
+  if (!GetNormalWidget())
     return false;
 
   XFA_VALUEPICTURE eType = XFA_VALUEPICTURE_Display;
   if (IsFocused())
     eType = XFA_VALUEPICTURE_Edit;
 
-  WideString wsText = m_pNode->GetWidgetAcc()->GetValue(eType);
-  auto* normalWidget = static_cast<CFWL_DateTimePicker*>(m_pNormalWidget.get());
-  normalWidget->SetEditText(wsText);
+  WideString wsText = m_pNode->GetValue(eType);
+  CFWL_DateTimePicker* pPicker = GetPickerWidget();
+  pPicker->SetEditText(wsText);
   if (IsFocused() && !wsText.IsEmpty()) {
     CXFA_LocaleValue lcValue = XFA_GetLocaleValue(m_pNode.Get());
     CFX_DateTime date = lcValue.GetDate();
     if (lcValue.IsValid()) {
       if (date.IsSet())
-        normalWidget->SetCurSel(date.GetYear(), date.GetMonth(), date.GetDay());
+        pPicker->SetCurSel(date.GetYear(), date.GetMonth(), date.GetDay());
     }
   }
-  m_pNormalWidget->Update();
+  GetNormalWidget()->Update();
   return true;
 }
 
 bool CXFA_FFDateTimeEdit::IsDataChanged() {
-  if (m_dwStatus & XFA_WidgetStatus_TextEditValueChanged)
+  if (GetLayoutItem()->TestStatusBits(XFA_WidgetStatus_TextEditValueChanged))
     return true;
 
-  WideString wsText =
-      static_cast<CFWL_DateTimePicker*>(m_pNormalWidget.get())->GetEditText();
-  return m_pNode->GetWidgetAcc()->GetValue(XFA_VALUEPICTURE_Edit) != wsText;
+  WideString wsText = GetPickerWidget()->GetEditText();
+  return m_pNode->GetValue(XFA_VALUEPICTURE_Edit) != wsText;
 }
 
 void CXFA_FFDateTimeEdit::OnSelectChanged(CFWL_Widget* pWidget,
                                           int32_t iYear,
                                           int32_t iMonth,
                                           int32_t iDay) {
-  WideString wsPicture =
-      m_pNode->GetWidgetAcc()->GetPictureContent(XFA_VALUEPICTURE_Edit);
+  WideString wsPicture = m_pNode->GetPictureContent(XFA_VALUEPICTURE_Edit);
 
-  CXFA_LocaleValue date(XFA_VT_DATE, GetDoc()->GetXFADoc()->GetLocalMgr());
+  CXFA_LocaleValue date(XFA_VT_DATE, GetDoc()->GetXFADoc()->GetLocaleMgr());
   date.SetDate(CFX_DateTime(iYear, iMonth, iDay, 0, 0, 0, 0));
 
   WideString wsDate;
   date.FormatPatterns(wsDate, wsPicture, m_pNode->GetLocale(),
                       XFA_VALUEPICTURE_Edit);
 
-  auto* pDateTime = static_cast<CFWL_DateTimePicker*>(m_pNormalWidget.get());
-  pDateTime->SetEditText(wsDate);
-  pDateTime->Update();
+  CFWL_DateTimePicker* pPicker = GetPickerWidget();
+  pPicker->SetEditText(wsDate);
+  pPicker->Update();
   GetDoc()->GetDocEnvironment()->SetFocusWidget(GetDoc(), nullptr);
 
   CXFA_EventParam eParam;
   eParam.m_eType = XFA_EVENT_Change;
-  eParam.m_pTarget = m_pNode->GetWidgetAcc();
-  eParam.m_wsNewText = m_pNode->GetWidgetAcc()->GetValue(XFA_VALUEPICTURE_Raw);
-  m_pNode->ProcessEvent(GetDocView(), XFA_AttributeEnum::Change, &eParam);
+  eParam.m_pTarget = m_pNode.Get();
+  eParam.m_wsPrevText = m_pNode->GetValue(XFA_VALUEPICTURE_Raw);
+  m_pNode->ProcessEvent(GetDocView(), XFA_AttributeValue::Change, &eParam);
 }
 
 void CXFA_FFDateTimeEdit::OnProcessEvent(CFWL_Event* pEvent) {
   if (pEvent->GetType() == CFWL_Event::Type::SelectChanged) {
     auto* event = static_cast<CFWL_EventSelectChanged*>(pEvent);
-    OnSelectChanged(m_pNormalWidget.get(), event->iYear, event->iMonth,
+    OnSelectChanged(GetNormalWidget(), event->iYear, event->iMonth,
                     event->iDay);
     return;
   }
   CXFA_FFTextEdit::OnProcessEvent(pEvent);
 }
+
+bool CXFA_FFDateTimeEdit::CanUndo() {
+  return GetPickerWidget()->CanUndo();
+}
+
+bool CXFA_FFDateTimeEdit::CanRedo() {
+  return GetPickerWidget()->CanRedo();
+}
+
+bool CXFA_FFDateTimeEdit::Undo() {
+  return GetPickerWidget()->Undo();
+}
+
+bool CXFA_FFDateTimeEdit::Redo() {
+  return GetPickerWidget()->Redo();
+}
+
+bool CXFA_FFDateTimeEdit::CanCopy() {
+  return GetPickerWidget()->HasSelection();
+}
+
+bool CXFA_FFDateTimeEdit::CanCut() {
+  if (GetPickerWidget()->GetStylesEx() & FWL_STYLEEXT_EDT_ReadOnly)
+    return false;
+  return GetPickerWidget()->HasSelection();
+}
+
+bool CXFA_FFDateTimeEdit::CanPaste() {
+  return !(GetPickerWidget()->GetStylesEx() & FWL_STYLEEXT_EDT_ReadOnly);
+}
+
+bool CXFA_FFDateTimeEdit::CanSelectAll() {
+  return GetPickerWidget()->GetEditTextLength() > 0;
+}
+
+Optional<WideString> CXFA_FFDateTimeEdit::Copy() {
+  return GetPickerWidget()->Copy();
+}
+
+Optional<WideString> CXFA_FFDateTimeEdit::Cut() {
+  return GetPickerWidget()->Cut();
+}
+
+bool CXFA_FFDateTimeEdit::Paste(const WideString& wsPaste) {
+  return GetPickerWidget()->Paste(wsPaste);
+}
+
+void CXFA_FFDateTimeEdit::SelectAll() {
+  GetPickerWidget()->SelectAll();
+}
+
+void CXFA_FFDateTimeEdit::Delete() {
+  GetPickerWidget()->ClearText();
+}
+
+void CXFA_FFDateTimeEdit::DeSelect() {
+  GetPickerWidget()->ClearSelection();
+}
+
+WideString CXFA_FFDateTimeEdit::GetText() {
+  return GetPickerWidget()->GetEditText();
+}
diff --git a/xfa/fxfa/cxfa_ffdatetimeedit.h b/xfa/fxfa/cxfa_ffdatetimeedit.h
index a549cbb..5ba6867 100644
--- a/xfa/fxfa/cxfa_ffdatetimeedit.h
+++ b/xfa/fxfa/cxfa_ffdatetimeedit.h
@@ -16,16 +16,17 @@
   XFA_DATETIMETYPE_DateAndTime
 };
 
+class CFWL_DateTimePicker;
 class CFWL_Event;
 class CFWL_Widget;
 
-class CXFA_FFDateTimeEdit : public CXFA_FFTextEdit {
+class CXFA_FFDateTimeEdit final : public CXFA_FFTextEdit {
  public:
   explicit CXFA_FFDateTimeEdit(CXFA_Node* pNode);
   ~CXFA_FFDateTimeEdit() override;
 
   // CXFA_FFTextEdit
-  CFX_RectF GetBBox(uint32_t dwStatus, bool bDrawFocus = false) override;
+  CFX_RectF GetBBox(FocusOption focus) override;
   bool LoadWidget() override;
   void UpdateWidgetProperty() override;
   void OnProcessEvent(CFWL_Event* pEvent) override;
@@ -35,12 +36,31 @@
                        int32_t iMonth,
                        int32_t iDay);
 
+  // CXFA_FFWidget
+  bool CanUndo() override;
+  bool CanRedo() override;
+  bool Undo() override;
+  bool Redo() override;
+  bool CanCopy() override;
+  bool CanCut() override;
+  bool CanPaste() override;
+  bool CanSelectAll() override;
+  Optional<WideString> Copy() override;
+  Optional<WideString> Cut() override;
+  bool Paste(const WideString& wsPaste) override;
+  void SelectAll() override;
+  void Delete() override;
+  void DeSelect() override;
+  WideString GetText() override;
+
  private:
   bool PtInActiveRect(const CFX_PointF& point) override;
   bool CommitData() override;
   bool UpdateFWLData() override;
   bool IsDataChanged() override;
 
+  CFWL_DateTimePicker* GetPickerWidget();
+
   uint32_t GetAlignment();
 };
 
diff --git a/xfa/fxfa/cxfa_ffdoc.cpp b/xfa/fxfa/cxfa_ffdoc.cpp
index 4dfa78e..ac4b35f 100644
--- a/xfa/fxfa/cxfa_ffdoc.cpp
+++ b/xfa/fxfa/cxfa_ffdoc.cpp
@@ -10,264 +10,107 @@
 #include <memory>
 #include <vector>
 
-#include "core/fpdfapi/parser/cpdf_array.h"
+#include "core/fpdfapi/parser/cpdf_dictionary.h"
 #include "core/fpdfapi/parser/cpdf_document.h"
-#include "core/fpdfapi/parser/fpdf_parser_decode.h"
+#include "core/fpdfapi/parser/cpdf_stream.h"
+#include "core/fpdfapi/parser/cpdf_stream_acc.h"
 #include "core/fpdfdoc/cpdf_nametree.h"
-#include "core/fxcrt/cfx_checksumcontext.h"
-#include "core/fxcrt/cfx_memorystream.h"
-#include "core/fxcrt/cfx_seekablemultistream.h"
+#include "core/fxcrt/cfx_readonlymemorystream.h"
 #include "core/fxcrt/fx_extension.h"
-#include "core/fxcrt/fx_memory.h"
+#include "core/fxcrt/xml/cfx_xmldocument.h"
 #include "core/fxcrt/xml/cfx_xmlelement.h"
 #include "core/fxcrt/xml/cfx_xmlnode.h"
+#include "core/fxge/dib/cfx_dibitmap.h"
 #include "fxjs/xfa/cjx_object.h"
 #include "third_party/base/ptr_util.h"
+#include "xfa/fgas/font/cfgas_pdffontmgr.h"
 #include "xfa/fwl/cfwl_notedriver.h"
 #include "xfa/fxfa/cxfa_ffapp.h"
 #include "xfa/fxfa/cxfa_ffdocview.h"
 #include "xfa/fxfa/cxfa_ffnotify.h"
 #include "xfa/fxfa/cxfa_ffwidget.h"
 #include "xfa/fxfa/cxfa_fontmgr.h"
+#include "xfa/fxfa/layout/cxfa_layoutprocessor.h"
 #include "xfa/fxfa/parser/cxfa_acrobat.h"
 #include "xfa/fxfa/parser/cxfa_acrobat7.h"
 #include "xfa/fxfa/parser/cxfa_dataexporter.h"
-#include "xfa/fxfa/parser/cxfa_dataimporter.h"
 #include "xfa/fxfa/parser/cxfa_document.h"
+#include "xfa/fxfa/parser/cxfa_document_parser.h"
 #include "xfa/fxfa/parser/cxfa_dynamicrender.h"
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-namespace {
+FX_IMAGEDIB_AND_DPI::FX_IMAGEDIB_AND_DPI() = default;
+FX_IMAGEDIB_AND_DPI::FX_IMAGEDIB_AND_DPI(const FX_IMAGEDIB_AND_DPI& that) =
+    default;
 
-struct FX_BASE64DATA {
-  uint32_t data1 : 2;
-  uint32_t data2 : 6;
-  uint32_t data3 : 4;
-  uint32_t data4 : 4;
-  uint32_t data5 : 6;
-  uint32_t data6 : 2;
-  uint32_t data7 : 8;
-};
+FX_IMAGEDIB_AND_DPI::FX_IMAGEDIB_AND_DPI(const RetainPtr<CFX_DIBBase>& pDib,
+                                         int32_t xDpi,
+                                         int32_t yDpi)
+    : pDibSource(pDib), iImageXDpi(xDpi), iImageYDpi(yDpi) {}
 
-const uint8_t kStartValuesRemoved = 43;
-const uint8_t kDecoderMapSize = 80;
-const uint8_t g_FXBase64DecoderMap[kDecoderMapSize] = {
-    0x3E, 0xFF, 0xFF, 0xFF, 0x3F, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A,
-    0x3B, 0x3C, 0x3D, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x01,
-    0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D,
-    0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19,
-    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
-    0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B,
-    0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33,
-};
+FX_IMAGEDIB_AND_DPI::~FX_IMAGEDIB_AND_DPI() = default;
 
-uint8_t base64DecoderValue(uint8_t val) {
-  if (val < kStartValuesRemoved || val >= kStartValuesRemoved + kDecoderMapSize)
-    return 0xFF;
-  return g_FXBase64DecoderMap[val - kStartValuesRemoved];
+// static
+std::unique_ptr<CXFA_FFDoc> CXFA_FFDoc::CreateAndOpen(
+    CXFA_FFApp* pApp,
+    IXFA_DocEnvironment* pDocEnvironment,
+    CPDF_Document* pPDFDoc,
+    const RetainPtr<IFX_SeekableStream>& stream) {
+  ASSERT(pApp);
+  ASSERT(pDocEnvironment);
+  ASSERT(pPDFDoc);
+
+  // Use WrapUnique() to keep constructor private.
+  auto result =
+      pdfium::WrapUnique(new CXFA_FFDoc(pApp, pDocEnvironment, pPDFDoc));
+  if (!result->OpenDoc(stream))
+    return nullptr;
+
+  return result;
 }
 
-void Base64DecodePiece(const char src[4],
-                       int32_t iChars,
-                       FX_BASE64DATA& dst,
-                       int32_t& iBytes) {
-  ASSERT(iChars > 0 && iChars < 5);
-  iBytes = 1;
-  dst.data2 = base64DecoderValue(static_cast<uint8_t>(src[0]));
-  if (iChars > 1) {
-    uint8_t b = base64DecoderValue(static_cast<uint8_t>(src[1]));
-    dst.data1 = b >> 4;
-    dst.data4 = b;
-    if (iChars > 2) {
-      iBytes = 2;
-      b = base64DecoderValue(static_cast<uint8_t>(src[2]));
-      dst.data3 = b >> 2;
-      dst.data6 = b;
-      if (iChars > 3) {
-        iBytes = 3;
-        dst.data5 = base64DecoderValue(static_cast<uint8_t>(src[3]));
-      } else {
-        dst.data5 = 0;
-      }
-    } else {
-      dst.data3 = 0;
-    }
-  } else {
-    dst.data1 = 0;
-  }
-}
-
-int32_t Base64DecodeW(const wchar_t* pSrc, int32_t iSrcLen, uint8_t* pDst) {
-  ASSERT(pSrc);
-  if (iSrcLen < 1) {
-    return 0;
-  }
-  while (iSrcLen > 0 && pSrc[iSrcLen - 1] == '=') {
-    iSrcLen--;
-  }
-  if (iSrcLen < 1) {
-    return 0;
-  }
-  if (!pDst) {
-    int32_t iDstLen = iSrcLen / 4 * 3;
-    iSrcLen %= 4;
-    if (iSrcLen == 1) {
-      iDstLen += 1;
-    } else if (iSrcLen == 2) {
-      iDstLen += 1;
-    } else if (iSrcLen == 3) {
-      iDstLen += 2;
-    }
-    return iDstLen;
-  }
-  char srcData[4];
-  FX_BASE64DATA dstData;
-  int32_t iChars = 4, iBytes;
-  uint8_t* pDstEnd = pDst;
-  while (iSrcLen > 0) {
-    if (iSrcLen > 3) {
-      srcData[0] = (char)*pSrc++;
-      srcData[1] = (char)*pSrc++;
-      srcData[2] = (char)*pSrc++;
-      srcData[3] = (char)*pSrc++;
-      iSrcLen -= 4;
-    } else {
-      *((uint32_t*)&dstData) = 0;
-      *((uint32_t*)srcData) = 0;
-      srcData[0] = (char)*pSrc++;
-      if (iSrcLen > 1) {
-        srcData[1] = (char)*pSrc++;
-      }
-      if (iSrcLen > 2) {
-        srcData[2] = (char)*pSrc++;
-      }
-      iChars = iSrcLen;
-      iSrcLen = 0;
-    }
-    Base64DecodePiece(srcData, iChars, dstData, iBytes);
-    *pDstEnd++ = ((uint8_t*)&dstData)[0];
-    if (iBytes > 1) {
-      *pDstEnd++ = ((uint8_t*)&dstData)[1];
-    }
-    if (iBytes > 2) {
-      *pDstEnd++ = ((uint8_t*)&dstData)[2];
-    }
-  }
-  return pDstEnd - pDst;
-}
-
-}  // namespace
-
-CXFA_FFDoc::CXFA_FFDoc(CXFA_FFApp* pApp, IXFA_DocEnvironment* pDocEnvironment)
-    : m_pDocEnvironment(pDocEnvironment), m_pApp(pApp) {}
+CXFA_FFDoc::CXFA_FFDoc(CXFA_FFApp* pApp,
+                       IXFA_DocEnvironment* pDocEnvironment,
+                       CPDF_Document* pPDFDoc)
+    : m_pDocEnvironment(pDocEnvironment),
+      m_pApp(pApp),
+      m_pPDFDoc(pPDFDoc),
+      m_pNotify(pdfium::MakeUnique<CXFA_FFNotify>(this)),
+      m_pDocument(pdfium::MakeUnique<CXFA_Document>(
+          m_pNotify.get(),
+          pdfium::MakeUnique<CXFA_LayoutProcessor>())) {}
 
 CXFA_FFDoc::~CXFA_FFDoc() {
-  CloseDoc();
+  if (m_DocView) {
+    m_DocView->RunDocClose();
+    m_DocView.reset();
+  }
+  if (m_pDocument)
+    m_pDocument->ClearLayoutData();
+
+  m_pDocument.reset();
+  m_pXMLDoc.reset();
+  m_pNotify.reset();
+  m_pPDFFontMgr.reset();
+  m_HashToDibDpiMap.clear();
+  m_pApp->ClearEventTargets();
 }
 
-int32_t CXFA_FFDoc::StartLoad() {
-  m_pNotify = pdfium::MakeUnique<CXFA_FFNotify>(this);
-  m_pDocumentParser = pdfium::MakeUnique<CXFA_DocumentParser>(m_pNotify.get());
-  return m_pDocumentParser->StartParse(m_pStream, XFA_PacketType::Xdp);
-}
+bool CXFA_FFDoc::ParseDoc(const RetainPtr<IFX_SeekableStream>& stream) {
+  CXFA_DocumentParser parser(m_pDocument.get());
+  bool parsed = parser.Parse(stream, XFA_PacketType::Xdp);
 
-bool XFA_GetPDFContentsFromPDFXML(CFX_XMLNode* pPDFElement,
-                                  uint8_t*& pByteBuffer,
-                                  int32_t& iBufferSize) {
-  CFX_XMLElement* pDocumentElement = nullptr;
-  for (CFX_XMLNode* pXMLNode =
-           pPDFElement->GetNodeItem(CFX_XMLNode::FirstChild);
-       pXMLNode; pXMLNode = pXMLNode->GetNodeItem(CFX_XMLNode::NextSibling)) {
-    if (pXMLNode->GetType() == FX_XMLNODE_Element) {
-      CFX_XMLElement* pXMLElement = static_cast<CFX_XMLElement*>(pXMLNode);
-      WideString wsTagName = pXMLElement->GetName();
-      if (wsTagName == L"document") {
-        pDocumentElement = pXMLElement;
-        break;
-      }
-    }
-  }
-  if (!pDocumentElement) {
+  // We have to set the XML document before we return so that we can clean
+  // up in the OpenDoc method. If we don't, the XMLDocument will get free'd
+  // when this method returns and UnownedPtrs get unhappy.
+  m_pXMLDoc = parser.GetXMLDoc();
+
+  if (!parsed)
     return false;
-  }
-  CFX_XMLElement* pChunkElement = nullptr;
-  for (CFX_XMLNode* pXMLNode =
-           pDocumentElement->GetNodeItem(CFX_XMLNode::FirstChild);
-       pXMLNode; pXMLNode = pXMLNode->GetNodeItem(CFX_XMLNode::NextSibling)) {
-    if (pXMLNode->GetType() == FX_XMLNODE_Element) {
-      CFX_XMLElement* pXMLElement = static_cast<CFX_XMLElement*>(pXMLNode);
-      WideString wsTagName = pXMLElement->GetName();
-      if (wsTagName == L"chunk") {
-        pChunkElement = pXMLElement;
-        break;
-      }
-    }
-  }
-  if (!pChunkElement) {
-    return false;
-  }
-  WideString wsPDFContent = pChunkElement->GetTextData();
-  iBufferSize =
-      Base64DecodeW(wsPDFContent.c_str(), wsPDFContent.GetLength(), nullptr);
-  pByteBuffer = FX_Alloc(uint8_t, iBufferSize + 1);
-  pByteBuffer[iBufferSize] = '0';  // FIXME: I bet this is wrong.
-  Base64DecodeW(wsPDFContent.c_str(), wsPDFContent.GetLength(), pByteBuffer);
+
+  m_pDocument->SetRoot(parser.GetRootNode());
   return true;
 }
-void XFA_XPDPacket_MergeRootNode(CXFA_Node* pOriginRoot, CXFA_Node* pNewRoot) {
-  CXFA_Node* pChildNode = pNewRoot->GetFirstChild();
-  while (pChildNode) {
-    CXFA_Node* pOriginChild =
-        pOriginRoot->GetFirstChildByName(pChildNode->GetNameHash());
-    if (pOriginChild) {
-      pChildNode = pChildNode->GetNextSibling();
-    } else {
-      CXFA_Node* pNextSibling = pChildNode->GetNextSibling();
-      pNewRoot->RemoveChild(pChildNode, true);
-      pOriginRoot->InsertChild(pChildNode, nullptr);
-      pChildNode = pNextSibling;
-      pNextSibling = nullptr;
-    }
-  }
-}
-
-int32_t CXFA_FFDoc::DoLoad() {
-  int32_t iStatus = m_pDocumentParser->DoParse();
-  if (iStatus == XFA_PARSESTATUS_Done && !m_pPDFDoc)
-    return XFA_PARSESTATUS_SyntaxErr;
-  return iStatus;
-}
-
-void CXFA_FFDoc::StopLoad() {
-  m_pPDFFontMgr = pdfium::MakeUnique<CFGAS_PDFFontMgr>(
-      GetPDFDoc(), GetApp()->GetFDEFontMgr());
-
-  m_FormType = FormType::kXFAForeground;
-  CXFA_Node* pConfig = ToNode(
-      m_pDocumentParser->GetDocument()->GetXFAObject(XFA_HASHCODE_Config));
-  if (!pConfig)
-    return;
-
-  CXFA_Acrobat* pAcrobat =
-      pConfig->GetFirstChildByClass<CXFA_Acrobat>(XFA_Element::Acrobat);
-  if (!pAcrobat)
-    return;
-
-  CXFA_Acrobat7* pAcrobat7 =
-      pAcrobat->GetFirstChildByClass<CXFA_Acrobat7>(XFA_Element::Acrobat7);
-  if (!pAcrobat7)
-    return;
-
-  CXFA_DynamicRender* pDynamicRender =
-      pAcrobat7->GetFirstChildByClass<CXFA_DynamicRender>(
-          XFA_Element::DynamicRender);
-  if (!pDynamicRender)
-    return;
-
-  WideString wsType = pDynamicRender->JSObject()->GetContent(false);
-  if (wsType == L"required")
-    m_FormType = FormType::kXFAFull;
-}
 
 CXFA_FFDocView* CXFA_FFDoc::CreateDocView() {
   if (!m_DocView)
@@ -285,64 +128,49 @@
   return m_DocView.get();
 }
 
-bool CXFA_FFDoc::OpenDoc(CPDF_Document* pPDFDoc) {
-  if (!pPDFDoc)
+bool CXFA_FFDoc::OpenDoc(const RetainPtr<IFX_SeekableStream>& stream) {
+  if (!ParseDoc(stream))
     return false;
 
-  const CPDF_Dictionary* pRoot = pPDFDoc->GetRoot();
-  if (!pRoot)
+  CFGAS_FontMgr* mgr = GetApp()->GetFDEFontMgr();
+  if (!mgr)
     return false;
 
-  CPDF_Dictionary* pAcroForm = pRoot->GetDictFor("AcroForm");
-  if (!pAcroForm)
-    return false;
+  // At this point we've got an XFA document and we want to always return
+  // true to signify the load succeeded.
+  m_pPDFFontMgr = pdfium::MakeUnique<CFGAS_PDFFontMgr>(GetPDFDoc(), mgr);
 
-  CPDF_Object* pElementXFA = pAcroForm->GetDirectObjectFor("XFA");
-  if (!pElementXFA)
-    return false;
+  m_FormType = FormType::kXFAForeground;
+  CXFA_Node* pConfig = ToNode(m_pDocument->GetXFAObject(XFA_HASHCODE_Config));
+  if (!pConfig)
+    return true;
 
-  std::vector<CPDF_Stream*> xfaStreams;
-  if (pElementXFA->IsArray()) {
-    CPDF_Array* pXFAArray = (CPDF_Array*)pElementXFA;
-    for (size_t i = 0; i < pXFAArray->GetCount() / 2; i++) {
-      if (CPDF_Stream* pStream = pXFAArray->GetStreamAt(i * 2 + 1))
-        xfaStreams.push_back(pStream);
-    }
-  } else if (pElementXFA->IsStream()) {
-    xfaStreams.push_back((CPDF_Stream*)pElementXFA);
-  }
-  if (xfaStreams.empty())
-    return false;
+  CXFA_Acrobat* pAcrobat =
+      pConfig->GetFirstChildByClass<CXFA_Acrobat>(XFA_Element::Acrobat);
+  if (!pAcrobat)
+    return true;
 
-  m_pPDFDoc = pPDFDoc;
-  m_pStream = pdfium::MakeRetain<CFX_SeekableMultiStream>(xfaStreams);
+  CXFA_Acrobat7* pAcrobat7 =
+      pAcrobat->GetFirstChildByClass<CXFA_Acrobat7>(XFA_Element::Acrobat7);
+  if (!pAcrobat7)
+    return true;
+
+  CXFA_DynamicRender* pDynamicRender =
+      pAcrobat7->GetFirstChildByClass<CXFA_DynamicRender>(
+          XFA_Element::DynamicRender);
+  if (!pDynamicRender)
+    return true;
+
+  WideString wsType = pDynamicRender->JSObject()->GetContent(false);
+  if (wsType.EqualsASCII("required"))
+    m_FormType = FormType::kXFAFull;
+
   return true;
 }
 
-void CXFA_FFDoc::CloseDoc() {
-  if (m_DocView) {
-    m_DocView->RunDocClose();
-    m_DocView.reset();
-  }
-  CXFA_Document* doc =
-      m_pDocumentParser ? m_pDocumentParser->GetDocument() : nullptr;
-  if (doc)
-    doc->ClearLayoutData();
-
-  m_pDocumentParser.reset();
-  m_pNotify.reset();
-  m_pPDFFontMgr.reset();
-  m_HashToDibDpiMap.clear();
-  m_pApp->ClearEventTargets();
-}
-
-RetainPtr<CFX_DIBitmap> CXFA_FFDoc::GetPDFNamedImage(
-    const WideStringView& wsName,
-    int32_t& iImageXDpi,
-    int32_t& iImageYDpi) {
-  if (!m_pPDFDoc)
-    return nullptr;
-
+RetainPtr<CFX_DIBitmap> CXFA_FFDoc::GetPDFNamedImage(WideStringView wsName,
+                                                     int32_t& iImageXDpi,
+                                                     int32_t& iImageYDpi) {
   uint32_t dwHash = FX_HashCode_GetW(wsName, false);
   auto it = m_HashToDibDpiMap.find(dwHash);
   if (it != m_HashToDibDpiMap.end()) {
@@ -351,7 +179,7 @@
     return it->second.pDibSource.As<CFX_DIBitmap>();
   }
 
-  const CPDF_Dictionary* pRoot = m_pPDFDoc->GetRoot();
+  CPDF_Dictionary* pRoot = m_pPDFDoc->GetRoot();
   if (!pRoot)
     return nullptr;
 
@@ -383,9 +211,8 @@
   auto pAcc = pdfium::MakeRetain<CPDF_StreamAcc>(pStream);
   pAcc->LoadAllDataFiltered();
 
-  RetainPtr<IFX_SeekableStream> pImageFileRead =
-      pdfium::MakeRetain<CFX_MemoryStream>(
-          const_cast<uint8_t*>(pAcc->GetData()), pAcc->GetSize(), false);
+  auto pImageFileRead =
+      pdfium::MakeRetain<CFX_ReadOnlyMemoryStream>(pAcc->GetSpan());
 
   RetainPtr<CFX_DIBitmap> pDibSource = XFA_LoadImageFromBuffer(
       pImageFileRead, FXCODEC_IMAGE_UNKNOWN, iImageXDpi, iImageYDpi);
@@ -394,23 +221,9 @@
 }
 
 bool CXFA_FFDoc::SavePackage(CXFA_Node* pNode,
-                             const RetainPtr<IFX_SeekableStream>& pFile,
-                             CFX_ChecksumContext* pCSContext) {
-  auto pExport = pdfium::MakeUnique<CXFA_DataExporter>(GetXFADoc());
-  if (!pNode)
-    return !!pExport->Export(pFile);
+                             const RetainPtr<IFX_SeekableStream>& pFile) {
+  ASSERT(pNode || GetXFADoc()->GetRoot());
 
-  ByteString bsChecksum;
-  if (pCSContext)
-    bsChecksum = pCSContext->GetChecksum();
-
-  return !!pExport->Export(
-      pFile, pNode, 0, bsChecksum.GetLength() ? bsChecksum.c_str() : nullptr);
-}
-
-bool CXFA_FFDoc::ImportData(const RetainPtr<IFX_SeekableStream>& pStream,
-                            bool bXDP) {
-  auto importer =
-      pdfium::MakeUnique<CXFA_DataImporter>(m_pDocumentParser->GetDocument());
-  return importer->ImportData(pStream);
+  CXFA_DataExporter exporter;
+  return exporter.Export(pFile, pNode ? pNode : GetXFADoc()->GetRoot());
 }
diff --git a/xfa/fxfa/cxfa_ffdoc.h b/xfa/fxfa/cxfa_ffdoc.h
index e183568..04d98bc 100644
--- a/xfa/fxfa/cxfa_ffdoc.h
+++ b/xfa/fxfa/cxfa_ffdoc.h
@@ -10,88 +10,82 @@
 #include <map>
 #include <memory>
 
+#include "core/fxcrt/fx_stream.h"
 #include "core/fxcrt/unowned_ptr.h"
 #include "xfa/fxfa/fxfa.h"
 #include "xfa/fxfa/parser/cxfa_document.h"
-#include "xfa/fxfa/parser/cxfa_document_parser.h"
 
 class CFGAS_PDFFontMgr;
 class CFX_ChecksumContext;
+class CFX_DIBBase;
+class CFX_DIBitmap;
+class CFX_XMLDocument;
 class CPDF_Document;
 class CXFA_FFApp;
 class CXFA_FFNotify;
 class CXFA_FFDocView;
+class CXFA_LayoutProcessor;
 
 struct FX_IMAGEDIB_AND_DPI {
   FX_IMAGEDIB_AND_DPI();
   FX_IMAGEDIB_AND_DPI(const FX_IMAGEDIB_AND_DPI& that);
-  FX_IMAGEDIB_AND_DPI(const RetainPtr<CFX_DIBSource>& pDib,
+  FX_IMAGEDIB_AND_DPI(const RetainPtr<CFX_DIBBase>& pDib,
                       int32_t xDpi,
                       int32_t yDpi);
   ~FX_IMAGEDIB_AND_DPI();
 
-  RetainPtr<CFX_DIBSource> pDibSource;
+  RetainPtr<CFX_DIBBase> pDibSource;
   int32_t iImageXDpi;
   int32_t iImageYDpi;
 };
 
-inline FX_IMAGEDIB_AND_DPI::FX_IMAGEDIB_AND_DPI() = default;
-inline FX_IMAGEDIB_AND_DPI::FX_IMAGEDIB_AND_DPI(
-    const FX_IMAGEDIB_AND_DPI& that) = default;
-
-inline FX_IMAGEDIB_AND_DPI::FX_IMAGEDIB_AND_DPI(
-    const RetainPtr<CFX_DIBSource>& pDib,
-    int32_t xDpi,
-    int32_t yDpi)
-    : pDibSource(pDib), iImageXDpi(xDpi), iImageYDpi(yDpi) {}
-
-inline FX_IMAGEDIB_AND_DPI::~FX_IMAGEDIB_AND_DPI() = default;
-
 class CXFA_FFDoc {
  public:
-  CXFA_FFDoc(CXFA_FFApp* pApp, IXFA_DocEnvironment* pDocEnvironment);
+  static std::unique_ptr<CXFA_FFDoc> CreateAndOpen(
+      CXFA_FFApp* pApp,
+      IXFA_DocEnvironment* pDocEnvironment,
+      CPDF_Document* pPDFDoc,
+      const RetainPtr<IFX_SeekableStream>& stream);
+
   ~CXFA_FFDoc();
 
   IXFA_DocEnvironment* GetDocEnvironment() const {
     return m_pDocEnvironment.Get();
   }
   FormType GetFormType() const { return m_FormType; }
-
-  int32_t StartLoad();
-  int32_t DoLoad();
-  void StopLoad();
+  CFX_XMLDocument* GetXMLDocument() const { return m_pXMLDoc.get(); }
 
   CXFA_FFDocView* CreateDocView();
 
-  bool OpenDoc(CPDF_Document* pPDFDoc);
-  void CloseDoc();
-
-  CXFA_Document* GetXFADoc() const { return m_pDocumentParser->GetDocument(); }
+  CXFA_Document* GetXFADoc() const { return m_pDocument.get(); }
   CXFA_FFApp* GetApp() const { return m_pApp.Get(); }
   CPDF_Document* GetPDFDoc() const { return m_pPDFDoc.Get(); }
   CXFA_FFDocView* GetDocView(CXFA_LayoutProcessor* pLayout);
   CXFA_FFDocView* GetDocView();
-  RetainPtr<CFX_DIBitmap> GetPDFNamedImage(const WideStringView& wsName,
+  RetainPtr<CFX_DIBitmap> GetPDFNamedImage(WideStringView wsName,
                                            int32_t& iImageXDpi,
                                            int32_t& iImageYDpi);
   CFGAS_PDFFontMgr* GetPDFFontMgr() const { return m_pPDFFontMgr.get(); }
 
   bool SavePackage(CXFA_Node* pNode,
-                   const RetainPtr<IFX_SeekableStream>& pFile,
-                   CFX_ChecksumContext* pCSContext);
-  bool ImportData(const RetainPtr<IFX_SeekableStream>& pStream,
-                  bool bXDP = true);
+                   const RetainPtr<IFX_SeekableStream>& pFile);
 
  private:
+  CXFA_FFDoc(CXFA_FFApp* pApp,
+             IXFA_DocEnvironment* pDocEnvironment,
+             CPDF_Document* pPDFDoc);
+  bool OpenDoc(const RetainPtr<IFX_SeekableStream>& stream);
+  bool ParseDoc(const RetainPtr<IFX_SeekableStream>& stream);
+
   UnownedPtr<IXFA_DocEnvironment> const m_pDocEnvironment;
-  std::unique_ptr<CXFA_DocumentParser> m_pDocumentParser;
-  RetainPtr<IFX_SeekableStream> m_pStream;
   UnownedPtr<CXFA_FFApp> const m_pApp;
+  UnownedPtr<CPDF_Document> const m_pPDFDoc;
+  std::unique_ptr<CFX_XMLDocument> m_pXMLDoc;
   std::unique_ptr<CXFA_FFNotify> m_pNotify;
-  UnownedPtr<CPDF_Document> m_pPDFDoc;
-  std::map<uint32_t, FX_IMAGEDIB_AND_DPI> m_HashToDibDpiMap;
+  std::unique_ptr<CXFA_Document> m_pDocument;
   std::unique_ptr<CXFA_FFDocView> m_DocView;
   std::unique_ptr<CFGAS_PDFFontMgr> m_pPDFFontMgr;
+  std::map<uint32_t, FX_IMAGEDIB_AND_DPI> m_HashToDibDpiMap;
   FormType m_FormType = FormType::kXFAForeground;
 };
 
diff --git a/xfa/fxfa/cxfa_ffdocview.cpp b/xfa/fxfa/cxfa_ffdocview.cpp
index c4e5299..3a44122 100644
--- a/xfa/fxfa/cxfa_ffdocview.cpp
+++ b/xfa/fxfa/cxfa_ffdocview.cpp
@@ -6,8 +6,11 @@
 
 #include "xfa/fxfa/cxfa_ffdocview.h"
 
+#include <set>
+#include <utility>
+
 #include "core/fxcrt/fx_extension.h"
-#include "fxjs/cfxjse_engine.h"
+#include "fxjs/xfa/cfxjse_engine.h"
 #include "fxjs/xfa/cjx_object.h"
 #include "third_party/base/ptr_util.h"
 #include "third_party/base/stl_util.h"
@@ -15,7 +18,6 @@
 #include "xfa/fxfa/cxfa_ffbarcode.h"
 #include "xfa/fxfa/cxfa_ffcheckbutton.h"
 #include "xfa/fxfa/cxfa_ffdoc.h"
-#include "xfa/fxfa/cxfa_ffdraw.h"
 #include "xfa/fxfa/cxfa_ffexclgroup.h"
 #include "xfa/fxfa/cxfa_fffield.h"
 #include "xfa/fxfa/cxfa_ffimage.h"
@@ -23,68 +25,57 @@
 #include "xfa/fxfa/cxfa_ffpageview.h"
 #include "xfa/fxfa/cxfa_ffpushbutton.h"
 #include "xfa/fxfa/cxfa_ffsignature.h"
-#include "xfa/fxfa/cxfa_ffsubform.h"
 #include "xfa/fxfa/cxfa_fftext.h"
 #include "xfa/fxfa/cxfa_ffwidget.h"
 #include "xfa/fxfa/cxfa_ffwidgethandler.h"
 #include "xfa/fxfa/cxfa_fwladapterwidgetmgr.h"
+#include "xfa/fxfa/cxfa_readynodeiterator.h"
 #include "xfa/fxfa/cxfa_textprovider.h"
-#include "xfa/fxfa/cxfa_widgetacciterator.h"
+#include "xfa/fxfa/layout/cxfa_layoutprocessor.h"
 #include "xfa/fxfa/parser/cxfa_acrobat.h"
 #include "xfa/fxfa/parser/cxfa_binditems.h"
 #include "xfa/fxfa/parser/cxfa_calculate.h"
-#include "xfa/fxfa/parser/cxfa_layoutprocessor.h"
 #include "xfa/fxfa/parser/cxfa_pageset.h"
 #include "xfa/fxfa/parser/cxfa_present.h"
 #include "xfa/fxfa/parser/cxfa_subform.h"
 #include "xfa/fxfa/parser/cxfa_validate.h"
 #include "xfa/fxfa/parser/xfa_resolvenode_rs.h"
+#include "xfa/fxfa/parser/xfa_utils.h"
 
-const XFA_AttributeEnum gs_EventActivity[] = {
-    XFA_AttributeEnum::Click,      XFA_AttributeEnum::Change,
-    XFA_AttributeEnum::DocClose,   XFA_AttributeEnum::DocReady,
-    XFA_AttributeEnum::Enter,      XFA_AttributeEnum::Exit,
-    XFA_AttributeEnum::Full,       XFA_AttributeEnum::IndexChange,
-    XFA_AttributeEnum::Initialize, XFA_AttributeEnum::MouseDown,
-    XFA_AttributeEnum::MouseEnter, XFA_AttributeEnum::MouseExit,
-    XFA_AttributeEnum::MouseUp,    XFA_AttributeEnum::PostExecute,
-    XFA_AttributeEnum::PostOpen,   XFA_AttributeEnum::PostPrint,
-    XFA_AttributeEnum::PostSave,   XFA_AttributeEnum::PostSign,
-    XFA_AttributeEnum::PostSubmit, XFA_AttributeEnum::PreExecute,
-    XFA_AttributeEnum::PreOpen,    XFA_AttributeEnum::PrePrint,
-    XFA_AttributeEnum::PreSave,    XFA_AttributeEnum::PreSign,
-    XFA_AttributeEnum::PreSubmit,  XFA_AttributeEnum::Ready,
-    XFA_AttributeEnum::Unknown,
+const XFA_AttributeValue gs_EventActivity[] = {
+    XFA_AttributeValue::Click,      XFA_AttributeValue::Change,
+    XFA_AttributeValue::DocClose,   XFA_AttributeValue::DocReady,
+    XFA_AttributeValue::Enter,      XFA_AttributeValue::Exit,
+    XFA_AttributeValue::Full,       XFA_AttributeValue::IndexChange,
+    XFA_AttributeValue::Initialize, XFA_AttributeValue::MouseDown,
+    XFA_AttributeValue::MouseEnter, XFA_AttributeValue::MouseExit,
+    XFA_AttributeValue::MouseUp,    XFA_AttributeValue::PostExecute,
+    XFA_AttributeValue::PostOpen,   XFA_AttributeValue::PostPrint,
+    XFA_AttributeValue::PostSave,   XFA_AttributeValue::PostSign,
+    XFA_AttributeValue::PostSubmit, XFA_AttributeValue::PreExecute,
+    XFA_AttributeValue::PreOpen,    XFA_AttributeValue::PrePrint,
+    XFA_AttributeValue::PreSave,    XFA_AttributeValue::PreSign,
+    XFA_AttributeValue::PreSubmit,  XFA_AttributeValue::Ready,
+    XFA_AttributeValue::Unknown,
 };
 
-CXFA_FFDocView::CXFA_FFDocView(CXFA_FFDoc* pDoc)
-    : m_bLayoutEvent(false),
-      m_pListFocusWidget(nullptr),
-      m_bInLayoutStatus(false),
-      m_pDoc(pDoc),
-      m_pXFADocLayout(nullptr),
-      m_iStatus(XFA_DOCVIEW_LAYOUTSTATUS_None),
-      m_iLock(0) {}
+CXFA_FFDocView::CXFA_FFDocView(CXFA_FFDoc* pDoc) : m_pDoc(pDoc) {}
 
-CXFA_FFDocView::~CXFA_FFDocView() {
-  DestroyDocView();
-}
+CXFA_FFDocView::~CXFA_FFDocView() = default;
 
 void CXFA_FFDocView::InitLayout(CXFA_Node* pNode) {
   RunBindItems();
-  ExecEventActivityByDeepFirst(pNode, XFA_EVENT_Initialize, false, true,
-                               nullptr);
-  ExecEventActivityByDeepFirst(pNode, XFA_EVENT_IndexChange, false, true,
-                               nullptr);
+  ExecEventActivityByDeepFirst(pNode, XFA_EVENT_Initialize, false, true);
+  ExecEventActivityByDeepFirst(pNode, XFA_EVENT_IndexChange, false, true);
 }
 
-int32_t CXFA_FFDocView::StartLayout(int32_t iStartPage) {
+int32_t CXFA_FFDocView::StartLayout() {
   m_iStatus = XFA_DOCVIEW_LAYOUTSTATUS_Start;
   m_pDoc->GetXFADoc()->DoProtoMerge();
   m_pDoc->GetXFADoc()->DoDataMerge();
   m_pXFADocLayout = GetXFALayout();
 
-  int32_t iStatus = m_pXFADocLayout->StartLayout();
+  int32_t iStatus = m_pXFADocLayout->StartLayout(false);
   if (iStatus < 0)
     return iStatus;
 
@@ -97,14 +88,13 @@
   InitCalculate(pRootItem);
   InitValidate(pRootItem);
 
-  ExecEventActivityByDeepFirst(pRootItem, XFA_EVENT_Ready, true, true, nullptr);
+  ExecEventActivityByDeepFirst(pRootItem, XFA_EVENT_Ready, true, true);
   m_iStatus = XFA_DOCVIEW_LAYOUTSTATUS_Start;
   return iStatus;
 }
 
 int32_t CXFA_FFDocView::DoLayout() {
-  int32_t iStatus = 100;
-  iStatus = m_pXFADocLayout->DoLayout();
+  int32_t iStatus = m_pXFADocLayout->DoLayout();
   if (iStatus != 100)
     return iStatus;
 
@@ -135,24 +125,19 @@
   InitCalculate(pPageSetNode);
   InitValidate(pPageSetNode);
 
-  ExecEventActivityByDeepFirst(pPageSetNode, XFA_EVENT_Ready, true, true,
-                               nullptr);
-  ExecEventActivityByDeepFirst(pRootItem, XFA_EVENT_Ready, false, true,
-                               nullptr);
-  ExecEventActivityByDeepFirst(pRootItem, XFA_EVENT_DocReady, false, true,
-                               nullptr);
+  ExecEventActivityByDeepFirst(pPageSetNode, XFA_EVENT_Ready, true, true);
+  ExecEventActivityByDeepFirst(pRootItem, XFA_EVENT_Ready, false, true);
+  ExecEventActivityByDeepFirst(pRootItem, XFA_EVENT_DocReady, false, true);
 
   RunCalculateWidgets();
   RunValidate();
 
-  if (RunLayout()) {
-    ExecEventActivityByDeepFirst(pRootItem, XFA_EVENT_Ready, false, true,
-                                 nullptr);
-  }
+  if (RunLayout())
+    ExecEventActivityByDeepFirst(pRootItem, XFA_EVENT_Ready, false, true);
 
-  m_CalculateAccs.clear();
-  if (m_pFocusAcc && !m_pFocusWidget)
-    SetFocusWidgetAcc(m_pFocusAcc.Get());
+  m_CalculateNodes.clear();
+  if (m_pFocusNode && !m_pFocusWidget)
+    SetFocusNode(m_pFocusNode.Get());
 
   m_iStatus = XFA_DOCVIEW_LAYOUTSTATUS_End;
 }
@@ -174,8 +159,9 @@
                            L"validation errors not reported.",
                            iRemain);
     }
-    pAppProvider->MsgBox(wsMsg, pAppProvider->GetAppTitle(), XFA_MBICON_Status,
-                         XFA_MB_OK);
+    pAppProvider->MsgBox(wsMsg, pAppProvider->GetAppTitle(),
+                         static_cast<uint32_t>(AlertIcon::kStatus),
+                         static_cast<uint32_t>(AlertButton::kOK));
   }
   m_arrNullTestMsg.clear();
 }
@@ -185,12 +171,13 @@
     return;
 
   LockUpdate();
-  for (CXFA_Node* pNode : m_NewAddedNodes) {
+  while (!m_NewAddedNodes.empty()) {
+    CXFA_Node* pNode = m_NewAddedNodes.front();
+    m_NewAddedNodes.pop_front();
     InitCalculate(pNode);
     InitValidate(pNode);
-    ExecEventActivityByDeepFirst(pNode, XFA_EVENT_Ready, true, true, nullptr);
+    ExecEventActivityByDeepFirst(pNode, XFA_EVENT_Ready, true, true);
   }
-  m_NewAddedNodes.clear();
 
   RunSubformIndexChange();
   RunCalculateWidgets();
@@ -202,11 +189,30 @@
     RunEventLayoutReady();
 
   m_bLayoutEvent = false;
-  m_CalculateAccs.clear();
-  RunInvalidate();
+  m_CalculateNodes.clear();
   UnlockUpdate();
 }
 
+void CXFA_FFDocView::UpdateUIDisplay(CXFA_Node* pNode, CXFA_FFWidget* pExcept) {
+  CXFA_FFWidget* pWidget = GetWidgetForNode(pNode);
+  CXFA_FFWidget* pNext = nullptr;
+  for (; pWidget; pWidget = pNext) {
+    pNext = pWidget->GetNextFFWidget();
+    if (pWidget == pExcept || !pWidget->IsLoaded() ||
+        (pNode->GetFFWidgetType() != XFA_FFWidgetType::kCheckButton &&
+         pWidget->IsFocused())) {
+      continue;
+    }
+    ObservedPtr<CXFA_FFWidget> pWatched(pWidget);
+    ObservedPtr<CXFA_FFWidget> pWatchedNext(pNext);
+    pWatched->UpdateFWLData();
+    if (pWatched)
+      pWatched->InvalidateRect();
+    if (!pWatchedNext)
+      break;
+  }
+}
+
 int32_t CXFA_FFDocView::CountPageViews() const {
   return m_pXFADocLayout ? m_pXFADocLayout->CountPages() : 0;
 }
@@ -214,37 +220,37 @@
 CXFA_FFPageView* CXFA_FFDocView::GetPageView(int32_t nIndex) const {
   if (!m_pXFADocLayout)
     return nullptr;
-  return static_cast<CXFA_FFPageView*>(m_pXFADocLayout->GetPage(nIndex));
+  auto* pPage = m_pXFADocLayout->GetPage(nIndex);
+  return pPage ? pPage->GetPageView() : nullptr;
 }
 
 CXFA_LayoutProcessor* CXFA_FFDocView::GetXFALayout() const {
-  return m_pDoc->GetXFADoc()->GetDocLayout();
+  return CXFA_LayoutProcessor::FromDocument(m_pDoc->GetXFADoc());
 }
 
-bool CXFA_FFDocView::ResetSingleWidgetAccData(CXFA_WidgetAcc* pWidgetAcc) {
-  CXFA_Node* pNode = pWidgetAcc->GetNode();
+bool CXFA_FFDocView::ResetSingleNodeData(CXFA_Node* pNode) {
   XFA_Element eType = pNode->GetElementType();
   if (eType != XFA_Element::Field && eType != XFA_Element::ExclGroup)
     return false;
 
-  pWidgetAcc->ResetData();
-  pWidgetAcc->UpdateUIDisplay(this, nullptr);
+  pNode->ResetData();
+  UpdateUIDisplay(pNode, nullptr);
   CXFA_Validate* validate = pNode->GetValidateIfExists();
   if (!validate)
     return true;
 
-  AddValidateWidget(pWidgetAcc);
-  validate->SetFlag(XFA_NodeFlag_NeedsInitApp, false);
+  AddValidateNode(pNode);
+  validate->SetFlag(XFA_NodeFlag_NeedsInitApp);
   return true;
 }
 
-void CXFA_FFDocView::ResetWidgetAcc(CXFA_WidgetAcc* pWidgetAcc) {
+void CXFA_FFDocView::ResetNode(CXFA_Node* pNode) {
   m_bLayoutEvent = true;
   bool bChanged = false;
   CXFA_Node* pFormNode = nullptr;
-  if (pWidgetAcc) {
-    bChanged = ResetSingleWidgetAccData(pWidgetAcc);
-    pFormNode = pWidgetAcc->GetNode();
+  if (pNode) {
+    bChanged = ResetSingleNodeData(pNode);
+    pFormNode = pNode;
   } else {
     pFormNode = GetRootSubform();
   }
@@ -253,65 +259,19 @@
 
   if (pFormNode->GetElementType() != XFA_Element::Field &&
       pFormNode->GetElementType() != XFA_Element::ExclGroup) {
-    CXFA_WidgetAccIterator Iterator(pFormNode);
-    while (CXFA_WidgetAcc* pAcc = Iterator.MoveToNext()) {
-      bChanged |= ResetSingleWidgetAccData(pAcc);
-      if (pAcc->GetNode()->GetElementType() == XFA_Element::ExclGroup)
-        Iterator.SkipTree();
+    CXFA_ReadyNodeIterator it(pFormNode);
+    while (CXFA_Node* next_node = it.MoveToNext()) {
+      bChanged |= ResetSingleNodeData(next_node);
+      if (next_node->GetElementType() == XFA_Element::ExclGroup)
+        it.SkipTree();
     }
   }
   if (bChanged)
     m_pDoc->GetDocEnvironment()->SetChangeMark(m_pDoc.Get());
 }
 
-int32_t CXFA_FFDocView::ProcessWidgetEvent(CXFA_EventParam* pParam,
-                                           CXFA_WidgetAcc* pWidgetAcc) {
-  if (!pParam)
-    return XFA_EVENTERROR_Error;
-
-  if (pParam->m_eType == XFA_EVENT_Validate) {
-    WideString wsValidateStr(L"preSubmit");
-    CXFA_Node* pConfigItem =
-        ToNode(m_pDoc->GetXFADoc()->GetXFAObject(XFA_HASHCODE_Config));
-    if (pConfigItem) {
-      CXFA_Acrobat* pAcrobatNode =
-          pConfigItem->GetChild<CXFA_Acrobat>(0, XFA_Element::Acrobat, false);
-      CXFA_Validate* pValidateNode =
-          pAcrobatNode ? pAcrobatNode->GetChild<CXFA_Validate>(
-                             0, XFA_Element::Validate, false)
-                       : nullptr;
-      if (!pValidateNode) {
-        CXFA_Present* pPresentNode =
-            pConfigItem->GetChild<CXFA_Present>(0, XFA_Element::Present, false);
-        pValidateNode = pPresentNode ? pPresentNode->GetChild<CXFA_Validate>(
-                                           0, XFA_Element::Validate, false)
-                                     : nullptr;
-      }
-      if (pValidateNode)
-        wsValidateStr = pValidateNode->JSObject()->GetContent(false);
-    }
-
-    if (!wsValidateStr.Contains(L"preSubmit"))
-      return XFA_EVENTERROR_Success;
-  }
-
-  CXFA_Node* pNode = pWidgetAcc ? pWidgetAcc->GetNode() : nullptr;
-  if (!pNode) {
-    CXFA_Node* pRootItem =
-        ToNode(m_pDoc->GetXFADoc()->GetXFAObject(XFA_HASHCODE_Form));
-    if (!pRootItem)
-      return XFA_EVENTERROR_Error;
-
-    pNode = pRootItem->GetChild<CXFA_Node>(0, XFA_Element::Subform, false);
-  }
-
-  ExecEventActivityByDeepFirst(pNode, pParam->m_eType, pParam->m_bIsFormReady,
-                               true, nullptr);
-  return XFA_EVENTERROR_Success;
-}
-
 CXFA_FFWidget* CXFA_FFDocView::GetWidgetForNode(CXFA_Node* node) {
-  return static_cast<CXFA_FFWidget*>(GetXFALayout()->GetLayoutItem(node));
+  return GetFFWidget(ToContentLayoutItem(GetXFALayout()->GetLayoutItem(node)));
 }
 
 CXFA_FFWidgetHandler* CXFA_FFDocView::GetWidgetHandler() {
@@ -320,74 +280,60 @@
   return m_pWidgetHandler.get();
 }
 
-std::unique_ptr<CXFA_WidgetAccIterator>
-CXFA_FFDocView::CreateWidgetAccIterator() {
+std::unique_ptr<CXFA_ReadyNodeIterator>
+CXFA_FFDocView::CreateReadyNodeIterator() {
   CXFA_Subform* pFormRoot = GetRootSubform();
-  return pFormRoot ? pdfium::MakeUnique<CXFA_WidgetAccIterator>(pFormRoot)
+  return pFormRoot ? pdfium::MakeUnique<CXFA_ReadyNodeIterator>(pFormRoot)
                    : nullptr;
 }
 
-void CXFA_FFDocView::KillFocus() {
-  if (m_pFocusWidget &&
-      (m_pFocusWidget->GetStatus() & XFA_WidgetStatus_Focused)) {
-    m_pFocusWidget->OnKillFocus(nullptr);
-  }
-  m_pFocusAcc = nullptr;
-  m_pFocusWidget = nullptr;
-  m_pOldFocusWidget = nullptr;
-}
-
-bool CXFA_FFDocView::SetFocus(CXFA_FFWidget* hWidget) {
-  CXFA_FFWidget* pNewFocus = hWidget;
-  if (m_pOldFocusWidget == pNewFocus)
+bool CXFA_FFDocView::SetFocus(CXFA_FFWidget* pNewFocus) {
+  if (pNewFocus == m_pFocusWidget)
     return false;
 
-  CXFA_FFWidget* pOldFocus = m_pOldFocusWidget.Get();
-  m_pOldFocusWidget = pNewFocus;
-  if (pOldFocus) {
-    if (m_pFocusWidget != m_pOldFocusWidget &&
-        (pOldFocus->GetStatus() & XFA_WidgetStatus_Focused)) {
-      m_pFocusWidget = pOldFocus;
-      pOldFocus->OnKillFocus(pNewFocus);
-    } else if ((pOldFocus->GetStatus() & XFA_WidgetStatus_Visible)) {
-      if (!pOldFocus->IsLoaded())
-        pOldFocus->LoadWidget();
-
-      pOldFocus->OnSetFocus(m_pFocusWidget.Get());
-      m_pFocusWidget = pOldFocus;
-      pOldFocus->OnKillFocus(pNewFocus);
+  ObservedPtr<CXFA_FFWidget> pNewWatched(pNewFocus);
+  if (m_pFocusWidget) {
+    CXFA_ContentLayoutItem* pItem = m_pFocusWidget->GetLayoutItem();
+    if (pItem->TestStatusBits(XFA_WidgetStatus_Visible) &&
+        !pItem->TestStatusBits(XFA_WidgetStatus_Focused)) {
+      if (!m_pFocusWidget->IsLoaded())
+        m_pFocusWidget->LoadWidget();
+      if (!m_pFocusWidget->OnSetFocus(m_pFocusWidget.Get()))
+        m_pFocusWidget.Reset();
     }
   }
-  if (m_pFocusWidget == m_pOldFocusWidget)
-    return false;
+  if (m_pFocusWidget) {
+    if (!m_pFocusWidget->OnKillFocus(pNewWatched.Get()))
+      return false;
+  }
 
-  pNewFocus = m_pOldFocusWidget.Get();
-  if (m_pListFocusWidget && pNewFocus == m_pListFocusWidget) {
-    m_pFocusAcc = nullptr;
-    m_pFocusWidget = nullptr;
-    m_pListFocusWidget = nullptr;
-    m_pOldFocusWidget = nullptr;
-    return false;
+  if (pNewWatched) {
+    if (pNewWatched->GetLayoutItem()->TestStatusBits(
+            XFA_WidgetStatus_Visible)) {
+      if (!pNewWatched->IsLoaded())
+        pNewWatched->LoadWidget();
+      if (!pNewWatched->OnSetFocus(m_pFocusWidget.Get()))
+        pNewWatched.Reset();
+    }
   }
-  if (pNewFocus && (pNewFocus->GetStatus() & XFA_WidgetStatus_Visible)) {
-    if (!pNewFocus->IsLoaded())
-      pNewFocus->LoadWidget();
-    pNewFocus->OnSetFocus(m_pFocusWidget.Get());
+  if (pNewWatched) {
+    CXFA_Node* node = pNewWatched->GetNode();
+    m_pFocusNode = node->IsWidgetReady() ? node : nullptr;
+    m_pFocusWidget.Reset(pNewWatched.Get());
+  } else {
+    m_pFocusNode.Reset();
+    m_pFocusWidget.Reset();
   }
-  m_pFocusAcc = pNewFocus ? pNewFocus->GetNode()->GetWidgetAcc() : nullptr;
-  m_pFocusWidget = pNewFocus;
-  m_pOldFocusWidget = m_pFocusWidget;
+
   return true;
 }
 
-void CXFA_FFDocView::SetFocusWidgetAcc(CXFA_WidgetAcc* pWidgetAcc) {
-  CXFA_FFWidget* pNewFocus = nullptr;
-  if (pWidgetAcc)
-    pNewFocus = GetWidgetForNode(pWidgetAcc->GetNode());
+void CXFA_FFDocView::SetFocusNode(CXFA_Node* node) {
+  CXFA_FFWidget* pNewFocus = node ? GetWidgetForNode(node) : nullptr;
   if (!SetFocus(pNewFocus))
     return;
 
-  m_pFocusAcc = pWidgetAcc;
+  m_pFocusNode = node;
   if (m_iStatus != XFA_DOCVIEW_LAYOUTSTATUS_End)
     return;
 
@@ -396,177 +342,136 @@
 }
 
 void CXFA_FFDocView::DeleteLayoutItem(CXFA_FFWidget* pWidget) {
-  if (m_pFocusAcc && m_pFocusAcc->GetNode() != pWidget->GetNode())
+  if (m_pFocusNode != pWidget->GetNode())
     return;
 
-  m_pFocusAcc = nullptr;
-  m_pFocusWidget = nullptr;
-  m_pOldFocusWidget = nullptr;
+  m_pFocusNode.Reset();
+  m_pFocusWidget.Reset();
 }
 
-static int32_t XFA_ProcessEvent(CXFA_FFDocView* pDocView,
-                                CXFA_WidgetAcc* pWidgetAcc,
-                                CXFA_EventParam* pParam) {
+static XFA_EventError XFA_ProcessEvent(CXFA_FFDocView* pDocView,
+                                       CXFA_Node* pNode,
+                                       CXFA_EventParam* pParam) {
   if (!pParam || pParam->m_eType == XFA_EVENT_Unknown)
-    return XFA_EVENTERROR_NotExist;
-  if (!pWidgetAcc)
-    return XFA_EVENTERROR_NotExist;
-
-  CXFA_Node* node = pWidgetAcc->GetNode();
-  if (node && node->GetElementType() == XFA_Element::Draw)
-    return XFA_EVENTERROR_NotExist;
+    return XFA_EventError::kNotExist;
+  if (pNode && pNode->GetElementType() == XFA_Element::Draw)
+    return XFA_EventError::kNotExist;
 
   switch (pParam->m_eType) {
     case XFA_EVENT_Calculate:
-      return node->ProcessCalculate(pDocView);
+      return pNode->ProcessCalculate(pDocView);
     case XFA_EVENT_Validate:
       if (pDocView->GetDoc()->GetDocEnvironment()->IsValidationsEnabled(
               pDocView->GetDoc())) {
-        return node->ProcessValidate(pDocView, 0x01);
+        return pNode->ProcessValidate(pDocView, 0x01);
       }
-      return XFA_EVENTERROR_Disabled;
+      return XFA_EventError::kDisabled;
     case XFA_EVENT_InitCalculate: {
-      CXFA_Calculate* calc = node->GetCalculateIfExists();
+      CXFA_Calculate* calc = pNode->GetCalculateIfExists();
       if (!calc)
-        return XFA_EVENTERROR_NotExist;
-      if (node->IsUserInteractive())
-        return XFA_EVENTERROR_Disabled;
+        return XFA_EventError::kNotExist;
+      if (pNode->IsUserInteractive())
+        return XFA_EventError::kDisabled;
 
-      return node->ExecuteScript(pDocView, calc->GetScriptIfExists(), pParam);
+      return pNode->ExecuteScript(pDocView, calc->GetScriptIfExists(), pParam);
     }
     default:
-      break;
+      return pNode->ProcessEvent(pDocView, gs_EventActivity[pParam->m_eType],
+                                 pParam);
   }
-
-  return node->ProcessEvent(pDocView, gs_EventActivity[pParam->m_eType],
-                            pParam);
 }
 
-int32_t CXFA_FFDocView::ExecEventActivityByDeepFirst(CXFA_Node* pFormNode,
-                                                     XFA_EVENTTYPE eEventType,
-                                                     bool bIsFormReady,
-                                                     bool bRecursive,
-                                                     CXFA_Node* pExclude) {
-  if (pFormNode == pExclude)
-    return XFA_EVENTERROR_NotExist;
+XFA_EventError CXFA_FFDocView::ExecEventActivityByDeepFirst(
+    CXFA_Node* pFormNode,
+    XFA_EVENTTYPE eEventType,
+    bool bIsFormReady,
+    bool bRecursive) {
+  if (!pFormNode)
+    return XFA_EventError::kNotExist;
 
   XFA_Element elementType = pFormNode->GetElementType();
   if (elementType == XFA_Element::Field) {
     if (eEventType == XFA_EVENT_IndexChange)
-      return XFA_EVENTERROR_NotExist;
+      return XFA_EventError::kNotExist;
 
-    CXFA_WidgetAcc* pWidgetAcc = pFormNode->GetWidgetAcc();
-    if (!pWidgetAcc)
-      return XFA_EVENTERROR_NotExist;
+    if (!pFormNode->IsWidgetReady())
+      return XFA_EventError::kNotExist;
 
     CXFA_EventParam eParam;
     eParam.m_eType = eEventType;
-    eParam.m_pTarget = pWidgetAcc;
+    eParam.m_pTarget = pFormNode;
     eParam.m_bIsFormReady = bIsFormReady;
-    return XFA_ProcessEvent(this, pWidgetAcc, &eParam);
+    return XFA_ProcessEvent(this, pFormNode, &eParam);
   }
 
-  int32_t iRet = XFA_EVENTERROR_NotExist;
+  XFA_EventError iRet = XFA_EventError::kNotExist;
   if (bRecursive) {
     for (CXFA_Node* pNode = pFormNode->GetFirstContainerChild(); pNode;
          pNode = pNode->GetNextContainerSibling()) {
       elementType = pNode->GetElementType();
       if (elementType != XFA_Element::Variables &&
           elementType != XFA_Element::Draw) {
-        iRet |= ExecEventActivityByDeepFirst(pNode, eEventType, bIsFormReady,
-                                             bRecursive, pExclude);
+        XFA_EventErrorAccumulate(
+            &iRet, ExecEventActivityByDeepFirst(pNode, eEventType, bIsFormReady,
+                                                bRecursive));
       }
     }
   }
-  CXFA_WidgetAcc* pWidgetAcc = pFormNode->GetWidgetAcc();
-  if (!pWidgetAcc)
+  if (!pFormNode->IsWidgetReady())
     return iRet;
 
   CXFA_EventParam eParam;
   eParam.m_eType = eEventType;
-  eParam.m_pTarget = pWidgetAcc;
+  eParam.m_pTarget = pFormNode;
   eParam.m_bIsFormReady = bIsFormReady;
-  iRet |= XFA_ProcessEvent(this, pWidgetAcc, &eParam);
 
+  XFA_EventErrorAccumulate(&iRet, XFA_ProcessEvent(this, pFormNode, &eParam));
   return iRet;
 }
 
 CXFA_FFWidget* CXFA_FFDocView::GetWidgetByName(const WideString& wsName,
                                                CXFA_FFWidget* pRefWidget) {
-  CXFA_WidgetAcc* pRefAcc =
-      pRefWidget ? pRefWidget->GetNode()->GetWidgetAcc() : nullptr;
-  CXFA_WidgetAcc* pAcc = GetWidgetAccByName(wsName, pRefAcc);
-  if (!pAcc)
-    return nullptr;
-  return GetWidgetForNode(pAcc->GetNode());
-}
-
-CXFA_WidgetAcc* CXFA_FFDocView::GetWidgetAccByName(
-    const WideString& wsName,
-    CXFA_WidgetAcc* pRefWidgetAcc) {
-  WideString wsExpression;
-  uint32_t dwStyle = XFA_RESOLVENODE_Children | XFA_RESOLVENODE_Properties |
-                     XFA_RESOLVENODE_Siblings | XFA_RESOLVENODE_Parent;
   CFXJSE_Engine* pScriptContext = m_pDoc->GetXFADoc()->GetScriptContext();
-  if (!pScriptContext)
-    return nullptr;
-
-  CXFA_Node* refNode = nullptr;
-  if (pRefWidgetAcc) {
-    refNode = pRefWidgetAcc->GetNode();
-    wsExpression = wsName;
-  } else {
-    wsExpression = L"$form." + wsName;
+  CXFA_Node* pRefNode = nullptr;
+  if (pRefWidget) {
+    CXFA_Node* node = pRefWidget->GetNode();
+    pRefNode = node->IsWidgetReady() ? node : nullptr;
   }
+  WideString wsExpression = (!pRefNode ? L"$form." : L"") + wsName;
 
   XFA_RESOLVENODE_RS resolveNodeRS;
-  if (!pScriptContext->ResolveObjects(refNode, wsExpression.AsStringView(),
-                                      &resolveNodeRS, dwStyle, nullptr)) {
+  constexpr uint32_t kStyle = XFA_RESOLVENODE_Children |
+                              XFA_RESOLVENODE_Properties |
+                              XFA_RESOLVENODE_Siblings | XFA_RESOLVENODE_Parent;
+  if (!pScriptContext->ResolveObjects(pRefNode, wsExpression.AsStringView(),
+                                      &resolveNodeRS, kStyle, nullptr)) {
     return nullptr;
   }
 
   if (resolveNodeRS.dwFlags == XFA_ResolveNode_RSType_Nodes) {
     CXFA_Node* pNode = resolveNodeRS.objects.front()->AsNode();
-    if (pNode)
-      return pNode->GetWidgetAcc();
+    if (pNode && pNode->IsWidgetReady())
+      return GetWidgetForNode(pNode);
   }
   return nullptr;
 }
 
-void CXFA_FFDocView::OnPageEvent(CXFA_ContainerLayoutItem* pSender,
+void CXFA_FFDocView::OnPageEvent(CXFA_ViewLayoutItem* pSender,
                                  uint32_t dwEvent) {
-  CXFA_FFPageView* pFFPageView = static_cast<CXFA_FFPageView*>(pSender);
+  CXFA_FFPageView* pFFPageView = pSender ? pSender->GetPageView() : nullptr;
   m_pDoc->GetDocEnvironment()->PageViewEvent(pFFPageView, dwEvent);
 }
 
-
-void CXFA_FFDocView::AddInvalidateRect(CXFA_FFWidget* pWidget,
-                                       const CFX_RectF& rtInvalidate) {
-  AddInvalidateRect(pWidget->GetPageView(), rtInvalidate);
-}
-
-void CXFA_FFDocView::AddInvalidateRect(CXFA_FFPageView* pPageView,
-                                       const CFX_RectF& rtInvalidate) {
-  if (m_mapPageInvalidate[pPageView]) {
-    m_mapPageInvalidate[pPageView]->Union(rtInvalidate);
-    return;
-  }
-
-  m_mapPageInvalidate[pPageView] = pdfium::MakeUnique<CFX_RectF>(rtInvalidate);
-}
-
-void CXFA_FFDocView::RunInvalidate() {
-  for (const auto& pair : m_mapPageInvalidate)
-    m_pDoc->GetDocEnvironment()->InvalidateRect(pair.first, *pair.second);
-
-  m_mapPageInvalidate.clear();
+void CXFA_FFDocView::InvalidateRect(CXFA_FFPageView* pPageView,
+                                    const CFX_RectF& rtInvalidate) {
+  m_pDoc->GetDocEnvironment()->InvalidateRect(pPageView, rtInvalidate);
 }
 
 bool CXFA_FFDocView::RunLayout() {
   LockUpdate();
   m_bInLayoutStatus = true;
   if (!m_pXFADocLayout->IncrementLayout() &&
-      m_pXFADocLayout->StartLayout() < 100) {
+      m_pXFADocLayout->StartLayout(false) < 100) {
     m_pXFADocLayout->DoLayout();
     UnlockUpdate();
     m_bInLayoutStatus = false;
@@ -583,16 +488,19 @@
 }
 
 void CXFA_FFDocView::RunSubformIndexChange() {
-  for (CXFA_Node* pSubformNode : m_IndexChangedSubforms) {
-    if (!pSubformNode->GetWidgetAcc())
+  std::set<CXFA_Node*> seen;
+  while (!m_IndexChangedSubforms.empty()) {
+    CXFA_Node* pSubformNode = m_IndexChangedSubforms.front();
+    m_IndexChangedSubforms.pop_front();
+    bool bInserted = seen.insert(pSubformNode).second;
+    if (!bInserted || !pSubformNode->IsWidgetReady())
       continue;
 
     CXFA_EventParam eParam;
     eParam.m_eType = XFA_EVENT_IndexChange;
-    eParam.m_pTarget = pSubformNode->GetWidgetAcc();
-    pSubformNode->ProcessEvent(this, XFA_AttributeEnum::IndexChange, &eParam);
+    eParam.m_pTarget = pSubformNode;
+    pSubformNode->ProcessEvent(this, XFA_AttributeValue::IndexChange, &eParam);
   }
-  m_IndexChangedSubforms.clear();
 }
 
 void CXFA_FFDocView::AddNewFormNode(CXFA_Node* pNode) {
@@ -602,7 +510,8 @@
 
 void CXFA_FFDocView::AddIndexChangedSubform(CXFA_Node* pNode) {
   ASSERT(pNode->GetElementType() == XFA_Element::Subform);
-  m_IndexChangedSubforms.push_back(pNode);
+  if (!pdfium::ContainsValue(m_IndexChangedSubforms, pNode))
+    m_IndexChangedSubforms.push_back(pNode);
 }
 
 void CXFA_FFDocView::RunDocClose() {
@@ -611,24 +520,14 @@
   if (!pRootItem)
     return;
 
-  ExecEventActivityByDeepFirst(pRootItem, XFA_EVENT_DocClose, false, true,
-                               nullptr);
+  ExecEventActivityByDeepFirst(pRootItem, XFA_EVENT_DocClose, false, true);
 }
 
-void CXFA_FFDocView::DestroyDocView() {
-  ClearInvalidateList();
-  m_iStatus = XFA_DOCVIEW_LAYOUTSTATUS_None;
-  m_iLock = 0;
-  m_ValidateAccs.clear();
-  m_BindItems.clear();
-  m_CalculateAccs.clear();
-}
-
-void CXFA_FFDocView::AddCalculateWidgetAcc(CXFA_WidgetAcc* pWidgetAcc) {
-  CXFA_WidgetAcc* pCurrentAcc =
-      !m_CalculateAccs.empty() ? m_CalculateAccs.back() : nullptr;
-  if (pCurrentAcc != pWidgetAcc)
-    m_CalculateAccs.push_back(pWidgetAcc);
+void CXFA_FFDocView::AddCalculateNode(CXFA_Node* node) {
+  CXFA_Node* pCurrentNode =
+      !m_CalculateNodes.empty() ? m_CalculateNodes.back() : nullptr;
+  if (pCurrentNode != node)
+    m_CalculateNodes.push_back(node);
 }
 
 void CXFA_FFDocView::AddCalculateNodeNotify(CXFA_Node* pNodeChange) {
@@ -637,54 +536,56 @@
     return;
 
   for (auto* pResult : pGlobalData->m_Globals) {
-    if (!pResult->HasRemovedChildren())
-      AddCalculateWidgetAcc(pResult->GetWidgetAcc());
+    if (!pResult->HasRemovedChildren() && pResult->IsWidgetReady())
+      AddCalculateNode(pResult);
   }
 }
 
 size_t CXFA_FFDocView::RunCalculateRecursive(size_t index) {
-  while (index < m_CalculateAccs.size()) {
-    CXFA_Node* node = m_CalculateAccs[index]->GetNode();
+  while (index < m_CalculateNodes.size()) {
+    CXFA_Node* node = m_CalculateNodes[index];
 
     AddCalculateNodeNotify(node);
     size_t recurse = node->JSObject()->GetCalcRecursionCount() + 1;
     node->JSObject()->SetCalcRecursionCount(recurse);
     if (recurse > 11)
       break;
-    if (node->ProcessCalculate(this) == XFA_EVENTERROR_Success)
-      AddValidateWidget(node->GetWidgetAcc());
+    if (node->ProcessCalculate(this) == XFA_EventError::kSuccess &&
+        node->IsWidgetReady()) {
+      AddValidateNode(node);
+    }
 
     index = RunCalculateRecursive(++index);
   }
   return index;
 }
 
-int32_t CXFA_FFDocView::RunCalculateWidgets() {
+XFA_EventError CXFA_FFDocView::RunCalculateWidgets() {
   if (!m_pDoc->GetDocEnvironment()->IsCalculationsEnabled(m_pDoc.Get()))
-    return XFA_EVENTERROR_Disabled;
-  if (!m_CalculateAccs.empty())
+    return XFA_EventError::kDisabled;
+
+  if (!m_CalculateNodes.empty())
     RunCalculateRecursive(0);
 
-  for (CXFA_WidgetAcc* pCurAcc : m_CalculateAccs)
-    pCurAcc->GetNode()->JSObject()->SetCalcRecursionCount(0);
+  for (CXFA_Node* node : m_CalculateNodes)
+    node->JSObject()->SetCalcRecursionCount(0);
 
-  m_CalculateAccs.clear();
-  return XFA_EVENTERROR_Success;
+  m_CalculateNodes.clear();
+  return XFA_EventError::kSuccess;
 }
 
-void CXFA_FFDocView::AddValidateWidget(CXFA_WidgetAcc* pWidget) {
-  if (!pdfium::ContainsValue(m_ValidateAccs, pWidget))
-    m_ValidateAccs.push_back(pWidget);
+void CXFA_FFDocView::AddValidateNode(CXFA_Node* node) {
+  if (!pdfium::ContainsValue(m_ValidateNodes, node))
+    m_ValidateNodes.push_back(node);
 }
 
 void CXFA_FFDocView::InitCalculate(CXFA_Node* pNode) {
-  ExecEventActivityByDeepFirst(pNode, XFA_EVENT_InitCalculate, false, true,
-                               nullptr);
+  ExecEventActivityByDeepFirst(pNode, XFA_EVENT_InitCalculate, false, true);
 }
 
-void CXFA_FFDocView::ProcessValueChanged(CXFA_WidgetAcc* widgetAcc) {
-  AddValidateWidget(widgetAcc);
-  AddCalculateWidgetAcc(widgetAcc);
+void CXFA_FFDocView::ProcessValueChanged(CXFA_Node* node) {
+  AddValidateNode(node);
+  AddCalculateNode(node);
   RunCalculateWidgets();
   RunValidate();
 }
@@ -693,8 +594,8 @@
   if (!m_pDoc->GetDocEnvironment()->IsValidationsEnabled(m_pDoc.Get()))
     return false;
 
-  ExecEventActivityByDeepFirst(pNode, XFA_EVENT_Validate, false, true, nullptr);
-  m_ValidateAccs.clear();
+  ExecEventActivityByDeepFirst(pNode, XFA_EVENT_Validate, false, true);
+  m_ValidateNodes.clear();
   return true;
 }
 
@@ -702,12 +603,12 @@
   if (!m_pDoc->GetDocEnvironment()->IsValidationsEnabled(m_pDoc.Get()))
     return false;
 
-  for (CXFA_WidgetAcc* pAcc : m_ValidateAccs) {
-    CXFA_Node* node = pAcc->GetNode();
+  while (!m_ValidateNodes.empty()) {
+    CXFA_Node* node = m_ValidateNodes.front();
+    m_ValidateNodes.pop_front();
     if (!node->HasRemovedChildren())
       node->ProcessValidate(this, 0);
   }
-  m_ValidateAccs.clear();
   return true;
 }
 
@@ -717,44 +618,46 @@
   if (!pRootItem)
     return false;
 
-  ExecEventActivityByDeepFirst(pRootItem, XFA_EVENT_Ready, false, true,
-                               nullptr);
+  ExecEventActivityByDeepFirst(pRootItem, XFA_EVENT_Ready, false, true);
   RunLayout();
   return true;
 }
 
 void CXFA_FFDocView::RunBindItems() {
-  for (auto* item : m_BindItems) {
+  while (!m_BindItems.empty()) {
+    CXFA_BindItems* item = m_BindItems.front();
+    m_BindItems.pop_front();
     if (item->HasRemovedChildren())
       continue;
 
     CXFA_Node* pWidgetNode = item->GetParent();
-    CXFA_WidgetAcc* pAcc = pWidgetNode->GetWidgetAcc();
-    if (!pAcc)
+    if (!pWidgetNode || !pWidgetNode->IsWidgetReady())
       continue;
 
     CFXJSE_Engine* pScriptContext =
         pWidgetNode->GetDocument()->GetScriptContext();
     WideString wsRef = item->GetRef();
-    uint32_t dwStyle = XFA_RESOLVENODE_Children | XFA_RESOLVENODE_Properties |
-                       XFA_RESOLVENODE_Siblings | XFA_RESOLVENODE_Parent |
-                       XFA_RESOLVENODE_ALL;
+    constexpr uint32_t kStyle =
+        XFA_RESOLVENODE_Children | XFA_RESOLVENODE_Properties |
+        XFA_RESOLVENODE_Siblings | XFA_RESOLVENODE_Parent | XFA_RESOLVENODE_ALL;
     XFA_RESOLVENODE_RS rs;
     pScriptContext->ResolveObjects(pWidgetNode, wsRef.AsStringView(), &rs,
-                                   dwStyle, nullptr);
-    pAcc->DeleteItem(-1, false, false);
+                                   kStyle, nullptr);
+    pWidgetNode->DeleteItem(-1, false, false);
     if (rs.dwFlags != XFA_ResolveNode_RSType_Nodes || rs.objects.empty())
       continue;
 
     WideString wsValueRef = item->GetValueRef();
     WideString wsLabelRef = item->GetLabelRef();
     const bool bUseValue = wsLabelRef.IsEmpty() || wsLabelRef == wsValueRef;
-    const bool bLabelUseContent = wsLabelRef.IsEmpty() || wsLabelRef == L"$";
-    const bool bValueUseContent = wsValueRef.IsEmpty() || wsValueRef == L"$";
+    const bool bLabelUseContent =
+        wsLabelRef.IsEmpty() || wsLabelRef.EqualsASCII("$");
+    const bool bValueUseContent =
+        wsValueRef.IsEmpty() || wsValueRef.EqualsASCII("$");
     WideString wsValue;
     WideString wsLabel;
     uint32_t uValueHash = FX_HashCode_GetW(wsValueRef.AsStringView(), false);
-    for (CXFA_Object* refObject : rs.objects) {
+    for (auto& refObject : rs.objects) {
       CXFA_Node* refNode = refObject->AsNode();
       if (!refNode)
         continue;
@@ -779,10 +682,9 @@
       } else {
         wsLabel = wsValue;
       }
-      pAcc->InsertItem(wsLabel, wsValue, false);
+      pWidgetNode->InsertItem(wsLabel, wsValue, false);
     }
   }
-  m_BindItems.clear();
 }
 
 void CXFA_FFDocView::SetChangeMark() {
diff --git a/xfa/fxfa/cxfa_ffdocview.h b/xfa/fxfa/cxfa_ffdocview.h
index 5c8f017..dbc5319 100644
--- a/xfa/fxfa/cxfa_ffdocview.h
+++ b/xfa/fxfa/cxfa_ffdocview.h
@@ -7,22 +7,26 @@
 #ifndef XFA_FXFA_CXFA_FFDOCVIEW_H_
 #define XFA_FXFA_CXFA_FFDOCVIEW_H_
 
-#include <map>
+#include <deque>
 #include <memory>
 #include <vector>
 
+#include "core/fxcrt/observed_ptr.h"
 #include "core/fxcrt/unowned_ptr.h"
 #include "xfa/fxfa/cxfa_eventparam.h"
 #include "xfa/fxfa/cxfa_ffdoc.h"
+#include "xfa/fxfa/cxfa_ffwidget.h"
+#include "xfa/fxfa/fxfa.h"
 
 class CXFA_BindItems;
-class CXFA_FFWidgetHandler;
 class CXFA_FFDoc;
-class CXFA_FFWidget;
+class CXFA_FFWidgetHandler;
+class CXFA_Node;
+class CXFA_ReadyNodeIterator;
 class CXFA_Subform;
-class CXFA_WidgetAccIterator;
+class CXFA_ViewLayoutItem;
 
-extern const XFA_AttributeEnum gs_EventActivity[];
+extern const XFA_AttributeValue gs_EventActivity[];
 enum XFA_DOCVIEW_LAYOUTSTATUS {
   XFA_DOCVIEW_LAYOUTSTATUS_None,
   XFA_DOCVIEW_LAYOUTSTATUS_Start,
@@ -45,74 +49,59 @@
   explicit CXFA_FFDocView(CXFA_FFDoc* pDoc);
   ~CXFA_FFDocView();
 
-  CXFA_FFDoc* GetDoc() { return m_pDoc.Get(); }
-  int32_t StartLayout(int32_t iStartPage = 0);
+  CXFA_FFDoc* GetDoc() const { return m_pDoc.Get(); }
+  int32_t StartLayout();
   int32_t DoLayout();
   void StopLayout();
   int32_t GetLayoutStatus() const { return m_iStatus; }
+
   void UpdateDocView();
+  void UpdateUIDisplay(CXFA_Node* pNode, CXFA_FFWidget* pExcept);
+
   int32_t CountPageViews() const;
   CXFA_FFPageView* GetPageView(int32_t nIndex) const;
 
-  void ResetWidgetAcc(CXFA_WidgetAcc* pWidgetAcc);
-  int32_t ProcessWidgetEvent(CXFA_EventParam* pParam,
-                             CXFA_WidgetAcc* pWidgetAcc);
+  void ResetNode(CXFA_Node* pNode);
   CXFA_FFWidgetHandler* GetWidgetHandler();
-  std::unique_ptr<CXFA_WidgetAccIterator> CreateWidgetAccIterator();
+  std::unique_ptr<CXFA_ReadyNodeIterator> CreateReadyNodeIterator();
   CXFA_FFWidget* GetFocusWidget() const { return m_pFocusWidget.Get(); }
-  void KillFocus();
-  bool SetFocus(CXFA_FFWidget* hWidget);
+  bool SetFocus(CXFA_FFWidget* pNewFocus);
   CXFA_FFWidget* GetWidgetForNode(CXFA_Node* node);
   CXFA_FFWidget* GetWidgetByName(const WideString& wsName,
                                  CXFA_FFWidget* pRefWidget);
-  CXFA_WidgetAcc* GetWidgetAccByName(const WideString& wsName,
-                                     CXFA_WidgetAcc* pRefWidgetAcc);
   CXFA_LayoutProcessor* GetXFALayout() const;
-  void OnPageEvent(CXFA_ContainerLayoutItem* pSender, uint32_t dwEvent);
+  void OnPageEvent(CXFA_ViewLayoutItem* pSender, uint32_t dwEvent);
   void LockUpdate() { m_iLock++; }
   void UnlockUpdate() { m_iLock--; }
-  bool IsUpdateLocked() { return m_iLock > 0; }
-  void ClearInvalidateList() { m_mapPageInvalidate.clear(); }
-  void AddInvalidateRect(CXFA_FFWidget* pWidget, const CFX_RectF& rtInvalidate);
-  void AddInvalidateRect(CXFA_FFPageView* pPageView,
-                         const CFX_RectF& rtInvalidate);
-  void RunInvalidate();
+  void InvalidateRect(CXFA_FFPageView* pPageView,
+                      const CFX_RectF& rtInvalidate);
   void RunDocClose();
-  void DestroyDocView();
 
-  void ProcessValueChanged(CXFA_WidgetAcc* widgetAcc);
-
-  bool InitValidate(CXFA_Node* pNode);
-  bool RunValidate();
-
+  void ProcessValueChanged(CXFA_Node* node);
   void SetChangeMark();
 
-  void AddValidateWidget(CXFA_WidgetAcc* pWidget);
+  void AddValidateNode(CXFA_Node* node);
   void AddCalculateNodeNotify(CXFA_Node* pNodeChange);
-  void AddCalculateWidgetAcc(CXFA_WidgetAcc* pWidgetAcc);
-  int32_t RunCalculateWidgets();
-  bool IsStaticNotify() {
-    return m_pDoc->GetFormType() == FormType::kXFAForeground;
-  }
+  void AddCalculateNode(CXFA_Node* node);
+
   bool RunLayout();
-  void RunSubformIndexChange();
   void AddNewFormNode(CXFA_Node* pNode);
   void AddIndexChangedSubform(CXFA_Node* pNode);
-  CXFA_WidgetAcc* GetFocusWidgetAcc() const { return m_pFocusAcc.Get(); }
-  void SetFocusWidgetAcc(CXFA_WidgetAcc* pWidgetAcc);
+  CXFA_Node* GetFocusNode() const { return m_pFocusNode.Get(); }
+  void SetFocusNode(CXFA_Node* pNode);
   void DeleteLayoutItem(CXFA_FFWidget* pWidget);
-  int32_t ExecEventActivityByDeepFirst(CXFA_Node* pFormNode,
-                                       XFA_EVENTTYPE eEventType,
-                                       bool bIsFormReady,
-                                       bool bRecursive,
-                                       CXFA_Node* pExclude);
+  XFA_EventError ExecEventActivityByDeepFirst(CXFA_Node* pFormNode,
+                                              XFA_EVENTTYPE eEventType,
+                                              bool bIsFormReady,
+                                              bool bRecursive);
 
   void AddBindItem(CXFA_BindItems* item) { m_BindItems.push_back(item); }
 
-  bool m_bLayoutEvent;
+  bool m_bLayoutEvent = false;
+  bool m_bInLayoutStatus = false;
   std::vector<WideString> m_arrNullTestMsg;
-  CXFA_FFWidget* m_pListFocusWidget;
-  bool m_bInLayoutStatus;
+
+  void ResetLayoutProcessor() { m_pXFADocLayout.Release(); }
 
  private:
   bool RunEventLayoutReady();
@@ -121,23 +110,27 @@
   void InitLayout(CXFA_Node* pNode);
   size_t RunCalculateRecursive(size_t index);
   void ShowNullTestMsg();
-  bool ResetSingleWidgetAccData(CXFA_WidgetAcc* pWidgetAcc);
+  bool ResetSingleNodeData(CXFA_Node* pNode);
   CXFA_Subform* GetRootSubform();
 
+  bool IsUpdateLocked() const { return m_iLock > 0; }
+  bool InitValidate(CXFA_Node* pNode);
+  bool RunValidate();
+  XFA_EventError RunCalculateWidgets();
+  void RunSubformIndexChange();
+
   UnownedPtr<CXFA_FFDoc> const m_pDoc;
   std::unique_ptr<CXFA_FFWidgetHandler> m_pWidgetHandler;
-  CXFA_LayoutProcessor* m_pXFADocLayout;  // Not owned.
-  UnownedPtr<CXFA_WidgetAcc> m_pFocusAcc;
-  UnownedPtr<CXFA_FFWidget> m_pFocusWidget;
-  UnownedPtr<CXFA_FFWidget> m_pOldFocusWidget;
-  std::map<CXFA_FFPageView*, std::unique_ptr<CFX_RectF>> m_mapPageInvalidate;
-  std::vector<CXFA_WidgetAcc*> m_ValidateAccs;
-  std::vector<CXFA_WidgetAcc*> m_CalculateAccs;
-  std::vector<CXFA_BindItems*> m_BindItems;
-  std::vector<CXFA_Node*> m_NewAddedNodes;
-  std::vector<CXFA_Node*> m_IndexChangedSubforms;
-  XFA_DOCVIEW_LAYOUTSTATUS m_iStatus;
-  int32_t m_iLock;
+  UnownedPtr<CXFA_LayoutProcessor> m_pXFADocLayout;
+  UnownedPtr<CXFA_Node> m_pFocusNode;
+  ObservedPtr<CXFA_FFWidget> m_pFocusWidget;
+  std::deque<CXFA_Node*> m_ValidateNodes;
+  std::vector<CXFA_Node*> m_CalculateNodes;
+  std::deque<CXFA_BindItems*> m_BindItems;
+  std::deque<CXFA_Node*> m_NewAddedNodes;
+  std::deque<CXFA_Node*> m_IndexChangedSubforms;
+  XFA_DOCVIEW_LAYOUTSTATUS m_iStatus = XFA_DOCVIEW_LAYOUTSTATUS_None;
+  int32_t m_iLock = 0;
 };
 
 #endif  // XFA_FXFA_CXFA_FFDOCVIEW_H_
diff --git a/xfa/fxfa/cxfa_ffdraw.cpp b/xfa/fxfa/cxfa_ffdraw.cpp
deleted file mode 100644
index 420bde1..0000000
--- a/xfa/fxfa/cxfa_ffdraw.cpp
+++ /dev/null
@@ -1,16 +0,0 @@
-// Copyright 2014 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
-
-#include "xfa/fxfa/cxfa_ffdraw.h"
-
-#include "xfa/fxfa/cxfa_ffapp.h"
-#include "xfa/fxfa/cxfa_ffdoc.h"
-#include "xfa/fxfa/cxfa_ffpageview.h"
-#include "xfa/fxfa/cxfa_ffwidget.h"
-
-CXFA_FFDraw::CXFA_FFDraw(CXFA_Node* pNode) : CXFA_FFWidget(pNode) {}
-
-CXFA_FFDraw::~CXFA_FFDraw() {}
diff --git a/xfa/fxfa/cxfa_ffdraw.h b/xfa/fxfa/cxfa_ffdraw.h
deleted file mode 100644
index de9cfcf..0000000
--- a/xfa/fxfa/cxfa_ffdraw.h
+++ /dev/null
@@ -1,19 +0,0 @@
-// Copyright 2014 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_CXFA_FFDRAW_H_
-#define XFA_FXFA_CXFA_FFDRAW_H_
-
-#include "xfa/fxfa/cxfa_ffpageview.h"
-#include "xfa/fxfa/cxfa_ffwidget.h"
-
-class CXFA_FFDraw : public CXFA_FFWidget {
- public:
-  explicit CXFA_FFDraw(CXFA_Node* pNode);
-  ~CXFA_FFDraw() override;
-};
-
-#endif  // XFA_FXFA_CXFA_FFDRAW_H_
diff --git a/xfa/fxfa/cxfa_ffdropdown.cpp b/xfa/fxfa/cxfa_ffdropdown.cpp
new file mode 100644
index 0000000..4289dc1
--- /dev/null
+++ b/xfa/fxfa/cxfa_ffdropdown.cpp
@@ -0,0 +1,19 @@
+// Copyright 2018 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
+
+#include "xfa/fxfa/cxfa_ffdropdown.h"
+
+CXFA_FFDropDown::CXFA_FFDropDown(CXFA_Node* node) : CXFA_FFField(node) {}
+
+CXFA_FFDropDown::~CXFA_FFDropDown() = default;
+
+CXFA_FFComboBox* CXFA_FFDropDown::AsComboBox() {
+  return nullptr;
+}
+
+CXFA_FFDropDown* CXFA_FFDropDown::AsDropDown() {
+  return this;
+}
diff --git a/xfa/fxfa/cxfa_ffdropdown.h b/xfa/fxfa/cxfa_ffdropdown.h
new file mode 100644
index 0000000..b1751b4
--- /dev/null
+++ b/xfa/fxfa/cxfa_ffdropdown.h
@@ -0,0 +1,34 @@
+// Copyright 2018 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_CXFA_FFDROPDOWN_H_
+#define XFA_FXFA_CXFA_FFDROPDOWN_H_
+
+#include "core/fxcrt/widestring.h"
+#include "xfa/fxfa/cxfa_fffield.h"
+
+class CXFA_FFComboBox;
+
+class CXFA_FFDropDown : public CXFA_FFField {
+ public:
+  ~CXFA_FFDropDown() override;
+
+  // CXFA_FFField:
+  CXFA_FFDropDown* AsDropDown() override;
+
+  virtual void InsertItem(const WideString& wsLabel, int32_t nIndex) = 0;
+  virtual void DeleteItem(int32_t nIndex) = 0;
+  virtual CXFA_FFComboBox* AsComboBox();
+
+ protected:
+  explicit CXFA_FFDropDown(CXFA_Node* pNode);
+};
+
+inline CXFA_FFComboBox* ToComboBox(CXFA_FFDropDown* pDropDown) {
+  return pDropDown ? pDropDown->AsComboBox() : nullptr;
+}
+
+#endif  // XFA_FXFA_CXFA_FFDROPDOWN_H_
diff --git a/xfa/fxfa/cxfa_ffexclgroup.cpp b/xfa/fxfa/cxfa_ffexclgroup.cpp
index 318752b..dc0b4c7 100644
--- a/xfa/fxfa/cxfa_ffexclgroup.cpp
+++ b/xfa/fxfa/cxfa_ffexclgroup.cpp
@@ -17,12 +17,12 @@
 
 void CXFA_FFExclGroup::RenderWidget(CXFA_Graphics* pGS,
                                     const CFX_Matrix& matrix,
-                                    uint32_t dwStatus) {
-  if (!IsMatchVisibleStatus(dwStatus))
+                                    HighlightOption highlight) {
+  if (!HasVisibleStatus())
     return;
 
   CFX_Matrix mtRotate = GetRotateMatrix();
   mtRotate.Concat(matrix);
 
-  CXFA_FFWidget::RenderWidget(pGS, mtRotate, dwStatus);
+  CXFA_FFWidget::RenderWidget(pGS, mtRotate, highlight);
 }
diff --git a/xfa/fxfa/cxfa_ffexclgroup.h b/xfa/fxfa/cxfa_ffexclgroup.h
index b904301..a14e071 100644
--- a/xfa/fxfa/cxfa_ffexclgroup.h
+++ b/xfa/fxfa/cxfa_ffexclgroup.h
@@ -10,7 +10,7 @@
 #include "xfa/fxfa/cxfa_ffpageview.h"
 #include "xfa/fxfa/cxfa_ffwidget.h"
 
-class CXFA_FFExclGroup : public CXFA_FFWidget {
+class CXFA_FFExclGroup final : public CXFA_FFWidget {
  public:
   explicit CXFA_FFExclGroup(CXFA_Node* pNode);
   ~CXFA_FFExclGroup() override;
@@ -18,7 +18,7 @@
   // CXFA_FFWidget
   void RenderWidget(CXFA_Graphics* pGS,
                     const CFX_Matrix& matrix,
-                    uint32_t dwStatus) override;
+                    HighlightOption highlight) override;
 };
 
 #endif  // XFA_FXFA_CXFA_FFEXCLGROUP_H_
diff --git a/xfa/fxfa/cxfa_fffield.cpp b/xfa/fxfa/cxfa_fffield.cpp
index cd4359d..b031089 100644
--- a/xfa/fxfa/cxfa_fffield.cpp
+++ b/xfa/fxfa/cxfa_fffield.cpp
@@ -6,6 +6,11 @@
 
 #include "xfa/fxfa/cxfa_fffield.h"
 
+#include <algorithm>
+#include <utility>
+
+#include "core/fxge/render_defines.h"
+#include "third_party/base/ptr_util.h"
 #include "xfa/fwl/cfwl_edit.h"
 #include "xfa/fwl/cfwl_eventmouse.h"
 #include "xfa/fwl/cfwl_messagekey.h"
@@ -15,6 +20,7 @@
 #include "xfa/fwl/cfwl_messagesetfocus.h"
 #include "xfa/fwl/cfwl_picturebox.h"
 #include "xfa/fwl/cfwl_widgetmgr.h"
+#include "xfa/fwl/fwl_widgetdef.h"
 #include "xfa/fxfa/cxfa_ffapp.h"
 #include "xfa/fxfa/cxfa_ffdoc.h"
 #include "xfa/fxfa/cxfa_ffdocview.h"
@@ -31,68 +37,70 @@
 #include "xfa/fxgraphics/cxfa_gecolor.h"
 #include "xfa/fxgraphics/cxfa_gepath.h"
 
-namespace {
-
-CXFA_FFField* ToField(CXFA_LayoutItem* widget) {
-  return static_cast<CXFA_FFField*>(widget);
-}
-
-}  // namespace
-
 CXFA_FFField::CXFA_FFField(CXFA_Node* pNode) : CXFA_FFWidget(pNode) {}
 
-CXFA_FFField::~CXFA_FFField() {
-  CXFA_FFField::UnloadWidget();
+CXFA_FFField::~CXFA_FFField() = default;
+
+CXFA_FFDropDown* CXFA_FFField::AsDropDown() {
+  return nullptr;
 }
 
-CFX_RectF CXFA_FFField::GetBBox(uint32_t dwStatus, bool bDrawFocus) {
-  if (!bDrawFocus)
-    return CXFA_FFWidget::GetBBox(dwStatus);
+CXFA_FFField* CXFA_FFField::AsField() {
+  return this;
+}
 
-  XFA_Element type = m_pNode->GetWidgetAcc()->GetUIType();
-  if (type != XFA_Element::Button && type != XFA_Element::CheckButton &&
-      type != XFA_Element::ImageEdit && type != XFA_Element::Signature &&
-      type != XFA_Element::ChoiceList) {
-    return CFX_RectF();
+CFX_RectF CXFA_FFField::GetBBox(FocusOption focus) {
+  if (focus == kDoNotDrawFocus)
+    return CXFA_FFWidget::GetBBox(kDoNotDrawFocus);
+
+  switch (m_pNode->GetFFWidgetType()) {
+    case XFA_FFWidgetType::kButton:
+    case XFA_FFWidgetType::kCheckButton:
+    case XFA_FFWidgetType::kImageEdit:
+    case XFA_FFWidgetType::kSignature:
+    case XFA_FFWidgetType::kChoiceList:
+      return GetRotateMatrix().TransformRect(m_rtUI);
+    default:
+      return CFX_RectF();
   }
-
-  return GetRotateMatrix().TransformRect(m_rtUI);
 }
 
 void CXFA_FFField::RenderWidget(CXFA_Graphics* pGS,
                                 const CFX_Matrix& matrix,
-                                uint32_t dwStatus) {
-  if (!IsMatchVisibleStatus(dwStatus))
+                                HighlightOption highlight) {
+  if (!HasVisibleStatus())
     return;
 
   CFX_Matrix mtRotate = GetRotateMatrix();
   mtRotate.Concat(matrix);
 
-  CXFA_FFWidget::RenderWidget(pGS, mtRotate, dwStatus);
-  DrawBorder(pGS, m_pNode->GetWidgetAcc()->GetUIBorder(), m_rtUI, mtRotate);
+  CXFA_FFWidget::RenderWidget(pGS, mtRotate, highlight);
+  DrawBorder(pGS, m_pNode->GetUIBorder(), m_rtUI, mtRotate);
   RenderCaption(pGS, &mtRotate);
-  DrawHighlight(pGS, &mtRotate, dwStatus, false);
+  DrawHighlight(pGS, &mtRotate, highlight, kSquareShape);
 
-  CFX_RectF rtWidget = m_pNormalWidget->GetWidgetRect();
+  CFX_RectF rtWidget = GetNormalWidget()->GetWidgetRect();
   CFX_Matrix mt(1, 0, 0, 1, rtWidget.left, rtWidget.top);
   mt.Concat(mtRotate);
-  GetApp()->GetFWLWidgetMgr()->OnDrawWidget(m_pNormalWidget.get(), pGS, mt);
+  GetApp()->GetFWLWidgetMgr()->OnDrawWidget(GetNormalWidget(), pGS, mt);
 }
 
 void CXFA_FFField::DrawHighlight(CXFA_Graphics* pGS,
                                  CFX_Matrix* pMatrix,
-                                 uint32_t dwStatus,
-                                 bool bEllipse) {
-  if (m_rtUI.IsEmpty() || !GetDoc()->GetXFADoc()->IsInteractive())
-    return;
-  if (!(dwStatus & XFA_WidgetStatus_Highlight) || !m_pNode->IsOpenAccess())
+                                 HighlightOption highlight,
+                                 ShapeOption shape) {
+  if (highlight == kNoHighlight)
     return;
 
+  if (m_rtUI.IsEmpty() || !GetDoc()->GetXFADoc()->IsInteractive() ||
+      !m_pNode->IsOpenAccess()) {
+    return;
+  }
   CXFA_FFDoc* pDoc = GetDoc();
   pGS->SetFillColor(
       CXFA_GEColor(pDoc->GetDocEnvironment()->GetHighlightColor(pDoc)));
   CXFA_GEPath path;
-  if (bEllipse)
+  if (shape == kRoundShape)
     path.AddEllipse(m_rtUI);
   else
     path.AddRectangle(m_rtUI.left, m_rtUI.top, m_rtUI.width, m_rtUI.height);
@@ -101,13 +109,13 @@
 }
 
 void CXFA_FFField::DrawFocus(CXFA_Graphics* pGS, CFX_Matrix* pMatrix) {
-  if (!(m_dwStatus & XFA_WidgetStatus_Focused))
+  if (!GetLayoutItem()->TestStatusBits(XFA_WidgetStatus_Focused))
     return;
 
   pGS->SetStrokeColor(CXFA_GEColor(0xFF000000));
 
-  float DashPattern[2] = {1, 1};
-  pGS->SetLineDash(0.0f, DashPattern, 2);
+  static constexpr float kDashPattern[2] = {1, 1};
+  pGS->SetLineDash(0.0f, kDashPattern, FX_ArraySize(kDashPattern));
   pGS->SetLineWidth(0);
 
   CXFA_GEPath path;
@@ -116,45 +124,53 @@
 }
 
 void CXFA_FFField::SetFWLThemeProvider() {
-  if (m_pNormalWidget)
-    m_pNormalWidget->SetThemeProvider(GetApp()->GetFWLTheme());
+  if (GetNormalWidget())
+    GetNormalWidget()->SetThemeProvider(GetApp()->GetFWLTheme(GetDoc()));
+}
+
+CFWL_Widget* CXFA_FFField::GetNormalWidget() {
+  return m_pNormalWidget.get();
+}
+
+const CFWL_Widget* CXFA_FFField::GetNormalWidget() const {
+  return m_pNormalWidget.get();
+}
+
+void CXFA_FFField::SetNormalWidget(std::unique_ptr<CFWL_Widget> widget) {
+  m_pNormalWidget = std::move(widget);
 }
 
 bool CXFA_FFField::IsLoaded() {
-  return m_pNormalWidget && CXFA_FFWidget::IsLoaded();
+  return GetNormalWidget() && CXFA_FFWidget::IsLoaded();
 }
 
 bool CXFA_FFField::LoadWidget() {
   SetFWLThemeProvider();
-  m_pNode->GetWidgetAcc()->LoadCaption(GetDoc());
+  m_pNode->LoadCaption(GetDoc());
   PerformLayout();
   return true;
 }
 
-void CXFA_FFField::UnloadWidget() {
-  m_pNormalWidget.reset();
-}
-
 void CXFA_FFField::SetEditScrollOffset() {
-  XFA_Element eType = m_pNode->GetWidgetAcc()->GetUIType();
-  if (eType != XFA_Element::TextEdit && eType != XFA_Element::NumericEdit &&
-      eType != XFA_Element::PasswordEdit) {
+  XFA_FFWidgetType eType = m_pNode->GetFFWidgetType();
+  if (eType != XFA_FFWidgetType::kTextEdit &&
+      eType != XFA_FFWidgetType::kNumericEdit &&
+      eType != XFA_FFWidgetType::kPasswordEdit) {
     return;
   }
 
   float fScrollOffset = 0;
-  CXFA_FFField* pPrev = ToField(GetPrev());
-  if (pPrev) {
-    CFX_RectF rtMargin = m_pNode->GetWidgetAcc()->GetUIMargin();
-    fScrollOffset = -rtMargin.top;
-  }
+  CXFA_ContentLayoutItem* pItem = GetLayoutItem()->GetPrev();
+  CXFA_FFField* pPrev = pItem ? ToField(pItem->GetFFWidget()) : nullptr;
+  if (pPrev)
+    fScrollOffset = -(m_pNode->GetUIMargin().top);
 
   while (pPrev) {
     fScrollOffset += pPrev->m_rtUI.height;
-    pPrev = ToField(pPrev->GetPrev());
+    pItem = pPrev->GetLayoutItem()->GetPrev();
+    pPrev = pItem ? ToField(pItem->GetFFWidget()) : nullptr;
   }
-  static_cast<CFWL_Edit*>(m_pNormalWidget.get())
-      ->SetScrollOffset(fScrollOffset);
+  static_cast<CFWL_Edit*>(GetNormalWidget())->SetScrollOffset(fScrollOffset);
 }
 
 bool CXFA_FFField::PerformLayout() {
@@ -163,8 +179,8 @@
   LayoutCaption();
   SetFWLRect();
   SetEditScrollOffset();
-  if (m_pNormalWidget)
-    m_pNormalWidget->Update();
+  if (GetNormalWidget())
+    GetNormalWidget()->Update();
   return true;
 }
 
@@ -172,7 +188,7 @@
   CFX_RectF rtWidget = GetRectWithoutRotate();
   CXFA_Margin* margin = m_pNode->GetMarginIfExists();
   if (margin) {
-    CXFA_LayoutItem* pItem = this;
+    CXFA_ContentLayoutItem* pItem = GetLayoutItem();
     float fLeftInset = margin->GetLeftInset();
     float fRightInset = margin->GetRightInset();
     float fTopInset = margin->GetTopInset();
@@ -189,18 +205,25 @@
     }
   }
 
-  XFA_AttributeEnum iCapPlacement = XFA_AttributeEnum::Unknown;
+  XFA_AttributeValue iCapPlacement = XFA_AttributeValue::Unknown;
   float fCapReserve = 0;
   CXFA_Caption* caption = m_pNode->GetCaptionIfExists();
   if (caption && !caption->IsHidden()) {
     iCapPlacement = caption->GetPlacementType();
-    if (iCapPlacement == XFA_AttributeEnum::Top && GetPrev()) {
-      m_rtCaption.Reset();
-    } else if (iCapPlacement == XFA_AttributeEnum::Bottom && GetNext()) {
-      m_rtCaption.Reset();
+    if ((iCapPlacement == XFA_AttributeValue::Top &&
+         GetLayoutItem()->GetPrev()) ||
+        (iCapPlacement == XFA_AttributeValue::Bottom &&
+         GetLayoutItem()->GetNext())) {
+      m_rtCaption = CFX_RectF();
     } else {
       fCapReserve = caption->GetReserve();
-      CXFA_LayoutItem* pItem = this;
+      if (iCapPlacement == XFA_AttributeValue::Top ||
+          iCapPlacement == XFA_AttributeValue::Bottom) {
+        fCapReserve = std::min(fCapReserve, rtWidget.height);
+      } else {
+        fCapReserve = std::min(fCapReserve, rtWidget.width);
+      }
+      CXFA_ContentLayoutItem* pItem = GetLayoutItem();
       if (!pItem->GetPrev() && !pItem->GetNext()) {
         m_rtCaption = rtWidget;
       } else {
@@ -211,17 +234,16 @@
           m_rtCaption.height += pItem->GetRect(false).Height();
           pItem = pItem->GetNext();
         }
-        XFA_RectWithoutMargin(m_rtCaption, margin);
+        XFA_RectWithoutMargin(&m_rtCaption, margin);
       }
 
-      CXFA_TextLayout* pCapTextLayout =
-          m_pNode->GetWidgetAcc()->GetCaptionTextLayout();
+      CXFA_TextLayout* pCapTextLayout = m_pNode->GetCaptionTextLayout();
       if (fCapReserve <= 0 && pCapTextLayout) {
         CFX_SizeF minSize;
         CFX_SizeF maxSize;
         CFX_SizeF size = pCapTextLayout->CalcSize(minSize, maxSize);
-        if (iCapPlacement == XFA_AttributeEnum::Top ||
-            iCapPlacement == XFA_AttributeEnum::Bottom) {
+        if (iCapPlacement == XFA_AttributeValue::Top ||
+            iCapPlacement == XFA_AttributeValue::Bottom) {
           fCapReserve = size.height;
         } else {
           fCapReserve = size.width;
@@ -233,56 +255,55 @@
   m_rtUI = rtWidget;
   CXFA_Margin* capMargin = caption ? caption->GetMarginIfExists() : nullptr;
   switch (iCapPlacement) {
-    case XFA_AttributeEnum::Left: {
+    case XFA_AttributeValue::Left: {
       m_rtCaption.width = fCapReserve;
       CapLeftRightPlacement(capMargin, rtWidget, iCapPlacement);
       m_rtUI.width -= fCapReserve;
       m_rtUI.left += fCapReserve;
       break;
     }
-    case XFA_AttributeEnum::Top: {
+    case XFA_AttributeValue::Top: {
       m_rtCaption.height = fCapReserve;
       CapTopBottomPlacement(capMargin, rtWidget, iCapPlacement);
       m_rtUI.top += fCapReserve;
       m_rtUI.height -= fCapReserve;
       break;
     }
-    case XFA_AttributeEnum::Right: {
+    case XFA_AttributeValue::Right: {
       m_rtCaption.left = m_rtCaption.right() - fCapReserve;
       m_rtCaption.width = fCapReserve;
       CapLeftRightPlacement(capMargin, rtWidget, iCapPlacement);
       m_rtUI.width -= fCapReserve;
       break;
     }
-    case XFA_AttributeEnum::Bottom: {
+    case XFA_AttributeValue::Bottom: {
       m_rtCaption.top = m_rtCaption.bottom() - fCapReserve;
       m_rtCaption.height = fCapReserve;
       CapTopBottomPlacement(capMargin, rtWidget, iCapPlacement);
       m_rtUI.height -= fCapReserve;
       break;
     }
-    case XFA_AttributeEnum::Inline:
+    case XFA_AttributeValue::Inline:
       break;
     default:
       break;
   }
 
-  CXFA_Border* borderUI = m_pNode->GetWidgetAcc()->GetUIBorder();
+  CXFA_Border* borderUI = m_pNode->GetUIBorder();
   if (borderUI) {
     CXFA_Margin* borderMargin = borderUI->GetMarginIfExists();
-    if (borderMargin)
-      XFA_RectWithoutMargin(m_rtUI, borderMargin);
+    XFA_RectWithoutMargin(&m_rtUI, borderMargin);
   }
   m_rtUI.Normalize();
 }
 
 void CXFA_FFField::CapTopBottomPlacement(const CXFA_Margin* margin,
                                          const CFX_RectF& rtWidget,
-                                         XFA_AttributeEnum iCapPlacement) {
-  CFX_RectF rtUIMargin = m_pNode->GetWidgetAcc()->GetUIMargin();
+                                         XFA_AttributeValue iCapPlacement) {
+  CFX_RectF rtUIMargin = m_pNode->GetUIMargin();
   m_rtCaption.left += rtUIMargin.left;
   if (margin) {
-    XFA_RectWithoutMargin(m_rtCaption, margin);
+    XFA_RectWithoutMargin(&m_rtCaption, margin);
     if (m_rtCaption.height < 0)
       m_rtCaption.top += m_rtCaption.height;
   }
@@ -297,19 +318,19 @@
     m_rtCaption.top += rtUIMargin.top + rtUIMargin.height;
   } else if (fHeight > rtWidget.height) {
     m_rtUI.height += fHeight - rtWidget.height;
-    if (iCapPlacement == XFA_AttributeEnum::Bottom)
+    if (iCapPlacement == XFA_AttributeValue::Bottom)
       m_rtCaption.top += fHeight - rtWidget.height;
   }
 }
 
 void CXFA_FFField::CapLeftRightPlacement(const CXFA_Margin* margin,
                                          const CFX_RectF& rtWidget,
-                                         XFA_AttributeEnum iCapPlacement) {
-  CFX_RectF rtUIMargin = m_pNode->GetWidgetAcc()->GetUIMargin();
+                                         XFA_AttributeValue iCapPlacement) {
+  CFX_RectF rtUIMargin = m_pNode->GetUIMargin();
   m_rtCaption.top += rtUIMargin.top;
   m_rtCaption.height -= rtUIMargin.top;
   if (margin) {
-    XFA_RectWithoutMargin(m_rtCaption, margin);
+    XFA_RectWithoutMargin(&m_rtCaption, margin);
     if (m_rtCaption.height < 0)
       m_rtCaption.top += m_rtCaption.height;
   }
@@ -318,7 +339,7 @@
   float fHeight = rtUIMargin.top + rtUIMargin.height;
   if (fWidth > rtWidget.width) {
     m_rtUI.width += fWidth - rtWidget.width;
-    if (iCapPlacement == XFA_AttributeEnum::Right)
+    if (iCapPlacement == XFA_AttributeValue::Right)
       m_rtCaption.left += fWidth - rtWidget.width;
   }
 
@@ -331,244 +352,241 @@
 }
 
 void CXFA_FFField::UpdateFWL() {
-  if (m_pNormalWidget)
-    m_pNormalWidget->Update();
+  if (GetNormalWidget())
+    GetNormalWidget()->Update();
 }
 
 uint32_t CXFA_FFField::UpdateUIProperty() {
-  CXFA_Node* pUiNode = m_pNode->GetWidgetAcc()->GetUIChild();
+  CXFA_Node* pUiNode = m_pNode->GetUIChildNode();
   if (pUiNode && pUiNode->GetElementType() == XFA_Element::DefaultUi)
     return FWL_STYLEEXT_EDT_ReadOnly;
   return 0;
 }
 
 void CXFA_FFField::SetFWLRect() {
-  if (!m_pNormalWidget)
+  if (!GetNormalWidget())
     return;
 
   CFX_RectF rtUi = m_rtUI;
-  if (rtUi.width < 1.0)
-    rtUi.width = 1.0;
+  rtUi.width = std::max(rtUi.width, 1.0f);
   if (!GetDoc()->GetXFADoc()->IsInteractive()) {
     float fFontSize = m_pNode->GetFontSize();
-    if (rtUi.height < fFontSize)
-      rtUi.height = fFontSize;
+    rtUi.height = std::max(rtUi.height, fFontSize);
   }
-  m_pNormalWidget->SetWidgetRect(rtUi);
+  GetNormalWidget()->SetWidgetRect(rtUi);
 }
 
 bool CXFA_FFField::OnMouseEnter() {
-  if (!m_pNormalWidget)
+  if (!GetNormalWidget())
     return false;
 
-  CFWL_MessageMouse ms(nullptr, m_pNormalWidget.get());
-  ms.m_dwCmd = FWL_MouseCommand::Enter;
-  TranslateFWLMessage(&ms);
-  return true;
+  ObservedPtr<CXFA_FFField> pWatched(this);
+  SendMessageToFWLWidget(pdfium::MakeUnique<CFWL_MessageMouse>(
+      GetNormalWidget(), FWL_MouseCommand::Enter));
+
+  return !!pWatched;
 }
 
 bool CXFA_FFField::OnMouseExit() {
-  if (!m_pNormalWidget)
+  if (!GetNormalWidget())
     return false;
 
-  CFWL_MessageMouse ms(nullptr, m_pNormalWidget.get());
-  ms.m_dwCmd = FWL_MouseCommand::Leave;
-  TranslateFWLMessage(&ms);
-  return true;
+  ObservedPtr<CXFA_FFField> pWatched(this);
+  SendMessageToFWLWidget(pdfium::MakeUnique<CFWL_MessageMouse>(
+      GetNormalWidget(), FWL_MouseCommand::Leave));
+
+  return !!pWatched;
 }
 
 CFX_PointF CXFA_FFField::FWLToClient(const CFX_PointF& point) {
-  return m_pNormalWidget ? point - m_pNormalWidget->GetWidgetRect().TopLeft()
-                         : point;
+  return GetNormalWidget()
+             ? point - GetNormalWidget()->GetWidgetRect().TopLeft()
+             : point;
 }
 
-bool CXFA_FFField::OnLButtonDown(uint32_t dwFlags, const CFX_PointF& point) {
-  if (!m_pNormalWidget)
+bool CXFA_FFField::AcceptsFocusOnButtonDown(uint32_t dwFlags,
+                                            const CFX_PointF& point,
+                                            FWL_MouseCommand command) {
+  if (!GetNormalWidget())
     return false;
   if (!m_pNode->IsOpenAccess() || !GetDoc()->GetXFADoc()->IsInteractive())
     return false;
   if (!PtInActiveRect(point))
     return false;
 
-  SetButtonDown(true);
-  CFWL_MessageMouse ms(nullptr, m_pNormalWidget.get());
-  ms.m_dwCmd = FWL_MouseCommand::LeftButtonDown;
-  ms.m_dwFlags = dwFlags;
-  ms.m_pos = FWLToClient(point);
-  TranslateFWLMessage(&ms);
   return true;
 }
 
+bool CXFA_FFField::OnLButtonDown(uint32_t dwFlags, const CFX_PointF& point) {
+  ObservedPtr<CXFA_FFField> pWatched(this);
+  SetButtonDown(true);
+  SendMessageToFWLWidget(pdfium::MakeUnique<CFWL_MessageMouse>(
+      GetNormalWidget(), FWL_MouseCommand::LeftButtonDown, dwFlags,
+      FWLToClient(point)));
+
+  return !!pWatched;
+}
+
 bool CXFA_FFField::OnLButtonUp(uint32_t dwFlags, const CFX_PointF& point) {
-  if (!m_pNormalWidget)
+  if (!GetNormalWidget())
     return false;
   if (!IsButtonDown())
     return false;
 
+  ObservedPtr<CXFA_FFField> pWatched(this);
   SetButtonDown(false);
-  CFWL_MessageMouse ms(nullptr, m_pNormalWidget.get());
-  ms.m_dwCmd = FWL_MouseCommand::LeftButtonUp;
-  ms.m_dwFlags = dwFlags;
-  ms.m_pos = FWLToClient(point);
-  TranslateFWLMessage(&ms);
-  return true;
+  SendMessageToFWLWidget(pdfium::MakeUnique<CFWL_MessageMouse>(
+      GetNormalWidget(), FWL_MouseCommand::LeftButtonUp, dwFlags,
+      FWLToClient(point)));
+
+  return !!pWatched;
 }
 
 bool CXFA_FFField::OnLButtonDblClk(uint32_t dwFlags, const CFX_PointF& point) {
-  if (!m_pNormalWidget)
+  if (!GetNormalWidget())
     return false;
 
-  CFWL_MessageMouse ms(nullptr, m_pNormalWidget.get());
-  ms.m_dwCmd = FWL_MouseCommand::LeftButtonDblClk;
-  ms.m_dwFlags = dwFlags;
-  ms.m_pos = FWLToClient(point);
-  TranslateFWLMessage(&ms);
-  return true;
+  ObservedPtr<CXFA_FFField> pWatched(this);
+  SendMessageToFWLWidget(pdfium::MakeUnique<CFWL_MessageMouse>(
+      GetNormalWidget(), FWL_MouseCommand::LeftButtonDblClk, dwFlags,
+      FWLToClient(point)));
+
+  return !!pWatched;
 }
 
 bool CXFA_FFField::OnMouseMove(uint32_t dwFlags, const CFX_PointF& point) {
-  if (!m_pNormalWidget)
+  if (!GetNormalWidget())
     return false;
 
-  CFWL_MessageMouse ms(nullptr, m_pNormalWidget.get());
-  ms.m_dwCmd = FWL_MouseCommand::Move;
-  ms.m_dwFlags = dwFlags;
-  ms.m_pos = FWLToClient(point);
-  TranslateFWLMessage(&ms);
-  return true;
+  ObservedPtr<CXFA_FFField> pWatched(this);
+  SendMessageToFWLWidget(pdfium::MakeUnique<CFWL_MessageMouse>(
+      GetNormalWidget(), FWL_MouseCommand::Move, dwFlags, FWLToClient(point)));
+
+  return !!pWatched;
 }
 
 bool CXFA_FFField::OnMouseWheel(uint32_t dwFlags,
                                 int16_t zDelta,
                                 const CFX_PointF& point) {
-  if (!m_pNormalWidget)
+  if (!GetNormalWidget())
     return false;
 
-  CFWL_MessageMouseWheel ms(nullptr, m_pNormalWidget.get());
-  ms.m_dwFlags = dwFlags;
-  ms.m_pos = FWLToClient(point);
-  ms.m_delta = CFX_PointF(zDelta, 0);
-  TranslateFWLMessage(&ms);
-  return true;
+  ObservedPtr<CXFA_FFField> pWatched(this);
+  SendMessageToFWLWidget(pdfium::MakeUnique<CFWL_MessageMouseWheel>(
+      GetNormalWidget(), dwFlags, FWLToClient(point), CFX_PointF(zDelta, 0)));
+
+  return !!pWatched;
 }
 
 bool CXFA_FFField::OnRButtonDown(uint32_t dwFlags, const CFX_PointF& point) {
-  if (!m_pNormalWidget)
-    return false;
-  if (!m_pNode->IsOpenAccess() || !GetDoc()->GetXFADoc()->IsInteractive())
-    return false;
-  if (!PtInActiveRect(point))
-    return false;
-
+  ObservedPtr<CXFA_FFField> pWatched(this);
   SetButtonDown(true);
+  SendMessageToFWLWidget(pdfium::MakeUnique<CFWL_MessageMouse>(
+      GetNormalWidget(), FWL_MouseCommand::RightButtonDown, dwFlags,
+      FWLToClient(point)));
 
-  CFWL_MessageMouse ms(nullptr, m_pNormalWidget.get());
-  ms.m_dwCmd = FWL_MouseCommand::RightButtonDown;
-  ms.m_dwFlags = dwFlags;
-  ms.m_pos = FWLToClient(point);
-  TranslateFWLMessage(&ms);
-  return true;
+  return !!pWatched;
 }
 
 bool CXFA_FFField::OnRButtonUp(uint32_t dwFlags, const CFX_PointF& point) {
-  if (!m_pNormalWidget)
+  if (!GetNormalWidget())
     return false;
   if (!IsButtonDown())
     return false;
 
+  ObservedPtr<CXFA_FFField> pWatched(this);
   SetButtonDown(false);
-  CFWL_MessageMouse ms(nullptr, m_pNormalWidget.get());
-  ms.m_dwCmd = FWL_MouseCommand::RightButtonUp;
-  ms.m_dwFlags = dwFlags;
-  ms.m_pos = FWLToClient(point);
-  TranslateFWLMessage(&ms);
-  return true;
+  SendMessageToFWLWidget(pdfium::MakeUnique<CFWL_MessageMouse>(
+      GetNormalWidget(), FWL_MouseCommand::RightButtonUp, dwFlags,
+      FWLToClient(point)));
+
+  return !!pWatched;
 }
 
 bool CXFA_FFField::OnRButtonDblClk(uint32_t dwFlags, const CFX_PointF& point) {
-  if (!m_pNormalWidget)
+  if (!GetNormalWidget())
     return false;
 
-  CFWL_MessageMouse ms(nullptr, m_pNormalWidget.get());
-  ms.m_dwCmd = FWL_MouseCommand::RightButtonDblClk;
-  ms.m_dwFlags = dwFlags;
-  ms.m_pos = FWLToClient(point);
-  TranslateFWLMessage(&ms);
-  return true;
+  ObservedPtr<CXFA_FFField> pWatched(this);
+  SendMessageToFWLWidget(pdfium::MakeUnique<CFWL_MessageMouse>(
+      GetNormalWidget(), FWL_MouseCommand::RightButtonDblClk, dwFlags,
+      FWLToClient(point)));
+
+  return !!pWatched;
 }
 
 bool CXFA_FFField::OnSetFocus(CXFA_FFWidget* pOldWidget) {
-  CXFA_FFWidget::OnSetFocus(pOldWidget);
-  if (!m_pNormalWidget)
+  if (!CXFA_FFWidget::OnSetFocus(pOldWidget))
     return false;
 
-  CFWL_MessageSetFocus ms(nullptr, m_pNormalWidget.get());
-  TranslateFWLMessage(&ms);
-  m_dwStatus |= XFA_WidgetStatus_Focused;
-  AddInvalidateRect();
-  return true;
+  if (!GetNormalWidget())
+    return false;
+
+  ObservedPtr<CXFA_FFField> pWatched(this);
+  SendMessageToFWLWidget(
+      pdfium::MakeUnique<CFWL_MessageSetFocus>(nullptr, GetNormalWidget()));
+  GetLayoutItem()->SetStatusBits(XFA_WidgetStatus_Focused);
+  InvalidateRect();
+
+  return !!pWatched;
 }
 
 bool CXFA_FFField::OnKillFocus(CXFA_FFWidget* pNewWidget) {
-  if (!m_pNormalWidget)
-    return CXFA_FFWidget::OnKillFocus(pNewWidget);
-
-  CFWL_MessageKillFocus ms(nullptr, m_pNormalWidget.get());
-  TranslateFWLMessage(&ms);
-  m_dwStatus &= ~XFA_WidgetStatus_Focused;
-  AddInvalidateRect();
-  CXFA_FFWidget::OnKillFocus(pNewWidget);
-  return true;
+  ObservedPtr<CXFA_FFField> pWatched(this);
+  ObservedPtr<CXFA_FFWidget> pNewWatched(pNewWidget);
+  if (GetNormalWidget()) {
+    SendMessageToFWLWidget(
+        pdfium::MakeUnique<CFWL_MessageKillFocus>(nullptr, GetNormalWidget()));
+    GetLayoutItem()->ClearStatusBits(XFA_WidgetStatus_Focused);
+    InvalidateRect();
+  }
+  return pWatched && pNewWatched &&
+         CXFA_FFWidget::OnKillFocus(pNewWatched.Get());
 }
 
 bool CXFA_FFField::OnKeyDown(uint32_t dwKeyCode, uint32_t dwFlags) {
-  if (!m_pNormalWidget || !GetDoc()->GetXFADoc()->IsInteractive())
+  if (!GetNormalWidget() || !GetDoc()->GetXFADoc()->IsInteractive())
     return false;
 
-  CFWL_MessageKey ms(nullptr, m_pNormalWidget.get());
-  ms.m_dwCmd = FWL_KeyCommand::KeyDown;
-  ms.m_dwFlags = dwFlags;
-  ms.m_dwKeyCode = dwKeyCode;
-  TranslateFWLMessage(&ms);
-  return true;
+  ObservedPtr<CXFA_FFField> pWatched(this);
+  SendMessageToFWLWidget(pdfium::MakeUnique<CFWL_MessageKey>(
+      GetNormalWidget(), FWL_KeyCommand::KeyDown, dwFlags, dwKeyCode));
+
+  return !!pWatched;
 }
 
 bool CXFA_FFField::OnKeyUp(uint32_t dwKeyCode, uint32_t dwFlags) {
-  if (!m_pNormalWidget || !GetDoc()->GetXFADoc()->IsInteractive())
+  if (!GetNormalWidget() || !GetDoc()->GetXFADoc()->IsInteractive())
     return false;
 
-  CFWL_MessageKey ms(nullptr, m_pNormalWidget.get());
-  ms.m_dwCmd = FWL_KeyCommand::KeyUp;
-  ms.m_dwFlags = dwFlags;
-  ms.m_dwKeyCode = dwKeyCode;
-  TranslateFWLMessage(&ms);
-  return true;
+  ObservedPtr<CXFA_FFField> pWatched(this);
+  SendMessageToFWLWidget(pdfium::MakeUnique<CFWL_MessageKey>(
+      GetNormalWidget(), FWL_KeyCommand::KeyUp, dwFlags, dwKeyCode));
+
+  return !!pWatched;
 }
 
 bool CXFA_FFField::OnChar(uint32_t dwChar, uint32_t dwFlags) {
   if (!GetDoc()->GetXFADoc()->IsInteractive())
     return false;
-  if (dwChar == FWL_VKEY_Tab)
+  if (dwChar == XFA_FWL_VKEY_Tab)
     return true;
-  if (!m_pNormalWidget)
+  if (!GetNormalWidget())
     return false;
   if (!m_pNode->IsOpenAccess())
     return false;
 
-  CFWL_MessageKey ms(nullptr, m_pNormalWidget.get());
-  ms.m_dwCmd = FWL_KeyCommand::Char;
-  ms.m_dwFlags = dwFlags;
-  ms.m_dwKeyCode = dwChar;
-  TranslateFWLMessage(&ms);
-  return true;
+  ObservedPtr<CXFA_FFField> pWatched(this);
+  SendMessageToFWLWidget(pdfium::MakeUnique<CFWL_MessageKey>(
+      GetNormalWidget(), FWL_KeyCommand::Char, dwFlags, dwChar));
+
+  return !!pWatched;
 }
 
-FWL_WidgetHit CXFA_FFField::OnHitTest(const CFX_PointF& point) {
-  if (m_pNormalWidget &&
-      m_pNormalWidget->HitTest(FWLToClient(point)) != FWL_WidgetHit::Unknown) {
+FWL_WidgetHit CXFA_FFField::HitTest(const CFX_PointF& point) {
+  auto* pNorm = GetNormalWidget();
+  if (pNorm && pNorm->HitTest(FWLToClient(point)) != FWL_WidgetHit::Unknown)
     return FWL_WidgetHit::Client;
-  }
-
   if (!GetRectWithoutRotate().Contains(point))
     return FWL_WidgetHit::Unknown;
   if (m_rtCaption.Contains(point))
@@ -581,24 +599,21 @@
 }
 
 bool CXFA_FFField::PtInActiveRect(const CFX_PointF& point) {
-  return m_pNormalWidget && m_pNormalWidget->GetWidgetRect().Contains(point);
+  return GetNormalWidget() &&
+         GetNormalWidget()->GetWidgetRect().Contains(point);
 }
 
 void CXFA_FFField::LayoutCaption() {
-  CXFA_TextLayout* pCapTextLayout =
-      m_pNode->GetWidgetAcc()->GetCaptionTextLayout();
+  CXFA_TextLayout* pCapTextLayout = m_pNode->GetCaptionTextLayout();
   if (!pCapTextLayout)
     return;
 
-  float fHeight =
-      pCapTextLayout->Layout(CFX_SizeF(m_rtCaption.width, m_rtCaption.height));
-  if (m_rtCaption.height < fHeight)
-    m_rtCaption.height = fHeight;
+  float fHeight = pCapTextLayout->Layout(m_rtCaption.Size());
+  m_rtCaption.height = std::max(m_rtCaption.height, fHeight);
 }
 
 void CXFA_FFField::RenderCaption(CXFA_Graphics* pGS, CFX_Matrix* pMatrix) {
-  CXFA_TextLayout* pCapTextLayout =
-      m_pNode->GetWidgetAcc()->GetCaptionTextLayout();
+  CXFA_TextLayout* pCapTextLayout = m_pNode->GetCaptionTextLayout();
   if (!pCapTextLayout)
     return;
 
@@ -607,7 +622,7 @@
     return;
 
   if (!pCapTextLayout->IsLoaded())
-    pCapTextLayout->Layout(CFX_SizeF(m_rtCaption.width, m_rtCaption.height));
+    pCapTextLayout->Layout(m_rtCaption.Size());
 
   CFX_RectF rtClip = m_rtCaption;
   rtClip.Intersect(GetRectWithoutRotate());
@@ -625,95 +640,92 @@
     return false;
   if (!IsDataChanged())
     return false;
-  if (CalculateOverride() != 1)
-    return false;
-  if (!CommitData())
-    return false;
 
   m_pDocView->SetChangeMark();
-  m_pDocView->AddValidateWidget(m_pNode->GetWidgetAcc());
-  return true;
+  m_pDocView->AddValidateNode(m_pNode.Get());
+
+  if (CalculateOverride() != 1)
+    return false;
+  return CommitData();
 }
 
 int32_t CXFA_FFField::CalculateOverride() {
   CXFA_Node* exclNode = m_pNode->GetExclGroupIfExists();
-  if (!exclNode)
-    return CalculateWidgetAcc(m_pNode->GetWidgetAcc());
-
-  CXFA_WidgetAcc* pAcc = exclNode->GetWidgetAcc();
-  if (!pAcc)
-    return CalculateWidgetAcc(m_pNode->GetWidgetAcc());
-  if (CalculateWidgetAcc(pAcc) == 0)
+  if (!exclNode || !exclNode->IsWidgetReady())
+    return CalculateNode(m_pNode.Get());
+  if (CalculateNode(exclNode) == 0)
     return 0;
 
-  CXFA_Node* pNode = pAcc->GetExclGroupFirstMember();
+  CXFA_Node* pNode = exclNode->GetExclGroupFirstMember();
   if (!pNode)
     return 1;
 
-  CXFA_WidgetAcc* pWidgetAcc = nullptr;
   while (pNode) {
-    pWidgetAcc = pNode->GetWidgetAcc();
-    if (!pWidgetAcc)
+    if (!pNode->IsWidgetReady())
       return 1;
-    if (CalculateWidgetAcc(pWidgetAcc) == 0)
+    if (CalculateNode(pNode) == 0)
       return 0;
 
-    pNode = pWidgetAcc->GetExclGroupNextMember(pNode);
+    pNode = pNode->GetExclGroupNextMember(pNode);
   }
   return 1;
 }
 
-int32_t CXFA_FFField::CalculateWidgetAcc(CXFA_WidgetAcc* pAcc) {
-  CXFA_Calculate* calc = pAcc->GetNode()->GetCalculateIfExists();
+int32_t CXFA_FFField::CalculateNode(CXFA_Node* pNode) {
+  CXFA_Calculate* calc = pNode->GetCalculateIfExists();
   if (!calc)
     return 1;
 
   XFA_VERSION version = GetDoc()->GetXFADoc()->GetCurVersionMode();
   switch (calc->GetOverride()) {
-    case XFA_AttributeEnum::Error: {
+    case XFA_AttributeValue::Error: {
       if (version <= XFA_VERSION_204)
         return 1;
 
-      IXFA_AppProvider* pAppProvider = GetApp()->GetAppProvider();
+      IXFA_AppProvider* pAppProvider = GetAppProvider();
       if (pAppProvider) {
-        pAppProvider->MsgBox(L"You are not allowed to modify this field.",
-                             L"Calculate Override", XFA_MBICON_Warning,
-                             XFA_MB_OK);
+        pAppProvider->MsgBox(
+            WideString::FromASCII("You are not allowed to modify this field."),
+            WideString::FromASCII("Calculate Override"),
+            static_cast<uint32_t>(AlertIcon::kWarning),
+            static_cast<uint32_t>(AlertButton::kOK));
       }
       return 0;
     }
-    case XFA_AttributeEnum::Warning: {
+    case XFA_AttributeValue::Warning: {
       if (version <= XFA_VERSION_204) {
         CXFA_Script* script = calc->GetScriptIfExists();
-        if (!script)
-          return 1;
-        if (script->GetExpression().IsEmpty())
+        if (!script || script->GetExpression().IsEmpty())
           return 1;
       }
 
-      if (pAcc->GetNode()->IsUserInteractive())
+      if (pNode->IsUserInteractive())
         return 1;
 
-      IXFA_AppProvider* pAppProvider = GetApp()->GetAppProvider();
+      IXFA_AppProvider* pAppProvider = GetAppProvider();
       if (!pAppProvider)
         return 0;
 
       WideString wsMessage = calc->GetMessageText();
       if (!wsMessage.IsEmpty())
         wsMessage += L"\r\n";
+      wsMessage +=
+          WideString::FromASCII("Are you sure you want to modify this field?");
 
-      wsMessage += L"Are you sure you want to modify this field?";
-      if (pAppProvider->MsgBox(wsMessage, L"Calculate Override",
-                               XFA_MBICON_Warning, XFA_MB_YesNo) == XFA_IDYes) {
-        pAcc->GetNode()->SetFlag(XFA_NodeFlag_UserInteractive, false);
+      if (pAppProvider->MsgBox(wsMessage,
+                               WideString::FromASCII("Calculate Override"),
+                               static_cast<uint32_t>(AlertIcon::kWarning),
+                               static_cast<uint32_t>(AlertButton::kYesNo)) ==
+          static_cast<uint32_t>(AlertReturn::kYes)) {
+        pNode->SetFlag(XFA_NodeFlag_UserInteractive);
         return 1;
       }
       return 0;
     }
-    case XFA_AttributeEnum::Ignore:
+    case XFA_AttributeValue::Ignore:
       return 0;
-    case XFA_AttributeEnum::Disabled:
-      pAcc->GetNode()->SetFlag(XFA_NodeFlag_UserInteractive, false);
+    case XFA_AttributeValue::Disabled:
+      pNode->SetFlag(XFA_NodeFlag_UserInteractive);
       return 1;
     default:
       return 1;
@@ -728,8 +740,9 @@
   return false;
 }
 
-void CXFA_FFField::TranslateFWLMessage(CFWL_Message* pMessage) {
-  GetApp()->GetFWLWidgetMgr()->OnProcessMessageToForm(pMessage);
+void CXFA_FFField::SendMessageToFWLWidget(
+    std::unique_ptr<CFWL_Message> pMessage) {
+  GetApp()->GetFWLWidgetMgr()->OnProcessMessageToForm(std::move(pMessage));
 }
 
 void CXFA_FFField::OnProcessMessage(CFWL_Message* pMessage) {}
@@ -741,26 +754,26 @@
       if (event->m_dwCmd == FWL_MouseCommand::Enter) {
         CXFA_EventParam eParam;
         eParam.m_eType = XFA_EVENT_MouseEnter;
-        eParam.m_pTarget = m_pNode->GetWidgetAcc();
-        m_pNode->ProcessEvent(GetDocView(), XFA_AttributeEnum::MouseEnter,
+        eParam.m_pTarget = m_pNode.Get();
+        m_pNode->ProcessEvent(GetDocView(), XFA_AttributeValue::MouseEnter,
                               &eParam);
       } else if (event->m_dwCmd == FWL_MouseCommand::Leave) {
         CXFA_EventParam eParam;
         eParam.m_eType = XFA_EVENT_MouseExit;
-        eParam.m_pTarget = m_pNode->GetWidgetAcc();
-        m_pNode->ProcessEvent(GetDocView(), XFA_AttributeEnum::MouseExit,
+        eParam.m_pTarget = m_pNode.Get();
+        m_pNode->ProcessEvent(GetDocView(), XFA_AttributeValue::MouseExit,
                               &eParam);
       } else if (event->m_dwCmd == FWL_MouseCommand::LeftButtonDown) {
         CXFA_EventParam eParam;
         eParam.m_eType = XFA_EVENT_MouseDown;
-        eParam.m_pTarget = m_pNode->GetWidgetAcc();
-        m_pNode->ProcessEvent(GetDocView(), XFA_AttributeEnum::MouseDown,
+        eParam.m_pTarget = m_pNode.Get();
+        m_pNode->ProcessEvent(GetDocView(), XFA_AttributeValue::MouseDown,
                               &eParam);
       } else if (event->m_dwCmd == FWL_MouseCommand::LeftButtonUp) {
         CXFA_EventParam eParam;
         eParam.m_eType = XFA_EVENT_MouseUp;
-        eParam.m_pTarget = m_pNode->GetWidgetAcc();
-        m_pNode->ProcessEvent(GetDocView(), XFA_AttributeEnum::MouseUp,
+        eParam.m_pTarget = m_pNode.Get();
+        m_pNode->ProcessEvent(GetDocView(), XFA_AttributeValue::MouseUp,
                               &eParam);
       }
       break;
@@ -768,8 +781,8 @@
     case CFWL_Event::Type::Click: {
       CXFA_EventParam eParam;
       eParam.m_eType = XFA_EVENT_Click;
-      eParam.m_pTarget = m_pNode->GetWidgetAcc();
-      m_pNode->ProcessEvent(GetDocView(), XFA_AttributeEnum::Click, &eParam);
+      eParam.m_pTarget = m_pNode.Get();
+      m_pNode->ProcessEvent(GetDocView(), XFA_AttributeValue::Click, &eParam);
       break;
     }
     default:
diff --git a/xfa/fxfa/cxfa_fffield.h b/xfa/fxfa/cxfa_fffield.h
index c2ba36c..dd7b914 100644
--- a/xfa/fxfa/cxfa_fffield.h
+++ b/xfa/fxfa/cxfa_fffield.h
@@ -14,23 +14,33 @@
 #include "xfa/fxfa/cxfa_ffpageview.h"
 #include "xfa/fxfa/cxfa_ffwidget.h"
 
+class CXFA_FFDropDown;
+class CXFA_Node;
+
 #define XFA_MINUI_HEIGHT 4.32f
 #define XFA_DEFAULTUI_HEIGHT 2.0f
 
 class CXFA_FFField : public CXFA_FFWidget, public IFWL_WidgetDelegate {
  public:
+  enum ShapeOption { kSquareShape = 0, kRoundShape };
+
   explicit CXFA_FFField(CXFA_Node* pNode);
   ~CXFA_FFField() override;
 
-  // CXFA_FFWidget
-  CFX_RectF GetBBox(uint32_t dwStatus, bool bDrawFocus = false) override;
+  virtual CXFA_FFDropDown* AsDropDown();
+
+  // CXFA_FFWidget:
+  CXFA_FFField* AsField() override;
+  CFX_RectF GetBBox(FocusOption focus) override;
   void RenderWidget(CXFA_Graphics* pGS,
                     const CFX_Matrix& matrix,
-                    uint32_t dwStatus) override;
+                    HighlightOption highlight) override;
   bool IsLoaded() override;
   bool LoadWidget() override;
-  void UnloadWidget() override;
   bool PerformLayout() override;
+  bool AcceptsFocusOnButtonDown(uint32_t dwFlags,
+                                const CFX_PointF& point,
+                                FWL_MouseCommand command) override;
   bool OnMouseEnter() override;
   bool OnMouseExit() override;
   bool OnLButtonDown(uint32_t dwFlags, const CFX_PointF& point) override;
@@ -43,16 +53,15 @@
   bool OnRButtonDown(uint32_t dwFlags, const CFX_PointF& point) override;
   bool OnRButtonUp(uint32_t dwFlags, const CFX_PointF& point) override;
   bool OnRButtonDblClk(uint32_t dwFlags, const CFX_PointF& point) override;
-
-  bool OnSetFocus(CXFA_FFWidget* pOldWidget) override;
-  bool OnKillFocus(CXFA_FFWidget* pNewWidget) override;
+  bool OnSetFocus(CXFA_FFWidget* pOldWidget) override WARN_UNUSED_RESULT;
+  bool OnKillFocus(CXFA_FFWidget* pNewWidget) override WARN_UNUSED_RESULT;
   bool OnKeyDown(uint32_t dwKeyCode, uint32_t dwFlags) override;
   bool OnKeyUp(uint32_t dwKeyCode, uint32_t dwFlags) override;
   bool OnChar(uint32_t dwChar, uint32_t dwFlags) override;
-  FWL_WidgetHit OnHitTest(const CFX_PointF& point) override;
   bool OnSetCursor(const CFX_PointF& point) override;
+  FWL_WidgetHit HitTest(const CFX_PointF& point) override;
 
-  // IFWL_WidgetDelegate
+  // IFWL_WidgetDelegate:
   void OnProcessMessage(CFWL_Message* pMessage) override;
   void OnProcessEvent(CFWL_Event* pEvent) override;
   void OnDrawWidget(CXFA_Graphics* pGraphics,
@@ -66,34 +75,42 @@
 
   virtual void SetFWLRect();
   void SetFWLThemeProvider();
-  CFWL_Widget* GetNormalWidget() { return m_pNormalWidget.get(); }
+  CFWL_Widget* GetNormalWidget();
+  const CFWL_Widget* GetNormalWidget() const;
+  void SetNormalWidget(std::unique_ptr<CFWL_Widget> widget);
   CFX_PointF FWLToClient(const CFX_PointF& point);
   void LayoutCaption();
   void RenderCaption(CXFA_Graphics* pGS, CFX_Matrix* pMatrix);
 
   int32_t CalculateOverride();
-  int32_t CalculateWidgetAcc(CXFA_WidgetAcc* pAcc);
+  int32_t CalculateNode(CXFA_Node* pNode);
   bool ProcessCommittedData();
   virtual bool CommitData();
   virtual bool IsDataChanged();
   void DrawHighlight(CXFA_Graphics* pGS,
                      CFX_Matrix* pMatrix,
-                     uint32_t dwStatus,
-                     bool bEllipse);
+                     HighlightOption highlight,
+                     ShapeOption shape);
   void DrawFocus(CXFA_Graphics* pGS, CFX_Matrix* pMatrix);
-  void TranslateFWLMessage(CFWL_Message* pMessage);
+  void SendMessageToFWLWidget(std::unique_ptr<CFWL_Message> pMessage);
   void CapPlacement();
   void CapTopBottomPlacement(const CXFA_Margin* margin,
                              const CFX_RectF& rtWidget,
-                             XFA_AttributeEnum iCapPlacement);
+                             XFA_AttributeValue iCapPlacement);
   void CapLeftRightPlacement(const CXFA_Margin* margin,
                              const CFX_RectF& rtWidget,
-                             XFA_AttributeEnum iCapPlacement);
+                             XFA_AttributeValue iCapPlacement);
   void SetEditScrollOffset();
 
-  std::unique_ptr<CFWL_Widget> m_pNormalWidget;
   CFX_RectF m_rtUI;
   CFX_RectF m_rtCaption;
+
+ private:
+  std::unique_ptr<CFWL_Widget> m_pNormalWidget;
 };
 
+inline CXFA_FFDropDown* ToDropDown(CXFA_FFField* field) {
+  return field ? field->AsDropDown() : nullptr;
+}
+
 #endif  // XFA_FXFA_CXFA_FFFIELD_H_
diff --git a/xfa/fxfa/cxfa_ffimage.cpp b/xfa/fxfa/cxfa_ffimage.cpp
index b4a0d32..eeb0e24 100644
--- a/xfa/fxfa/cxfa_ffimage.cpp
+++ b/xfa/fxfa/cxfa_ffimage.cpp
@@ -6,75 +6,63 @@
 
 #include "xfa/fxfa/cxfa_ffimage.h"
 
+#include "core/fxge/dib/cfx_dibitmap.h"
 #include "xfa/fxfa/cxfa_ffapp.h"
 #include "xfa/fxfa/cxfa_ffdoc.h"
-#include "xfa/fxfa/cxfa_ffdraw.h"
 #include "xfa/fxfa/cxfa_ffpageview.h"
 #include "xfa/fxfa/cxfa_ffwidget.h"
 #include "xfa/fxfa/parser/cxfa_image.h"
 #include "xfa/fxfa/parser/cxfa_para.h"
 #include "xfa/fxfa/parser/cxfa_value.h"
 
-CXFA_FFImage::CXFA_FFImage(CXFA_Node* pNode) : CXFA_FFDraw(pNode) {}
+CXFA_FFImage::CXFA_FFImage(CXFA_Node* pNode) : CXFA_FFWidget(pNode) {}
 
 CXFA_FFImage::~CXFA_FFImage() {
-  CXFA_FFImage::UnloadWidget();
+  GetNode()->SetImageImage(nullptr);
 }
 
 bool CXFA_FFImage::IsLoaded() {
-  return !!GetNode()->GetWidgetAcc()->GetImageImage();
+  return !!GetNode()->GetImageImage();
 }
 
 bool CXFA_FFImage::LoadWidget() {
-  if (GetNode()->GetWidgetAcc()->GetImageImage())
+  if (GetNode()->GetImageImage())
     return true;
 
-  return GetNode()->GetWidgetAcc()->LoadImageImage(GetDoc())
-             ? CXFA_FFDraw::LoadWidget()
-             : false;
-}
-
-void CXFA_FFImage::UnloadWidget() {
-  GetNode()->GetWidgetAcc()->SetImageImage(nullptr);
+  return GetNode()->LoadImageImage(GetDoc()) && CXFA_FFWidget::LoadWidget();
 }
 
 void CXFA_FFImage::RenderWidget(CXFA_Graphics* pGS,
                                 const CFX_Matrix& matrix,
-                                uint32_t dwStatus) {
-  if (!IsMatchVisibleStatus(dwStatus))
+                                HighlightOption highlight) {
+  if (!HasVisibleStatus())
     return;
 
   CFX_Matrix mtRotate = GetRotateMatrix();
   mtRotate.Concat(matrix);
 
-  CXFA_FFWidget::RenderWidget(pGS, mtRotate, dwStatus);
+  CXFA_FFWidget::RenderWidget(pGS, mtRotate, highlight);
 
-  RetainPtr<CFX_DIBitmap> pDIBitmap =
-      GetNode()->GetWidgetAcc()->GetImageImage();
+  RetainPtr<CFX_DIBitmap> pDIBitmap = GetNode()->GetImageImage();
   if (!pDIBitmap)
     return;
 
   CFX_RectF rtImage = GetRectWithoutRotate();
   CXFA_Margin* margin = m_pNode->GetMarginIfExists();
-  if (margin)
-    XFA_RectWithoutMargin(rtImage, margin);
+  XFA_RectWithoutMargin(&rtImage, margin);
 
-  XFA_AttributeEnum iHorzAlign = XFA_AttributeEnum::Left;
-  XFA_AttributeEnum iVertAlign = XFA_AttributeEnum::Top;
+  XFA_AttributeValue iHorzAlign = XFA_AttributeValue::Left;
+  XFA_AttributeValue iVertAlign = XFA_AttributeValue::Top;
   CXFA_Para* para = m_pNode->GetParaIfExists();
   if (para) {
     iHorzAlign = para->GetHorizontalAlign();
     iVertAlign = para->GetVerticalAlign();
   }
 
-  int32_t iImageXDpi = 0;
-  int32_t iImageYDpi = 0;
-  m_pNode->GetWidgetAcc()->GetImageDpi(iImageXDpi, iImageYDpi);
-
   auto* value = m_pNode->GetFormValueIfExists();
   CXFA_Image* image = value ? value->GetImageIfExists() : nullptr;
   if (image) {
     XFA_DrawImage(pGS, rtImage, mtRotate, pDIBitmap, image->GetAspect(),
-                  iImageXDpi, iImageYDpi, iHorzAlign, iVertAlign);
+                  m_pNode->GetImageDpi(), iHorzAlign, iVertAlign);
   }
 }
diff --git a/xfa/fxfa/cxfa_ffimage.h b/xfa/fxfa/cxfa_ffimage.h
index c721b11..5d23f60 100644
--- a/xfa/fxfa/cxfa_ffimage.h
+++ b/xfa/fxfa/cxfa_ffimage.h
@@ -7,9 +7,9 @@
 #ifndef XFA_FXFA_CXFA_FFIMAGE_H_
 #define XFA_FXFA_CXFA_FFIMAGE_H_
 
-#include "xfa/fxfa/cxfa_ffdraw.h"
+#include "xfa/fxfa/cxfa_ffwidget.h"
 
-class CXFA_FFImage : public CXFA_FFDraw {
+class CXFA_FFImage final : public CXFA_FFWidget {
  public:
   explicit CXFA_FFImage(CXFA_Node* pNode);
   ~CXFA_FFImage() override;
@@ -17,10 +17,9 @@
   // CXFA_FFWidget
   void RenderWidget(CXFA_Graphics* pGS,
                     const CFX_Matrix& matrix,
-                    uint32_t dwStatus) override;
+                    HighlightOption highlight) override;
   bool IsLoaded() override;
   bool LoadWidget() override;
-  void UnloadWidget() override;
 };
 
 #endif  // XFA_FXFA_CXFA_FFIMAGE_H_
diff --git a/xfa/fxfa/cxfa_ffimageedit.cpp b/xfa/fxfa/cxfa_ffimageedit.cpp
index 0e97559..60f584a 100644
--- a/xfa/fxfa/cxfa_ffimageedit.cpp
+++ b/xfa/fxfa/cxfa_ffimageedit.cpp
@@ -8,6 +8,7 @@
 
 #include <utility>
 
+#include "core/fxge/dib/cfx_dibitmap.h"
 #include "third_party/base/ptr_util.h"
 #include "xfa/fwl/cfwl_app.h"
 #include "xfa/fwl/cfwl_messagemouse.h"
@@ -23,65 +24,57 @@
 #include "xfa/fxfa/parser/cxfa_para.h"
 #include "xfa/fxfa/parser/cxfa_value.h"
 
-CXFA_FFImageEdit::CXFA_FFImageEdit(CXFA_Node* pNode)
-    : CXFA_FFField(pNode), m_pOldDelegate(nullptr) {}
+CXFA_FFImageEdit::CXFA_FFImageEdit(CXFA_Node* pNode) : CXFA_FFField(pNode) {}
 
 CXFA_FFImageEdit::~CXFA_FFImageEdit() {
-  CXFA_FFImageEdit::UnloadWidget();
+  m_pNode->SetImageEditImage(nullptr);
 }
 
 bool CXFA_FFImageEdit::LoadWidget() {
+  ASSERT(!IsLoaded());
   auto pNew = pdfium::MakeUnique<CFWL_PictureBox>(GetFWLApp());
   CFWL_PictureBox* pPictureBox = pNew.get();
-  m_pNormalWidget = std::move(pNew);
-  m_pNormalWidget->SetLayoutItem(this);
+  SetNormalWidget(std::move(pNew));
+  pPictureBox->SetAdapterIface(this);
 
-  CFWL_NoteDriver* pNoteDriver =
-      m_pNormalWidget->GetOwnerApp()->GetNoteDriver();
-  pNoteDriver->RegisterEventTarget(m_pNormalWidget.get(),
-                                   m_pNormalWidget.get());
+  CFWL_NoteDriver* pNoteDriver = pPictureBox->GetOwnerApp()->GetNoteDriver();
+  pNoteDriver->RegisterEventTarget(pPictureBox, pPictureBox);
   m_pOldDelegate = pPictureBox->GetDelegate();
   pPictureBox->SetDelegate(this);
 
   CXFA_FFField::LoadWidget();
-  if (!m_pNode->GetWidgetAcc()->GetImageEditImage())
+  if (!m_pNode->GetImageEditImage())
     UpdateFWLData();
 
   return true;
 }
 
-void CXFA_FFImageEdit::UnloadWidget() {
-  m_pNode->GetWidgetAcc()->SetImageEditImage(nullptr);
-  CXFA_FFField::UnloadWidget();
-}
-
 void CXFA_FFImageEdit::RenderWidget(CXFA_Graphics* pGS,
                                     const CFX_Matrix& matrix,
-                                    uint32_t dwStatus) {
-  if (!IsMatchVisibleStatus(dwStatus))
+                                    HighlightOption highlight) {
+  if (!HasVisibleStatus())
     return;
 
   CFX_Matrix mtRotate = GetRotateMatrix();
   mtRotate.Concat(matrix);
 
-  CXFA_FFWidget::RenderWidget(pGS, mtRotate, dwStatus);
-  DrawBorder(pGS, m_pNode->GetWidgetAcc()->GetUIBorder(), m_rtUI, mtRotate);
+  CXFA_FFWidget::RenderWidget(pGS, mtRotate, highlight);
+  DrawBorder(pGS, m_pNode->GetUIBorder(), m_rtUI, mtRotate);
   RenderCaption(pGS, &mtRotate);
-  RetainPtr<CFX_DIBitmap> pDIBitmap =
-      m_pNode->GetWidgetAcc()->GetImageEditImage();
+  RetainPtr<CFX_DIBitmap> pDIBitmap = m_pNode->GetImageEditImage();
   if (!pDIBitmap)
     return;
 
-  CFX_RectF rtImage = m_pNormalWidget->GetWidgetRect();
-  XFA_AttributeEnum iHorzAlign = XFA_AttributeEnum::Left;
-  XFA_AttributeEnum iVertAlign = XFA_AttributeEnum::Top;
+  CFX_RectF rtImage = GetNormalWidget()->GetWidgetRect();
+  XFA_AttributeValue iHorzAlign = XFA_AttributeValue::Left;
+  XFA_AttributeValue iVertAlign = XFA_AttributeValue::Top;
   CXFA_Para* para = m_pNode->GetParaIfExists();
   if (para) {
     iHorzAlign = para->GetHorizontalAlign();
     iVertAlign = para->GetVerticalAlign();
   }
 
-  XFA_AttributeEnum iAspect = XFA_AttributeEnum::Fit;
+  XFA_AttributeValue iAspect = XFA_AttributeValue::Fit;
   CXFA_Value* value = m_pNode->GetFormValueIfExists();
   if (value) {
     CXFA_Image* image = value->GetImageIfExists();
@@ -89,39 +82,44 @@
       iAspect = image->GetAspect();
   }
 
-  int32_t iImageXDpi = 0;
-  int32_t iImageYDpi = 0;
-  m_pNode->GetWidgetAcc()->GetImageEditDpi(iImageXDpi, iImageYDpi);
-  XFA_DrawImage(pGS, rtImage, mtRotate, pDIBitmap, iAspect, iImageXDpi,
-                iImageYDpi, iHorzAlign, iVertAlign);
+  XFA_DrawImage(pGS, rtImage, mtRotate, pDIBitmap, iAspect,
+                m_pNode->GetImageEditDpi(), iHorzAlign, iVertAlign);
 }
 
-bool CXFA_FFImageEdit::OnLButtonDown(uint32_t dwFlags,
-                                     const CFX_PointF& point) {
+bool CXFA_FFImageEdit::AcceptsFocusOnButtonDown(uint32_t dwFlags,
+                                                const CFX_PointF& point,
+                                                FWL_MouseCommand command) {
+  if (command != FWL_MouseCommand::LeftButtonDown)
+    return CXFA_FFField::AcceptsFocusOnButtonDown(dwFlags, point, command);
+
   if (!m_pNode->IsOpenAccess())
     return false;
   if (!PtInActiveRect(point))
     return false;
 
-  SetButtonDown(true);
-
-  CFWL_MessageMouse ms(nullptr, m_pNormalWidget.get());
-  ms.m_dwCmd = FWL_MouseCommand::LeftButtonDown;
-  ms.m_dwFlags = dwFlags;
-  ms.m_pos = FWLToClient(point);
-  TranslateFWLMessage(&ms);
   return true;
 }
 
+bool CXFA_FFImageEdit::OnLButtonDown(uint32_t dwFlags,
+                                     const CFX_PointF& point) {
+  ObservedPtr<CXFA_FFImageEdit> pWatched(this);
+  SetButtonDown(true);
+  SendMessageToFWLWidget(pdfium::MakeUnique<CFWL_MessageMouse>(
+      GetNormalWidget(), FWL_MouseCommand::LeftButtonDown, dwFlags,
+      FWLToClient(point)));
+
+  return !!pWatched;
+}
+
 void CXFA_FFImageEdit::SetFWLRect() {
-  if (!m_pNormalWidget)
+  if (!GetNormalWidget())
     return;
 
-  CFX_RectF rtUIMargin = m_pNode->GetWidgetAcc()->GetUIMargin();
+  CFX_RectF rtUIMargin = m_pNode->GetUIMargin();
   CFX_RectF rtImage(m_rtUI);
   rtImage.Deflate(rtUIMargin.left, rtUIMargin.top, rtUIMargin.width,
                   rtUIMargin.height);
-  m_pNormalWidget->SetWidgetRect(rtImage);
+  GetNormalWidget()->SetWidgetRect(rtImage);
 }
 
 bool CXFA_FFImageEdit::CommitData() {
@@ -129,8 +127,8 @@
 }
 
 bool CXFA_FFImageEdit::UpdateFWLData() {
-  m_pNode->GetWidgetAcc()->SetImageEditImage(nullptr);
-  m_pNode->GetWidgetAcc()->LoadImageEditImage(GetDoc());
+  m_pNode->SetImageEditImage(nullptr);
+  m_pNode->LoadImageEditImage(GetDoc());
   return true;
 }
 
diff --git a/xfa/fxfa/cxfa_ffimageedit.h b/xfa/fxfa/cxfa_ffimageedit.h
index a7ef6a8..f1233b3 100644
--- a/xfa/fxfa/cxfa_ffimageedit.h
+++ b/xfa/fxfa/cxfa_ffimageedit.h
@@ -7,9 +7,10 @@
 #ifndef XFA_FXFA_CXFA_FFIMAGEEDIT_H_
 #define XFA_FXFA_CXFA_FFIMAGEEDIT_H_
 
+#include "core/fxcrt/unowned_ptr.h"
 #include "xfa/fxfa/cxfa_fffield.h"
 
-class CXFA_FFImageEdit : public CXFA_FFField {
+class CXFA_FFImageEdit final : public CXFA_FFField {
  public:
   explicit CXFA_FFImageEdit(CXFA_Node* pNode);
   ~CXFA_FFImageEdit() override;
@@ -17,9 +18,11 @@
   // CXFA_FFField
   void RenderWidget(CXFA_Graphics* pGS,
                     const CFX_Matrix& matrix,
-                    uint32_t dwStatus) override;
+                    HighlightOption highlight) override;
   bool LoadWidget() override;
-  void UnloadWidget() override;
+  bool AcceptsFocusOnButtonDown(uint32_t dwFlags,
+                                const CFX_PointF& point,
+                                FWL_MouseCommand command) override;
   bool OnLButtonDown(uint32_t dwFlags, const CFX_PointF& point) override;
   void OnProcessMessage(CFWL_Message* pMessage) override;
   void OnProcessEvent(CFWL_Event* pEvent) override;
@@ -32,7 +35,7 @@
   bool UpdateFWLData() override;
   bool CommitData() override;
 
-  IFWL_WidgetDelegate* m_pOldDelegate;
+  UnownedPtr<IFWL_WidgetDelegate> m_pOldDelegate;
 };
 
 #endif  // XFA_FXFA_CXFA_FFIMAGEEDIT_H_
diff --git a/xfa/fxfa/cxfa_ffline.cpp b/xfa/fxfa/cxfa_ffline.cpp
index 4937a0e..ec51040 100644
--- a/xfa/fxfa/cxfa_ffline.cpp
+++ b/xfa/fxfa/cxfa_ffline.cpp
@@ -15,11 +15,11 @@
 
 namespace {
 
-CFX_GraphStateData::LineCap LineCapToFXGE(XFA_AttributeEnum iLineCap) {
+CFX_GraphStateData::LineCap LineCapToFXGE(XFA_AttributeValue iLineCap) {
   switch (iLineCap) {
-    case XFA_AttributeEnum::Round:
+    case XFA_AttributeValue::Round:
       return CFX_GraphStateData::LineCapRound;
-    case XFA_AttributeEnum::Butt:
+    case XFA_AttributeValue::Butt:
       return CFX_GraphStateData::LineCapButt;
     default:
       break;
@@ -29,22 +29,23 @@
 
 }  // namespace
 
-CXFA_FFLine::CXFA_FFLine(CXFA_Node* pNode) : CXFA_FFDraw(pNode) {}
+CXFA_FFLine::CXFA_FFLine(CXFA_Node* pNode) : CXFA_FFWidget(pNode) {}
 
 CXFA_FFLine::~CXFA_FFLine() {}
 
 void CXFA_FFLine::GetRectFromHand(CFX_RectF& rect,
-                                  XFA_AttributeEnum iHand,
+                                  XFA_AttributeValue iHand,
                                   float fLineWidth) {
   float fHalfWidth = fLineWidth / 2.0f;
   if (rect.height < 1.0f) {
     switch (iHand) {
-      case XFA_AttributeEnum::Left:
+      case XFA_AttributeValue::Left:
         rect.top -= fHalfWidth;
         break;
-      case XFA_AttributeEnum::Right:
+      case XFA_AttributeValue::Right:
         rect.top += fHalfWidth;
-      case XFA_AttributeEnum::Even:
+        break;
+      case XFA_AttributeValue::Even:
         break;
       default:
         NOTREACHED();
@@ -52,13 +53,13 @@
     }
   } else if (rect.width < 1.0f) {
     switch (iHand) {
-      case XFA_AttributeEnum::Left:
+      case XFA_AttributeValue::Left:
         rect.left += fHalfWidth;
         break;
-      case XFA_AttributeEnum::Right:
+      case XFA_AttributeValue::Right:
         rect.left += fHalfWidth;
         break;
-      case XFA_AttributeEnum::Even:
+      case XFA_AttributeValue::Even:
         break;
       default:
         NOTREACHED();
@@ -66,13 +67,13 @@
     }
   } else {
     switch (iHand) {
-      case XFA_AttributeEnum::Left:
+      case XFA_AttributeValue::Left:
         rect.Inflate(fHalfWidth, fHalfWidth);
         break;
-      case XFA_AttributeEnum::Right:
+      case XFA_AttributeValue::Right:
         rect.Deflate(fHalfWidth, fHalfWidth);
         break;
-      case XFA_AttributeEnum::Even:
+      case XFA_AttributeValue::Even:
         break;
       default:
         NOTREACHED();
@@ -83,8 +84,8 @@
 
 void CXFA_FFLine::RenderWidget(CXFA_Graphics* pGS,
                                const CFX_Matrix& matrix,
-                               uint32_t dwStatus) {
-  if (!IsMatchVisibleStatus(dwStatus))
+                               HighlightOption highlight) {
+  if (!HasVisibleStatus())
     return;
 
   CXFA_Value* value = m_pNode->GetFormValueIfExists();
@@ -93,9 +94,8 @@
 
   FX_ARGB lineColor = 0xFF000000;
   float fLineWidth = 1.0f;
-  XFA_AttributeEnum iStrokeType = XFA_AttributeEnum::Unknown;
-  XFA_AttributeEnum iCap = XFA_AttributeEnum::Unknown;
-
+  XFA_AttributeValue iStrokeType = XFA_AttributeValue::Unknown;
+  XFA_AttributeValue iCap = XFA_AttributeValue::Unknown;
   CXFA_Line* line = value->GetLineIfExists();
   if (line) {
     CXFA_Edge* edge = line->GetEdgeIfExists();
@@ -115,10 +115,9 @@
 
   CFX_RectF rtLine = GetRectWithoutRotate();
   CXFA_Margin* margin = m_pNode->GetMarginIfExists();
-  if (margin)
-    XFA_RectWithoutMargin(rtLine, margin);
+  XFA_RectWithoutMargin(&rtLine, margin);
 
-  GetRectFromHand(rtLine, line ? line->GetHand() : XFA_AttributeEnum::Left,
+  GetRectFromHand(rtLine, line ? line->GetHand() : XFA_AttributeValue::Left,
                   fLineWidth);
   CXFA_GEPath linePath;
   if (line && line->GetSlope() && rtLine.right() > 0.0f &&
diff --git a/xfa/fxfa/cxfa_ffline.h b/xfa/fxfa/cxfa_ffline.h
index 01f3fd3..62750d1 100644
--- a/xfa/fxfa/cxfa_ffline.h
+++ b/xfa/fxfa/cxfa_ffline.h
@@ -7,9 +7,9 @@
 #ifndef XFA_FXFA_CXFA_FFLINE_H_
 #define XFA_FXFA_CXFA_FFLINE_H_
 
-#include "xfa/fxfa/cxfa_ffdraw.h"
+#include "xfa/fxfa/cxfa_ffwidget.h"
 
-class CXFA_FFLine : public CXFA_FFDraw {
+class CXFA_FFLine final : public CXFA_FFWidget {
  public:
   explicit CXFA_FFLine(CXFA_Node* pNode);
   ~CXFA_FFLine() override;
@@ -17,11 +17,11 @@
   // CXFA_FFWidget
   void RenderWidget(CXFA_Graphics* pGS,
                     const CFX_Matrix& matrix,
-                    uint32_t dwStatus) override;
+                    HighlightOption highlight) override;
 
  private:
   void GetRectFromHand(CFX_RectF& rect,
-                       XFA_AttributeEnum iHand,
+                       XFA_AttributeValue iHand,
                        float fLineWidth);
 };
 
diff --git a/xfa/fxfa/cxfa_fflistbox.cpp b/xfa/fxfa/cxfa_fflistbox.cpp
index ce9198a..45162ee 100644
--- a/xfa/fxfa/cxfa_fflistbox.cpp
+++ b/xfa/fxfa/cxfa_fflistbox.cpp
@@ -10,6 +10,8 @@
 #include <utility>
 #include <vector>
 
+#include "third_party/base/ptr_util.h"
+#include "third_party/base/stl_util.h"
 #include "xfa/fwl/cfwl_listbox.h"
 #include "xfa/fwl/cfwl_notedriver.h"
 #include "xfa/fwl/cfwl_widget.h"
@@ -24,74 +26,75 @@
 
 }  // namespace
 
-CXFA_FFListBox::CXFA_FFListBox(CXFA_Node* pNode)
-    : CXFA_FFField(pNode), m_pOldDelegate(nullptr) {}
+CXFA_FFListBox::CXFA_FFListBox(CXFA_Node* pNode) : CXFA_FFDropDown(pNode) {}
 
 CXFA_FFListBox::~CXFA_FFListBox() {
-  if (!m_pNormalWidget)
+  if (!GetNormalWidget())
     return;
 
   CFWL_NoteDriver* pNoteDriver =
-      m_pNormalWidget->GetOwnerApp()->GetNoteDriver();
-  pNoteDriver->UnregisterEventTarget(m_pNormalWidget.get());
+      GetNormalWidget()->GetOwnerApp()->GetNoteDriver();
+  pNoteDriver->UnregisterEventTarget(GetNormalWidget());
 }
 
 bool CXFA_FFListBox::LoadWidget() {
+  ASSERT(!IsLoaded());
   auto pNew = pdfium::MakeUnique<CFWL_ListBox>(
       GetFWLApp(), pdfium::MakeUnique<CFWL_WidgetProperties>(), nullptr);
   CFWL_ListBox* pListBox = pNew.get();
   pListBox->ModifyStyles(FWL_WGTSTYLE_VScroll | FWL_WGTSTYLE_NoBackground,
                          0xFFFFFFFF);
-  m_pNormalWidget = std::move(pNew);
-  m_pNormalWidget->SetLayoutItem(this);
+  SetNormalWidget(std::move(pNew));
+  pListBox->SetAdapterIface(this);
 
-  CFWL_NoteDriver* pNoteDriver =
-      m_pNormalWidget->GetOwnerApp()->GetNoteDriver();
-  pNoteDriver->RegisterEventTarget(m_pNormalWidget.get(),
-                                   m_pNormalWidget.get());
-  m_pOldDelegate = m_pNormalWidget->GetDelegate();
-  m_pNormalWidget->SetDelegate(this);
-  m_pNormalWidget->LockUpdate();
+  CFWL_NoteDriver* pNoteDriver = pListBox->GetOwnerApp()->GetNoteDriver();
+  pNoteDriver->RegisterEventTarget(pListBox, pListBox);
+  m_pOldDelegate = pListBox->GetDelegate();
+  pListBox->SetDelegate(this);
 
-  for (const auto& label : m_pNode->GetWidgetAcc()->GetChoiceListItems(false))
-    pListBox->AddString(label.AsStringView());
+  {
+    CFWL_Widget::ScopedUpdateLock update_lock(pListBox);
+    for (const auto& label : m_pNode->GetChoiceListItems(false))
+      pListBox->AddString(label);
 
-  uint32_t dwExtendedStyle = FWL_STYLEEXT_LTB_ShowScrollBarFocus;
-  if (m_pNode->GetWidgetAcc()->IsChoiceListMultiSelect())
-    dwExtendedStyle |= FWL_STYLEEXT_LTB_MultiSelection;
+    uint32_t dwExtendedStyle = FWL_STYLEEXT_LTB_ShowScrollBarFocus;
+    if (m_pNode->IsChoiceListMultiSelect())
+      dwExtendedStyle |= FWL_STYLEEXT_LTB_MultiSelection;
 
-  dwExtendedStyle |= GetAlignment();
-  m_pNormalWidget->ModifyStylesEx(dwExtendedStyle, 0xFFFFFFFF);
-  for (int32_t selected : m_pNode->GetWidgetAcc()->GetSelectedItems())
-    pListBox->SetSelItem(pListBox->GetItem(nullptr, selected), true);
+    dwExtendedStyle |= GetAlignment();
+    pListBox->ModifyStylesEx(dwExtendedStyle, 0xFFFFFFFF);
+    for (int32_t selected : m_pNode->GetSelectedItems())
+      pListBox->SetSelItem(pListBox->GetItem(nullptr, selected), true);
+  }
 
-  m_pNormalWidget->UnlockUpdate();
   return CXFA_FFField::LoadWidget();
 }
 
 bool CXFA_FFListBox::OnKillFocus(CXFA_FFWidget* pNewFocus) {
+  ObservedPtr<CXFA_FFListBox> pWatched(this);
+  ObservedPtr<CXFA_FFWidget> pNewWatched(pNewFocus);
   if (!ProcessCommittedData())
     UpdateFWLData();
 
-  CXFA_FFField::OnKillFocus(pNewFocus);
-  return true;
+  return pWatched && pNewWatched &&
+         CXFA_FFField::OnKillFocus(pNewWatched.Get());
 }
 
 bool CXFA_FFListBox::CommitData() {
-  auto* pListBox = ToListBox(m_pNormalWidget.get());
+  auto* pListBox = ToListBox(GetNormalWidget());
   std::vector<int32_t> iSelArray;
   int32_t iSels = pListBox->CountSelItems();
   for (int32_t i = 0; i < iSels; ++i)
     iSelArray.push_back(pListBox->GetSelIndex(i));
 
-  m_pNode->GetWidgetAcc()->SetSelectedItems(iSelArray, true, false, true);
+  m_pNode->SetSelectedItems(iSelArray, true, false, true);
   return true;
 }
 
 bool CXFA_FFListBox::IsDataChanged() {
-  std::vector<int32_t> iSelArray = m_pNode->GetWidgetAcc()->GetSelectedItems();
+  std::vector<int32_t> iSelArray = m_pNode->GetSelectedItems();
   int32_t iOldSels = pdfium::CollectionSize<int32_t>(iSelArray);
-  auto* pListBox = ToListBox(m_pNormalWidget.get());
+  auto* pListBox = ToListBox(GetNormalWidget());
   int32_t iSels = pListBox->CountSelItems();
   if (iOldSels != iSels)
     return true;
@@ -111,16 +114,16 @@
 
   uint32_t dwExtendedStyle = 0;
   switch (para->GetHorizontalAlign()) {
-    case XFA_AttributeEnum::Center:
+    case XFA_AttributeValue::Center:
       dwExtendedStyle |= FWL_STYLEEXT_LTB_CenterAlign;
       break;
-    case XFA_AttributeEnum::Justify:
+    case XFA_AttributeValue::Justify:
       break;
-    case XFA_AttributeEnum::JustifyAll:
+    case XFA_AttributeValue::JustifyAll:
       break;
-    case XFA_AttributeEnum::Radix:
+    case XFA_AttributeValue::Radix:
       break;
-    case XFA_AttributeEnum::Right:
+    case XFA_AttributeValue::Right:
       dwExtendedStyle |= FWL_STYLEEXT_LTB_RightAlign;
       break;
     default:
@@ -131,11 +134,11 @@
 }
 
 bool CXFA_FFListBox::UpdateFWLData() {
-  if (!m_pNormalWidget)
+  if (!GetNormalWidget())
     return false;
 
-  auto* pListBox = ToListBox(m_pNormalWidget.get());
-  std::vector<int32_t> iSelArray = m_pNode->GetWidgetAcc()->GetSelectedItems();
+  auto* pListBox = ToListBox(GetNormalWidget());
+  std::vector<int32_t> iSelArray = m_pNode->GetSelectedItems();
   std::vector<CFWL_ListItem*> selItemArray(iSelArray.size());
   std::transform(iSelArray.begin(), iSelArray.end(), selItemArray.begin(),
                  [pListBox](int32_t val) { return pListBox->GetSelItem(val); });
@@ -144,48 +147,40 @@
   for (CFWL_ListItem* pItem : selItemArray)
     pListBox->SetSelItem(pItem, true);
 
-  m_pNormalWidget->Update();
+  GetNormalWidget()->Update();
   return true;
 }
 
 void CXFA_FFListBox::OnSelectChanged(CFWL_Widget* pWidget) {
   CXFA_EventParam eParam;
   eParam.m_eType = XFA_EVENT_Change;
-  eParam.m_pTarget = m_pNode->GetWidgetAcc();
-  eParam.m_wsPrevText = m_pNode->GetWidgetAcc()->GetValue(XFA_VALUEPICTURE_Raw);
-
-  auto* pListBox = ToListBox(m_pNormalWidget.get());
-  int32_t iSels = pListBox->CountSelItems();
-  if (iSels > 0) {
-    CFWL_ListItem* item = pListBox->GetSelItem(0);
-    eParam.m_wsNewText = item ? item->GetText() : L"";
-  }
-  m_pNode->ProcessEvent(GetDocView(), XFA_AttributeEnum::Change, &eParam);
+  eParam.m_pTarget = m_pNode.Get();
+  eParam.m_wsPrevText = m_pNode->GetValue(XFA_VALUEPICTURE_Raw);
+  m_pNode->ProcessEvent(GetDocView(), XFA_AttributeValue::Change, &eParam);
 }
 
 void CXFA_FFListBox::SetItemState(int32_t nIndex, bool bSelected) {
-  auto* pListBox = ToListBox(m_pNormalWidget.get());
+  auto* pListBox = ToListBox(GetNormalWidget());
   pListBox->SetSelItem(pListBox->GetSelItem(nIndex), bSelected);
-  m_pNormalWidget->Update();
-  AddInvalidateRect();
+  GetNormalWidget()->Update();
+  InvalidateRect();
 }
 
-void CXFA_FFListBox::InsertItem(const WideStringView& wsLabel, int32_t nIndex) {
-  WideString wsTemp(wsLabel);
-  ToListBox(m_pNormalWidget.get())->AddString(wsTemp.AsStringView());
-  m_pNormalWidget->Update();
-  AddInvalidateRect();
+void CXFA_FFListBox::InsertItem(const WideString& wsLabel, int32_t nIndex) {
+  ToListBox(GetNormalWidget())->AddString(wsLabel);
+  GetNormalWidget()->Update();
+  InvalidateRect();
 }
 
 void CXFA_FFListBox::DeleteItem(int32_t nIndex) {
-  auto* pListBox = ToListBox(m_pNormalWidget.get());
+  auto* pListBox = ToListBox(GetNormalWidget());
   if (nIndex < 0)
     pListBox->DeleteAll();
   else
     pListBox->DeleteString(pListBox->GetItem(nullptr, nIndex));
 
   pListBox->Update();
-  AddInvalidateRect();
+  InvalidateRect();
 }
 
 void CXFA_FFListBox::OnProcessMessage(CFWL_Message* pMessage) {
@@ -196,7 +191,7 @@
   CXFA_FFField::OnProcessEvent(pEvent);
   switch (pEvent->GetType()) {
     case CFWL_Event::Type::SelectChanged:
-      OnSelectChanged(m_pNormalWidget.get());
+      OnSelectChanged(GetNormalWidget());
       break;
     default:
       break;
diff --git a/xfa/fxfa/cxfa_fflistbox.h b/xfa/fxfa/cxfa_fflistbox.h
index 27f1cdb..896ee61 100644
--- a/xfa/fxfa/cxfa_fflistbox.h
+++ b/xfa/fxfa/cxfa_fflistbox.h
@@ -7,26 +7,29 @@
 #ifndef XFA_FXFA_CXFA_FFLISTBOX_H_
 #define XFA_FXFA_CXFA_FFLISTBOX_H_
 
-#include "xfa/fxfa/cxfa_fffield.h"
+#include "core/fxcrt/unowned_ptr.h"
+#include "xfa/fxfa/cxfa_ffdropdown.h"
 
-class CXFA_FFListBox : public CXFA_FFField {
+class CXFA_FFListBox final : public CXFA_FFDropDown {
  public:
   explicit CXFA_FFListBox(CXFA_Node* pNode);
   ~CXFA_FFListBox() override;
 
-  // CXFA_FFField
+  // CXFA_FFField:
   bool LoadWidget() override;
-  bool OnKillFocus(CXFA_FFWidget* pNewWidget) override;
+  bool OnKillFocus(CXFA_FFWidget* pNewWidget) override WARN_UNUSED_RESULT;
   void OnProcessMessage(CFWL_Message* pMessage) override;
   void OnProcessEvent(CFWL_Event* pEvent) override;
   void OnDrawWidget(CXFA_Graphics* pGraphics,
                     const CFX_Matrix& matrix) override;
   FormFieldType GetFormFieldType() override;
 
+  // CXFA_FFDropDown
+  void InsertItem(const WideString& wsLabel, int32_t nIndex) override;
+  void DeleteItem(int32_t nIndex) override;
+
   void OnSelectChanged(CFWL_Widget* pWidget);
   void SetItemState(int32_t nIndex, bool bSelected);
-  void InsertItem(const WideStringView& wsLabel, int32_t nIndex);
-  void DeleteItem(int32_t nIndex);
 
  private:
   bool CommitData() override;
@@ -35,7 +38,7 @@
 
   uint32_t GetAlignment();
 
-  IFWL_WidgetDelegate* m_pOldDelegate;
+  UnownedPtr<IFWL_WidgetDelegate> m_pOldDelegate;
 };
 
 #endif  // XFA_FXFA_CXFA_FFLISTBOX_H_
diff --git a/xfa/fxfa/cxfa_ffnotify.cpp b/xfa/fxfa/cxfa_ffnotify.cpp
index 3f41620..fc70e6b 100644
--- a/xfa/fxfa/cxfa_ffnotify.cpp
+++ b/xfa/fxfa/cxfa_ffnotify.cpp
@@ -6,9 +6,9 @@
 
 #include "xfa/fxfa/cxfa_ffnotify.h"
 
-#include <memory>
 #include <utility>
 
+#include "third_party/base/ptr_util.h"
 #include "xfa/fxfa/cxfa_ffapp.h"
 #include "xfa/fxfa/cxfa_ffarc.h"
 #include "xfa/fxfa/cxfa_ffbarcode.h"
@@ -17,7 +17,6 @@
 #include "xfa/fxfa/cxfa_ffdatetimeedit.h"
 #include "xfa/fxfa/cxfa_ffdoc.h"
 #include "xfa/fxfa/cxfa_ffdocview.h"
-#include "xfa/fxfa/cxfa_ffdraw.h"
 #include "xfa/fxfa/cxfa_ffexclgroup.h"
 #include "xfa/fxfa/cxfa_fffield.h"
 #include "xfa/fxfa/cxfa_ffimage.h"
@@ -30,184 +29,169 @@
 #include "xfa/fxfa/cxfa_ffpushbutton.h"
 #include "xfa/fxfa/cxfa_ffrectangle.h"
 #include "xfa/fxfa/cxfa_ffsignature.h"
-#include "xfa/fxfa/cxfa_ffsubform.h"
 #include "xfa/fxfa/cxfa_fftext.h"
 #include "xfa/fxfa/cxfa_ffwidget.h"
 #include "xfa/fxfa/cxfa_ffwidgethandler.h"
 #include "xfa/fxfa/cxfa_fwladapterwidgetmgr.h"
 #include "xfa/fxfa/cxfa_textlayout.h"
 #include "xfa/fxfa/cxfa_textprovider.h"
+#include "xfa/fxfa/layout/cxfa_layoutprocessor.h"
+#include "xfa/fxfa/parser/cxfa_barcode.h"
 #include "xfa/fxfa/parser/cxfa_binditems.h"
+#include "xfa/fxfa/parser/cxfa_button.h"
+#include "xfa/fxfa/parser/cxfa_checkbutton.h"
 #include "xfa/fxfa/parser/cxfa_node.h"
-
-namespace {
-
-CXFA_FFListBox* ToListBox(CXFA_FFWidget* widget) {
-  return static_cast<CXFA_FFListBox*>(widget);
-}
-
-CXFA_FFComboBox* ToComboBox(CXFA_FFWidget* widget) {
-  return static_cast<CXFA_FFComboBox*>(widget);
-}
-
-}  // namespace
+#include "xfa/fxfa/parser/cxfa_passwordedit.h"
 
 CXFA_FFNotify::CXFA_FFNotify(CXFA_FFDoc* pDoc) : m_pDoc(pDoc) {}
 
 CXFA_FFNotify::~CXFA_FFNotify() {}
 
-void CXFA_FFNotify::OnPageEvent(CXFA_ContainerLayoutItem* pSender,
+void CXFA_FFNotify::OnPageEvent(CXFA_ViewLayoutItem* pSender,
                                 uint32_t dwEvent) {
   CXFA_FFDocView* pDocView = m_pDoc->GetDocView(pSender->GetLayout());
   if (pDocView)
     pDocView->OnPageEvent(pSender, dwEvent);
 }
 
-void CXFA_FFNotify::OnWidgetListItemAdded(CXFA_WidgetAcc* pSender,
-                                          const wchar_t* pLabel,
-                                          const wchar_t* pValue,
+void CXFA_FFNotify::OnWidgetListItemAdded(CXFA_Node* pSender,
+                                          const WideString& wsLabel,
                                           int32_t iIndex) {
-  if (pSender->GetUIType() != XFA_Element::ChoiceList)
+  if (pSender->GetFFWidgetType() != XFA_FFWidgetType::kChoiceList)
     return;
 
-  CXFA_FFWidget* pWidget =
-      m_pDoc->GetDocView()->GetWidgetForNode(pSender->GetNode());
-  for (; pWidget; pWidget = pSender->GetNextWidget(pWidget)) {
-    if (pWidget->IsLoaded()) {
-      if (pSender->IsListBox())
-        ToListBox(pWidget)->InsertItem(pLabel, iIndex);
-      else
-        ToComboBox(pWidget)->InsertItem(pLabel, iIndex);
-    }
+  CXFA_FFWidget* pWidget = m_pDoc->GetDocView()->GetWidgetForNode(pSender);
+  for (; pWidget; pWidget = pWidget->GetNextFFWidget()) {
+    if (pWidget->IsLoaded())
+      ToDropDown(ToField(pWidget))->InsertItem(wsLabel, iIndex);
   }
 }
 
-void CXFA_FFNotify::OnWidgetListItemRemoved(CXFA_WidgetAcc* pSender,
+void CXFA_FFNotify::OnWidgetListItemRemoved(CXFA_Node* pSender,
                                             int32_t iIndex) {
-  if (pSender->GetUIType() != XFA_Element::ChoiceList)
+  if (pSender->GetFFWidgetType() != XFA_FFWidgetType::kChoiceList)
     return;
 
-  CXFA_FFWidget* pWidget =
-      m_pDoc->GetDocView()->GetWidgetForNode(pSender->GetNode());
-  for (; pWidget; pWidget = pSender->GetNextWidget(pWidget)) {
-    if (pWidget->IsLoaded()) {
-      if (pSender->IsListBox())
-        ToListBox(pWidget)->DeleteItem(iIndex);
-      else
-        ToComboBox(pWidget)->DeleteItem(iIndex);
-    }
+  CXFA_FFWidget* pWidget = m_pDoc->GetDocView()->GetWidgetForNode(pSender);
+  for (; pWidget; pWidget = pWidget->GetNextFFWidget()) {
+    if (pWidget->IsLoaded())
+      ToDropDown(ToField(pWidget))->DeleteItem(iIndex);
   }
 }
 
-CXFA_ContainerLayoutItem* CXFA_FFNotify::OnCreateContainerLayoutItem(
+std::unique_ptr<CXFA_FFPageView> CXFA_FFNotify::OnCreateViewLayoutItem(
     CXFA_Node* pNode) {
-  XFA_Element type = pNode->GetElementType();
-  ASSERT(type == XFA_Element::ContentArea || type == XFA_Element::PageArea);
+  if (pNode->GetElementType() != XFA_Element::PageArea)
+    return nullptr;
 
-  if (type == XFA_Element::PageArea) {
-    CXFA_LayoutProcessor* pLayout = m_pDoc->GetXFADoc()->GetDocLayout();
-    return new CXFA_FFPageView(m_pDoc->GetDocView(pLayout), pNode);
-  }
-  return new CXFA_ContainerLayoutItem(pNode);
+  auto* pLayout = CXFA_LayoutProcessor::FromDocument(m_pDoc->GetXFADoc());
+  return pdfium::MakeUnique<CXFA_FFPageView>(m_pDoc->GetDocView(pLayout),
+                                             pNode);
 }
 
-CXFA_ContentLayoutItem* CXFA_FFNotify::OnCreateContentLayoutItem(
+std::unique_ptr<CXFA_FFWidget> CXFA_FFNotify::OnCreateContentLayoutItem(
     CXFA_Node* pNode) {
   ASSERT(pNode->GetElementType() != XFA_Element::ContentArea);
   ASSERT(pNode->GetElementType() != XFA_Element::PageArea);
 
   // We only need to create the widget for certain types of objects.
   if (!pNode->HasCreatedUIWidget())
-    return new CXFA_ContentLayoutItem(pNode);
+    return nullptr;
 
-  CXFA_FFWidget* pWidget;
-  switch (pNode->GetWidgetAcc()->GetUIType()) {
-    case XFA_Element::Barcode:
-      pWidget = new CXFA_FFBarcode(pNode);
+  std::unique_ptr<CXFA_FFWidget> pWidget;
+  switch (pNode->GetFFWidgetType()) {
+    case XFA_FFWidgetType::kBarcode: {
+      CXFA_Node* child = pNode->GetUIChildNode();
+      if (child->GetElementType() != XFA_Element::Barcode)
+        return nullptr;
+
+      pWidget = pdfium::MakeUnique<CXFA_FFBarcode>(
+          pNode, static_cast<CXFA_Barcode*>(child));
       break;
-    case XFA_Element::Button:
-      pWidget = new CXFA_FFPushButton(pNode);
+    }
+    case XFA_FFWidgetType::kButton: {
+      CXFA_Node* child = pNode->GetUIChildNode();
+      if (child->GetElementType() != XFA_Element::Button)
+        return nullptr;
+
+      pWidget = pdfium::MakeUnique<CXFA_FFPushButton>(
+          pNode, static_cast<CXFA_Button*>(child));
       break;
-    case XFA_Element::CheckButton:
-      pWidget = new CXFA_FFCheckButton(pNode);
+    }
+    case XFA_FFWidgetType::kCheckButton: {
+      CXFA_Node* child = pNode->GetUIChildNode();
+      if (child->GetElementType() != XFA_Element::CheckButton)
+        return nullptr;
+
+      pWidget = pdfium::MakeUnique<CXFA_FFCheckButton>(
+          pNode, static_cast<CXFA_CheckButton*>(child));
       break;
-    case XFA_Element::ChoiceList: {
-      if (pNode->GetWidgetAcc()->IsListBox())
-        pWidget = new CXFA_FFListBox(pNode);
+    }
+    case XFA_FFWidgetType::kChoiceList: {
+      if (pNode->IsListBox())
+        pWidget = pdfium::MakeUnique<CXFA_FFListBox>(pNode);
       else
-        pWidget = new CXFA_FFComboBox(pNode);
-    } break;
-    case XFA_Element::DateTimeEdit:
-      pWidget = new CXFA_FFDateTimeEdit(pNode);
+        pWidget = pdfium::MakeUnique<CXFA_FFComboBox>(pNode);
       break;
-    case XFA_Element::ImageEdit:
-      pWidget = new CXFA_FFImageEdit(pNode);
+    }
+    case XFA_FFWidgetType::kDateTimeEdit:
+      pWidget = pdfium::MakeUnique<CXFA_FFDateTimeEdit>(pNode);
       break;
-    case XFA_Element::NumericEdit:
-      pWidget = new CXFA_FFNumericEdit(pNode);
+    case XFA_FFWidgetType::kImageEdit:
+      pWidget = pdfium::MakeUnique<CXFA_FFImageEdit>(pNode);
       break;
-    case XFA_Element::PasswordEdit:
-      pWidget = new CXFA_FFPasswordEdit(pNode);
+    case XFA_FFWidgetType::kNumericEdit:
+      pWidget = pdfium::MakeUnique<CXFA_FFNumericEdit>(pNode);
       break;
-    case XFA_Element::Signature:
-      pWidget = new CXFA_FFSignature(pNode);
-      break;
-    case XFA_Element::TextEdit:
-      pWidget = new CXFA_FFTextEdit(pNode);
-      break;
-    case XFA_Element::Arc:
-      pWidget = new CXFA_FFArc(pNode);
-      break;
-    case XFA_Element::Line:
-      pWidget = new CXFA_FFLine(pNode);
-      break;
-    case XFA_Element::Rectangle:
-      pWidget = new CXFA_FFRectangle(pNode);
-      break;
-    case XFA_Element::Text:
-      pWidget = new CXFA_FFText(pNode);
-      break;
-    case XFA_Element::Image:
-      pWidget = new CXFA_FFImage(pNode);
-      break;
-    case XFA_Element::Draw:
-      pWidget = new CXFA_FFDraw(pNode);
-      break;
-    case XFA_Element::Subform:
-      pWidget = new CXFA_FFSubForm(pNode);
-      break;
-    case XFA_Element::ExclGroup:
-      pWidget = new CXFA_FFExclGroup(pNode);
-      break;
-    case XFA_Element::DefaultUi:
-    default:
-      pWidget = nullptr;
-      break;
-  }
+    case XFA_FFWidgetType::kPasswordEdit: {
+      CXFA_Node* child = pNode->GetUIChildNode();
+      if (child->GetElementType() != XFA_Element::PasswordEdit)
+        return nullptr;
 
-  if (pWidget) {
-    CXFA_LayoutProcessor* pLayout = m_pDoc->GetXFADoc()->GetDocLayout();
-    pWidget->SetDocView(m_pDoc->GetDocView(pLayout));
+      pWidget = pdfium::MakeUnique<CXFA_FFPasswordEdit>(
+          pNode, static_cast<CXFA_PasswordEdit*>(child));
+      break;
+    }
+    case XFA_FFWidgetType::kSignature:
+      pWidget = pdfium::MakeUnique<CXFA_FFSignature>(pNode);
+      break;
+    case XFA_FFWidgetType::kTextEdit:
+      pWidget = pdfium::MakeUnique<CXFA_FFTextEdit>(pNode);
+      break;
+    case XFA_FFWidgetType::kArc:
+      pWidget = pdfium::MakeUnique<CXFA_FFArc>(pNode);
+      break;
+    case XFA_FFWidgetType::kLine:
+      pWidget = pdfium::MakeUnique<CXFA_FFLine>(pNode);
+      break;
+    case XFA_FFWidgetType::kRectangle:
+      pWidget = pdfium::MakeUnique<CXFA_FFRectangle>(pNode);
+      break;
+    case XFA_FFWidgetType::kText:
+      pWidget = pdfium::MakeUnique<CXFA_FFText>(pNode);
+      break;
+    case XFA_FFWidgetType::kImage:
+      pWidget = pdfium::MakeUnique<CXFA_FFImage>(pNode);
+      break;
+    case XFA_FFWidgetType::kSubform:
+      pWidget = pdfium::MakeUnique<CXFA_FFWidget>(pNode);
+      break;
+    case XFA_FFWidgetType::kExclGroup:
+      pWidget = pdfium::MakeUnique<CXFA_FFExclGroup>(pNode);
+      break;
+    case XFA_FFWidgetType::kNone:
+      return nullptr;
   }
+  ASSERT(pWidget);
+  auto* pLayout = CXFA_LayoutProcessor::FromDocument(m_pDoc->GetXFADoc());
+  pWidget->SetDocView(m_pDoc->GetDocView(pLayout));
   return pWidget;
 }
 
 void CXFA_FFNotify::StartFieldDrawLayout(CXFA_Node* pItem,
-                                         float& fCalcWidth,
-                                         float& fCalcHeight) {
-  CXFA_WidgetAcc* pAcc = pItem->GetWidgetAcc();
-  if (!pAcc)
-    return;
-
-  pAcc->StartWidgetLayout(m_pDoc.Get(), fCalcWidth, fCalcHeight);
-}
-
-bool CXFA_FFNotify::FindSplitPos(CXFA_Node* pItem,
-                                 int32_t iBlockIndex,
-                                 float& fCalcHeightPos) {
-  CXFA_WidgetAcc* pAcc = pItem->GetWidgetAcc();
-  return pAcc &&
-         pAcc->FindSplitPos(m_pDoc->GetDocView(), iBlockIndex, fCalcHeightPos);
+                                         float* pCalcWidth,
+                                         float* pCalcHeight) {
+  pItem->StartWidgetLayout(m_pDoc.Get(), pCalcWidth, pCalcHeight);
 }
 
 bool CXFA_FFNotify::RunScript(CXFA_Script* script, CXFA_Node* item) {
@@ -218,23 +202,21 @@
   CXFA_EventParam EventParam;
   EventParam.m_eType = XFA_EVENT_Unknown;
 
-  int32_t iRet;
+  XFA_EventError iRet;
   bool bRet;
   std::tie(iRet, bRet) = item->ExecuteBoolScript(pDocView, script, &EventParam);
-  return iRet == XFA_EVENTERROR_Success && bRet;
+  return iRet == XFA_EventError::kSuccess && bRet;
 }
 
-int32_t CXFA_FFNotify::ExecEventByDeepFirst(CXFA_Node* pFormNode,
-                                            XFA_EVENTTYPE eEventType,
-                                            bool bIsFormReady,
-                                            bool bRecursive,
-                                            CXFA_WidgetAcc* pExclude) {
+XFA_EventError CXFA_FFNotify::ExecEventByDeepFirst(CXFA_Node* pFormNode,
+                                                   XFA_EVENTTYPE eEventType,
+                                                   bool bIsFormReady,
+                                                   bool bRecursive) {
   CXFA_FFDocView* pDocView = m_pDoc->GetDocView();
   if (!pDocView)
-    return XFA_EVENTERROR_NotExist;
-  return pDocView->ExecEventActivityByDeepFirst(
-      pFormNode, eEventType, bIsFormReady, bRecursive,
-      pExclude ? pExclude->GetNode() : nullptr);
+    return XFA_EventError::kNotExist;
+  return pDocView->ExecEventActivityByDeepFirst(pFormNode, eEventType,
+                                                bIsFormReady, bRecursive);
 }
 
 void CXFA_FFNotify::AddCalcValidate(CXFA_Node* pNode) {
@@ -242,20 +224,8 @@
   if (!pDocView)
     return;
 
-  CXFA_WidgetAcc* pWidgetAcc = pNode->GetWidgetAcc();
-  if (!pWidgetAcc)
-    return;
-
-  pDocView->AddCalculateWidgetAcc(pWidgetAcc);
-  pDocView->AddValidateWidget(pWidgetAcc);
-}
-
-CXFA_FFDoc* CXFA_FFNotify::GetHDOC() {
-  return m_pDoc.Get();
-}
-
-IXFA_DocEnvironment* CXFA_FFNotify::GetDocEnvironment() const {
-  return m_pDoc->GetDocEnvironment();
+  pDocView->AddCalculateNode(pNode);
+  pDocView->AddValidateNode(pNode);
 }
 
 IXFA_AppProvider* CXFA_FFNotify::GetAppProvider() {
@@ -267,36 +237,47 @@
   return pDocView ? pDocView->GetWidgetHandler() : nullptr;
 }
 
-CXFA_FFWidget* CXFA_FFNotify::GetHWidget(CXFA_LayoutItem* pLayoutItem) {
-  return XFA_GetWidgetFromLayoutItem(pLayoutItem);
-}
+void CXFA_FFNotify::OpenDropDownList(CXFA_Node* pNode) {
+  auto* pDocLayout = CXFA_LayoutProcessor::FromDocument(m_pDoc->GetXFADoc());
+  CXFA_LayoutItem* pLayoutItem = pDocLayout->GetLayoutItem(pNode);
+  if (!pLayoutItem)
+    return;
 
-void CXFA_FFNotify::OpenDropDownList(CXFA_FFWidget* hWidget) {
-  if (hWidget->GetNode()->GetWidgetAcc()->GetUIType() !=
-      XFA_Element::ChoiceList)
+  CXFA_FFWidget* hWidget = XFA_GetWidgetFromLayoutItem(pLayoutItem);
+  if (!hWidget)
+    return;
+
+  // SetFocusWidget() may destroy |hWidget| object by JS callback.
+  ObservedPtr<CXFA_FFWidget> pObservedWidget(hWidget);
+  CXFA_FFDoc* hDoc = GetHDOC();
+  hDoc->GetDocEnvironment()->SetFocusWidget(hDoc, hWidget);
+  if (!pObservedWidget)
+    return;
+
+  if (hWidget->GetNode()->GetFFWidgetType() != XFA_FFWidgetType::kChoiceList)
+    return;
+
+  if (!hWidget->IsLoaded())
+    return;
+
+  CXFA_FFDropDown* pDropDown = ToDropDown(ToField(hWidget));
+  CXFA_FFComboBox* pComboBox = ToComboBox(pDropDown);
+  if (!pComboBox)
     return;
 
   CXFA_FFDocView* pDocView = m_pDoc->GetDocView();
   pDocView->LockUpdate();
-  ToComboBox(hWidget)->OpenDropDownList();
+  pComboBox->OpenDropDownList();
   pDocView->UnlockUpdate();
   pDocView->UpdateDocView();
 }
 
-WideString CXFA_FFNotify::GetCurrentDateTime() {
-  CFX_DateTime dataTime = CFX_DateTime::Now();
-  return WideString::Format(L"%d%02d%02dT%02d%02d%02d", dataTime.GetYear(),
-                            dataTime.GetMonth(), dataTime.GetDay(),
-                            dataTime.GetHour(), dataTime.GetMinute(),
-                            dataTime.GetSecond());
-}
-
-void CXFA_FFNotify::ResetData(CXFA_WidgetAcc* pWidgetAcc) {
+void CXFA_FFNotify::ResetData(CXFA_Node* pNode) {
   CXFA_FFDocView* pDocView = m_pDoc->GetDocView();
   if (!pDocView)
     return;
 
-  pDocView->ResetWidgetAcc(pWidgetAcc);
+  pDocView->ResetNode(pNode);
 }
 
 int32_t CXFA_FFNotify::GetLayoutStatus() {
@@ -322,20 +303,14 @@
 
 CXFA_Node* CXFA_FFNotify::GetFocusWidgetNode() {
   CXFA_FFDocView* pDocView = m_pDoc->GetDocView();
-  if (!pDocView)
-    return nullptr;
-
-  CXFA_WidgetAcc* pAcc = pDocView->GetFocusWidgetAcc();
-  return pAcc ? pAcc->GetNode() : nullptr;
+  return pDocView ? pDocView->GetFocusNode() : nullptr;
 }
 
 void CXFA_FFNotify::SetFocusWidgetNode(CXFA_Node* pNode) {
   CXFA_FFDocView* pDocView = m_pDoc->GetDocView();
   if (!pDocView)
     return;
-
-  CXFA_WidgetAcc* pAcc = pNode ? pNode->GetWidgetAcc() : nullptr;
-  pDocView->SetFocusWidgetAcc(pAcc);
+  pDocView->SetFocusNode(pNode);
 }
 
 void CXFA_FFNotify::OnNodeReady(CXFA_Node* pNode) {
@@ -344,7 +319,7 @@
     return;
 
   if (pNode->HasCreatedUIWidget()) {
-    pNode->CreateWidgetAcc();
+    pNode->SetWidgetReady();
     return;
   }
 
@@ -353,7 +328,7 @@
       pDocView->AddBindItem(static_cast<CXFA_BindItems*>(pNode));
       break;
     case XFA_Element::Validate:
-      pNode->SetFlag(XFA_NodeFlag_NeedsInitApp, false);
+      pNode->SetFlag(XFA_NodeFlag_NeedsInitApp);
       break;
     default:
       break;
@@ -374,15 +349,10 @@
   if (pDocView->GetLayoutStatus() < XFA_DOCVIEW_LAYOUTSTATUS_End)
     return;
 
-  CXFA_WidgetAcc* pWidgetAcc = pSender->GetWidgetAcc();
-  if (!pWidgetAcc)
-    return;
-
-  CXFA_FFWidget* pWidget =
-      m_pDoc->GetDocView()->GetWidgetForNode(pWidgetAcc->GetNode());
-  for (; pWidget; pWidget = pWidgetAcc->GetNextWidget(pWidget)) {
+  CXFA_FFWidget* pWidget = m_pDoc->GetDocView()->GetWidgetForNode(pSender);
+  for (; pWidget; pWidget = pWidget->GetNextFFWidget()) {
     if (pWidget->IsLoaded())
-      pWidget->AddInvalidateRect();
+      pWidget->InvalidateRect();
   }
 }
 
@@ -402,15 +372,11 @@
 
   XFA_Element eType = pParentNode->GetElementType();
   bool bIsContainerNode = pParentNode->IsContainerNode();
-  CXFA_WidgetAcc* pWidgetAcc = pWidgetNode->GetWidgetAcc();
-  if (!pWidgetAcc)
-    return;
-
   bool bUpdateProperty = false;
   pDocView->SetChangeMark();
   switch (eType) {
     case XFA_Element::Caption: {
-      CXFA_TextLayout* pCapOut = pWidgetAcc->GetCaptionTextLayout();
+      CXFA_TextLayout* pCapOut = pWidgetNode->GetCaptionTextLayout();
       if (!pCapOut)
         return;
 
@@ -431,30 +397,33 @@
     pDocView->AddCalculateNodeNotify(pSender);
     if (eType == XFA_Element::Value || bIsContainerNode) {
       if (bIsContainerNode) {
-        pWidgetAcc->UpdateUIDisplay(m_pDoc->GetDocView(), nullptr);
-        pDocView->AddCalculateWidgetAcc(pWidgetAcc);
-        pDocView->AddValidateWidget(pWidgetAcc);
+        m_pDoc->GetDocView()->UpdateUIDisplay(pWidgetNode, nullptr);
+        pDocView->AddCalculateNode(pWidgetNode);
+        pDocView->AddValidateNode(pWidgetNode);
       } else if (pWidgetNode->GetParent()->GetElementType() ==
                  XFA_Element::ExclGroup) {
-        pWidgetAcc->UpdateUIDisplay(m_pDoc->GetDocView(), nullptr);
+        m_pDoc->GetDocView()->UpdateUIDisplay(pWidgetNode, nullptr);
       }
       return;
     }
   }
 
-  CXFA_FFWidget* pWidget =
-      m_pDoc->GetDocView()->GetWidgetForNode(pWidgetAcc->GetNode());
-  for (; pWidget; pWidget = pWidgetAcc->GetNextWidget(pWidget)) {
+  CXFA_FFWidget* pWidget = m_pDoc->GetDocView()->GetWidgetForNode(pWidgetNode);
+  for (; pWidget; pWidget = pWidget->GetNextFFWidget()) {
     if (!pWidget->IsLoaded())
       continue;
 
     if (bUpdateProperty)
       pWidget->UpdateWidgetProperty();
     pWidget->PerformLayout();
-    pWidget->AddInvalidateRect();
+    pWidget->InvalidateRect();
   }
 }
 
+void CXFA_FFNotify::OnContainerChanged(CXFA_Node* pNode) {
+  m_pDoc->GetXFADoc()->GetLayoutProcessor()->AddChangedContainer(pNode);
+}
+
 void CXFA_FFNotify::OnChildAdded(CXFA_Node* pSender) {
   if (!pSender->IsFormContainer())
     return;
@@ -503,8 +472,7 @@
       (dwStatus & (XFA_WidgetStatus_Visible | XFA_WidgetStatus_Viewable)) ==
           (XFA_WidgetStatus_Visible | XFA_WidgetStatus_Viewable)) {
     pWidget->SetPageView(pNewPageView);
-    m_pDoc->GetDocEnvironment()->WidgetPostAdd(
-        pWidget, pWidget->GetNode()->GetWidgetAcc());
+    m_pDoc->GetDocEnvironment()->WidgetPostAdd(pWidget);
   }
   if (pDocView->GetLayoutStatus() != XFA_DOCVIEW_LAYOUTSTATUS_End ||
       !(dwStatus & XFA_WidgetStatus_Visible)) {
@@ -516,7 +484,7 @@
   } else {
     pWidget->LoadWidget();
   }
-  pWidget->AddInvalidateRect();
+  pWidget->InvalidateRect();
 }
 
 void CXFA_FFNotify::OnLayoutItemRemoving(CXFA_LayoutProcessor* pLayout,
@@ -530,7 +498,6 @@
     return;
 
   pDocView->DeleteLayoutItem(pWidget);
-  m_pDoc->GetDocEnvironment()->WidgetPreRemove(
-      pWidget, pWidget->GetNode()->GetWidgetAcc());
-  pWidget->AddInvalidateRect();
+  m_pDoc->GetDocEnvironment()->WidgetPreRemove(pWidget);
+  pWidget->InvalidateRect();
 }
diff --git a/xfa/fxfa/cxfa_ffnotify.h b/xfa/fxfa/cxfa_ffnotify.h
index 924a060..52fae1d 100644
--- a/xfa/fxfa/cxfa_ffnotify.h
+++ b/xfa/fxfa/cxfa_ffnotify.h
@@ -7,25 +7,30 @@
 #ifndef XFA_FXFA_CXFA_FFNOTIFY_H_
 #define XFA_FXFA_CXFA_FFNOTIFY_H_
 
+#include <memory>
+
 #include "xfa/fxfa/cxfa_eventparam.h"
+#include "xfa/fxfa/fxfa.h"
 #include "xfa/fxfa/parser/cxfa_document.h"
 
-class CXFA_FFWidgetHandler;
-class CXFA_ContainerLayoutItem;
 class CXFA_ContentLayoutItem;
+class CXFA_FFWidgetHandler;
+class CXFA_LayoutItem;
+class CXFA_LayoutProcessor;
+class CXFA_Script;
+class CXFA_ViewLayoutItem;
 
 class CXFA_FFNotify {
  public:
   explicit CXFA_FFNotify(CXFA_FFDoc* pDoc);
   ~CXFA_FFNotify();
 
-  void OnPageEvent(CXFA_ContainerLayoutItem* pSender, uint32_t dwEvent);
+  void OnPageEvent(CXFA_ViewLayoutItem* pSender, uint32_t dwEvent);
 
-  void OnWidgetListItemAdded(CXFA_WidgetAcc* pSender,
-                             const wchar_t* pLabel,
-                             const wchar_t* pValue,
+  void OnWidgetListItemAdded(CXFA_Node* pSender,
+                             const WideString& wsLabel,
                              int32_t iIndex);
-  void OnWidgetListItemRemoved(CXFA_WidgetAcc* pSender, int32_t iIndex);
+  void OnWidgetListItemRemoved(CXFA_Node* pSender, int32_t iIndex);
 
   // Node events
   void OnNodeReady(CXFA_Node* pNode);
@@ -34,11 +39,12 @@
                       XFA_Attribute eAttr,
                       CXFA_Node* pParentNode,
                       CXFA_Node* pWidgetNode);
+  void OnContainerChanged(CXFA_Node* pNode);
   void OnChildAdded(CXFA_Node* pSender);
   void OnChildRemoved();
 
-  CXFA_ContainerLayoutItem* OnCreateContainerLayoutItem(CXFA_Node* pNode);
-  CXFA_ContentLayoutItem* OnCreateContentLayoutItem(CXFA_Node* pNode);
+  std::unique_ptr<CXFA_FFPageView> OnCreateViewLayoutItem(CXFA_Node* pNode);
+  std::unique_ptr<CXFA_FFWidget> OnCreateContentLayoutItem(CXFA_Node* pNode);
 
   void OnLayoutItemAdded(CXFA_LayoutProcessor* pLayout,
                          CXFA_LayoutItem* pSender,
@@ -48,26 +54,19 @@
                             CXFA_LayoutItem* pSender);
 
   void StartFieldDrawLayout(CXFA_Node* pItem,
-                            float& fCalcWidth,
-                            float& fCalcHeight);
-  bool FindSplitPos(CXFA_Node* pItem,
-                    int32_t iBlockIndex,
-                    float& fCalcHeightPos);
+                            float* pCalcWidth,
+                            float* pCalcHeight);
   bool RunScript(CXFA_Script* pScript, CXFA_Node* pFormItem);
-  int32_t ExecEventByDeepFirst(CXFA_Node* pFormNode,
-                               XFA_EVENTTYPE eEventType,
-                               bool bIsFormReady = false,
-                               bool bRecursive = true,
-                               CXFA_WidgetAcc* pExclude = nullptr);
+  XFA_EventError ExecEventByDeepFirst(CXFA_Node* pFormNode,
+                                      XFA_EVENTTYPE eEventType,
+                                      bool bIsFormReady,
+                                      bool bRecursive);
   void AddCalcValidate(CXFA_Node* pNode);
-  CXFA_FFDoc* GetHDOC();
-  IXFA_DocEnvironment* GetDocEnvironment() const;
+  CXFA_FFDoc* GetHDOC() const { return m_pDoc.Get(); }
   IXFA_AppProvider* GetAppProvider();
   CXFA_FFWidgetHandler* GetWidgetHandler();
-  CXFA_FFWidget* GetHWidget(CXFA_LayoutItem* pLayoutItem);
-  void OpenDropDownList(CXFA_FFWidget* hWidget);
-  WideString GetCurrentDateTime();
-  void ResetData(CXFA_WidgetAcc* pWidgetAcc = nullptr);
+  void OpenDropDownList(CXFA_Node* pNode);
+  void ResetData(CXFA_Node* pNode);
   int32_t GetLayoutStatus();
   void RunNodeInitialize(CXFA_Node* pNode);
   void RunSubformIndexChange(CXFA_Node* pSubformNode);
diff --git a/xfa/fxfa/cxfa_ffnumericedit.cpp b/xfa/fxfa/cxfa_ffnumericedit.cpp
index b437bc2..8d1b3bb 100644
--- a/xfa/fxfa/cxfa_ffnumericedit.cpp
+++ b/xfa/fxfa/cxfa_ffnumericedit.cpp
@@ -8,6 +8,7 @@
 
 #include <utility>
 
+#include "third_party/base/ptr_util.h"
 #include "xfa/fwl/cfwl_edit.h"
 #include "xfa/fwl/cfwl_eventvalidate.h"
 #include "xfa/fwl/cfwl_notedriver.h"
@@ -19,31 +20,32 @@
 CXFA_FFNumericEdit::CXFA_FFNumericEdit(CXFA_Node* pNode)
     : CXFA_FFTextEdit(pNode) {}
 
-CXFA_FFNumericEdit::~CXFA_FFNumericEdit() {}
+CXFA_FFNumericEdit::~CXFA_FFNumericEdit() = default;
 
 bool CXFA_FFNumericEdit::LoadWidget() {
+  ASSERT(!IsLoaded());
   auto pNewEdit = pdfium::MakeUnique<CFWL_Edit>(
       GetFWLApp(), pdfium::MakeUnique<CFWL_WidgetProperties>(), nullptr);
   CFWL_Edit* pWidget = pNewEdit.get();
-  m_pNormalWidget = std::move(pNewEdit);
-  m_pNormalWidget->SetLayoutItem(this);
+  SetNormalWidget(std::move(pNewEdit));
+  pWidget->SetAdapterIface(this);
 
-  CFWL_NoteDriver* pNoteDriver =
-      m_pNormalWidget->GetOwnerApp()->GetNoteDriver();
-  pNoteDriver->RegisterEventTarget(m_pNormalWidget.get(),
-                                   m_pNormalWidget.get());
-  m_pOldDelegate = m_pNormalWidget->GetDelegate();
-  m_pNormalWidget->SetDelegate(this);
-  m_pNormalWidget->LockUpdate();
+  CFWL_NoteDriver* pNoteDriver = pWidget->GetOwnerApp()->GetNoteDriver();
+  pNoteDriver->RegisterEventTarget(pWidget, pWidget);
+  m_pOldDelegate = pWidget->GetDelegate();
+  pWidget->SetDelegate(this);
 
-  pWidget->SetText(m_pNode->GetWidgetAcc()->GetValue(XFA_VALUEPICTURE_Display));
-  UpdateWidgetProperty();
-  m_pNormalWidget->UnlockUpdate();
+  {
+    CFWL_Widget::ScopedUpdateLock update_lock(pWidget);
+    pWidget->SetText(m_pNode->GetValue(XFA_VALUEPICTURE_Display));
+    UpdateWidgetProperty();
+  }
+
   return CXFA_FFField::LoadWidget();
 }
 
 void CXFA_FFNumericEdit::UpdateWidgetProperty() {
-  CFWL_Edit* pWidget = static_cast<CFWL_Edit*>(m_pNormalWidget.get());
+  CFWL_Edit* pWidget = static_cast<CFWL_Edit*>(GetNormalWidget());
   if (!pWidget)
     return;
 
@@ -51,10 +53,10 @@
       FWL_STYLEEXT_EDT_ShowScrollbarFocus | FWL_STYLEEXT_EDT_OuterScrollbar |
       FWL_STYLEEXT_EDT_Validate | FWL_STYLEEXT_EDT_Number;
   dwExtendedStyle |= UpdateUIProperty();
-  if (!m_pNode->GetWidgetAcc()->IsHorizontalScrollPolicyOff())
+  if (!m_pNode->IsHorizontalScrollPolicyOff())
     dwExtendedStyle |= FWL_STYLEEXT_EDT_AutoHScroll;
 
-  Optional<int32_t> numCells = m_pNode->GetWidgetAcc()->GetNumberOfCells();
+  Optional<int32_t> numCells = m_pNode->GetNumberOfCells();
   if (numCells && *numCells > 0) {
     dwExtendedStyle |= FWL_STYLEEXT_EDT_CombText;
     pWidget->SetLimit(*numCells);
@@ -63,29 +65,27 @@
   if (!m_pNode->IsOpenAccess() || !GetDoc()->GetXFADoc()->IsInteractive())
     dwExtendedStyle |= FWL_STYLEEXT_EDT_ReadOnly;
 
-  m_pNormalWidget->ModifyStylesEx(dwExtendedStyle, 0xFFFFFFFF);
+  GetNormalWidget()->ModifyStylesEx(dwExtendedStyle, 0xFFFFFFFF);
 }
 
 void CXFA_FFNumericEdit::OnProcessEvent(CFWL_Event* pEvent) {
   if (pEvent->GetType() == CFWL_Event::Type::Validate) {
     CFWL_EventValidate* event = static_cast<CFWL_EventValidate*>(pEvent);
-    event->bValidate = OnValidate(m_pNormalWidget.get(), event->wsInsert);
+    event->bValidate = OnValidate(GetNormalWidget(), event->wsInsert);
     return;
   }
   CXFA_FFTextEdit::OnProcessEvent(pEvent);
 }
 
 bool CXFA_FFNumericEdit::OnValidate(CFWL_Widget* pWidget, WideString& wsText) {
-  WideString wsPattern =
-      m_pNode->GetWidgetAcc()->GetPictureContent(XFA_VALUEPICTURE_Edit);
+  WideString wsPattern = m_pNode->GetPictureContent(XFA_VALUEPICTURE_Edit);
   if (!wsPattern.IsEmpty())
     return true;
 
   WideString wsFormat;
   CXFA_LocaleValue widgetValue = XFA_GetLocaleValue(m_pNode.Get());
-  widgetValue.GetNumericFormat(wsFormat,
-                               m_pNode->GetWidgetAcc()->GetLeadDigits(),
-                               m_pNode->GetWidgetAcc()->GetFracDigits());
+  widgetValue.GetNumericFormat(wsFormat, m_pNode->GetLeadDigits(),
+                               m_pNode->GetFracDigits());
   return widgetValue.ValidateNumericTemp(wsText, wsFormat,
                                          m_pNode->GetLocale());
 }
diff --git a/xfa/fxfa/cxfa_ffnumericedit.h b/xfa/fxfa/cxfa_ffnumericedit.h
index c413ac6..b2c39ce 100644
--- a/xfa/fxfa/cxfa_ffnumericedit.h
+++ b/xfa/fxfa/cxfa_ffnumericedit.h
@@ -12,9 +12,8 @@
 
 class CFWL_Event;
 class CFWL_Widget;
-class CXFA_WidgetAcc;
 
-class CXFA_FFNumericEdit : public CXFA_FFTextEdit {
+class CXFA_FFNumericEdit final : public CXFA_FFTextEdit {
  public:
   explicit CXFA_FFNumericEdit(CXFA_Node* pNode);
   ~CXFA_FFNumericEdit() override;
diff --git a/xfa/fxfa/cxfa_ffpageview.cpp b/xfa/fxfa/cxfa_ffpageview.cpp
index fe1fbb5..1915152 100644
--- a/xfa/fxfa/cxfa_ffpageview.cpp
+++ b/xfa/fxfa/cxfa_ffpageview.cpp
@@ -28,38 +28,39 @@
 namespace {
 
 CFX_Matrix GetPageMatrix(const CFX_RectF& docPageRect,
-                         const CFX_Rect& devicePageRect,
+                         const FX_RECT& devicePageRect,
                          int32_t iRotate,
                          uint32_t dwCoordinatesType) {
-  ASSERT(iRotate >= 0 && iRotate <= 3);
+  ASSERT(iRotate >= 0);
+  ASSERT(iRotate <= 3);
 
   bool bFlipX = (dwCoordinatesType & 0x01) != 0;
   bool bFlipY = (dwCoordinatesType & 0x02) != 0;
   CFX_Matrix m((bFlipX ? -1.0f : 1.0f), 0, 0, (bFlipY ? -1.0f : 1.0f), 0, 0);
   if (iRotate == 0 || iRotate == 2) {
-    m.a *= (float)devicePageRect.width / docPageRect.width;
-    m.d *= (float)devicePageRect.height / docPageRect.height;
+    m.a *= (float)devicePageRect.Width() / docPageRect.width;
+    m.d *= (float)devicePageRect.Height() / docPageRect.height;
   } else {
-    m.a *= (float)devicePageRect.height / docPageRect.width;
-    m.d *= (float)devicePageRect.width / docPageRect.height;
+    m.a *= (float)devicePageRect.Height() / docPageRect.width;
+    m.d *= (float)devicePageRect.Width() / docPageRect.height;
   }
   m.Rotate(iRotate * 1.57079632675f);
   switch (iRotate) {
     case 0:
-      m.e = bFlipX ? (float)devicePageRect.right() : (float)devicePageRect.left;
-      m.f = bFlipY ? (float)devicePageRect.bottom() : (float)devicePageRect.top;
+      m.e = bFlipX ? devicePageRect.right : devicePageRect.left;
+      m.f = bFlipY ? devicePageRect.bottom : devicePageRect.top;
       break;
     case 1:
-      m.e = bFlipY ? (float)devicePageRect.left : (float)devicePageRect.right();
-      m.f = bFlipX ? (float)devicePageRect.bottom() : (float)devicePageRect.top;
+      m.e = bFlipY ? devicePageRect.left : devicePageRect.right;
+      m.f = bFlipX ? devicePageRect.bottom : devicePageRect.top;
       break;
     case 2:
-      m.e = bFlipX ? (float)devicePageRect.left : (float)devicePageRect.right();
-      m.f = bFlipY ? (float)devicePageRect.top : (float)devicePageRect.bottom();
+      m.e = bFlipX ? devicePageRect.left : devicePageRect.right;
+      m.f = bFlipY ? devicePageRect.top : devicePageRect.bottom;
       break;
     case 3:
-      m.e = bFlipY ? (float)devicePageRect.right() : (float)devicePageRect.left;
-      m.f = bFlipX ? (float)devicePageRect.top : (float)devicePageRect.bottom();
+      m.e = bFlipY ? devicePageRect.right : devicePageRect.left;
+      m.f = bFlipX ? devicePageRect.top : devicePageRect.bottom;
       break;
     default:
       break;
@@ -70,23 +71,23 @@
 bool PageWidgetFilter(CXFA_FFWidget* pWidget,
                       uint32_t dwFilter,
                       bool bTraversal,
-                      bool bIgnorerelevant) {
+                      bool bIgnoreRelevant) {
   CXFA_Node* pNode = pWidget->GetNode();
 
-  if (!!(dwFilter & XFA_WidgetStatus_Focused) &&
+  if ((dwFilter & XFA_WidgetStatus_Focused) &&
       (!pNode || pNode->GetElementType() != XFA_Element::Field)) {
     return false;
   }
 
-  uint32_t dwStatus = pWidget->GetStatus();
-  if (bTraversal && (dwStatus & XFA_WidgetStatus_Disabled))
+  CXFA_ContentLayoutItem* pItem = pWidget->GetLayoutItem();
+  if (bTraversal && pItem->TestStatusBits(XFA_WidgetStatus_Disabled))
     return false;
-  if (bIgnorerelevant)
-    return !!(dwStatus & XFA_WidgetStatus_Visible);
+  if (bIgnoreRelevant)
+    return pItem->TestStatusBits(XFA_WidgetStatus_Visible);
 
   dwFilter &= (XFA_WidgetStatus_Visible | XFA_WidgetStatus_Viewable |
                XFA_WidgetStatus_Printable);
-  return (dwFilter & dwStatus) == dwFilter;
+  return pItem->TestStatusBits(dwFilter);
 }
 
 bool IsLayoutElement(XFA_Element eElement, bool bLayoutContainer) {
@@ -110,7 +111,7 @@
 }  // namespace
 
 CXFA_FFPageView::CXFA_FFPageView(CXFA_FFDocView* pDocView, CXFA_Node* pPageArea)
-    : CXFA_ContainerLayoutItem(pPageArea), m_pDocView(pDocView) {}
+    : m_pPageArea(pPageArea), m_pDocView(pDocView) {}
 
 CXFA_FFPageView::~CXFA_FFPageView() {}
 
@@ -119,32 +120,32 @@
 }
 
 CFX_RectF CXFA_FFPageView::GetPageViewRect() const {
-  return CFX_RectF(0, 0, GetPageSize());
+  return CFX_RectF(0, 0, GetLayoutItem()->GetPageSize());
 }
 
-CFX_Matrix CXFA_FFPageView::GetDisplayMatrix(const CFX_Rect& rtDisp,
+CFX_Matrix CXFA_FFPageView::GetDisplayMatrix(const FX_RECT& rtDisp,
                                              int32_t iRotate) const {
-  return GetPageMatrix(CFX_RectF(0, 0, GetPageSize()), rtDisp, iRotate, 0);
+  return GetPageMatrix(CFX_RectF(0, 0, GetLayoutItem()->GetPageSize()), rtDisp,
+                       iRotate, 0);
 }
 
-std::unique_ptr<IXFA_WidgetIterator> CXFA_FFPageView::CreateWidgetIterator(
-    uint32_t dwTraverseWay,
+std::unique_ptr<IXFA_WidgetIterator> CXFA_FFPageView::CreateFormWidgetIterator(
     uint32_t dwWidgetFilter) {
-  switch (dwTraverseWay) {
-    case XFA_TRAVERSEWAY_Tranvalse:
-      return pdfium::MakeUnique<CXFA_FFTabOrderPageWidgetIterator>(
-          this, dwWidgetFilter);
-    case XFA_TRAVERSEWAY_Form:
-      return pdfium::MakeUnique<CXFA_FFPageWidgetIterator>(this,
-                                                           dwWidgetFilter);
-  }
-  return nullptr;
+  return pdfium::MakeUnique<CXFA_FFPageWidgetIterator>(this, dwWidgetFilter);
+}
+
+std::unique_ptr<IXFA_WidgetIterator>
+CXFA_FFPageView::CreateTraverseWidgetIterator(uint32_t dwWidgetFilter) {
+  return pdfium::MakeUnique<CXFA_FFTabOrderPageWidgetIterator>(this,
+                                                               dwWidgetFilter);
 }
 
 CXFA_FFPageWidgetIterator::CXFA_FFPageWidgetIterator(CXFA_FFPageView* pPageView,
                                                      uint32_t dwFilter)
-    : m_pPageView(pPageView), m_dwFilter(dwFilter), m_sIterator(pPageView) {
-  m_bIgnorerelevant =
+    : m_pPageView(pPageView),
+      m_dwFilter(dwFilter),
+      m_sIterator(pPageView->GetLayoutItem()) {
+  m_bIgnoreRelevant =
       m_pPageView->GetDocView()->GetDoc()->GetXFADoc()->GetCurVersionMode() <
       XFA_VERSION_205;
 }
@@ -196,8 +197,8 @@
   return pLayoutItem ? XFA_GetWidgetFromLayoutItem(pLayoutItem) : nullptr;
 }
 
-bool CXFA_FFPageWidgetIterator::SetCurrentWidget(CXFA_FFWidget* hWidget) {
-  return hWidget && m_sIterator.SetCurrent(hWidget);
+bool CXFA_FFPageWidgetIterator::SetCurrentWidget(CXFA_FFWidget* pWidget) {
+  return pWidget && m_sIterator.SetCurrent(pWidget->GetLayoutItem());
 }
 
 CXFA_FFWidget* CXFA_FFPageWidgetIterator::GetWidget(
@@ -206,11 +207,11 @@
   if (!pWidget)
     return nullptr;
 
-  if (!PageWidgetFilter(pWidget, m_dwFilter, false, m_bIgnorerelevant))
+  if (!PageWidgetFilter(pWidget, m_dwFilter, false, m_bIgnoreRelevant))
     return nullptr;
 
   if (!pWidget->IsLoaded() &&
-      !!(pWidget->GetStatus() & XFA_WidgetStatus_Visible)) {
+      pWidget->GetLayoutItem()->TestStatusBits(XFA_WidgetStatus_Visible)) {
     if (!pWidget->LoadWidget())
       return nullptr;
   }
@@ -231,7 +232,7 @@
     CXFA_FFPageView* pPageView,
     uint32_t dwFilter)
     : m_pPageView(pPageView), m_dwFilter(dwFilter), m_iCurWidget(-1) {
-  m_bIgnorerelevant =
+  m_bIgnoreRelevant =
       m_pPageView->GetDocView()->GetDoc()->GetXFADoc()->GetCurVersionMode() <
       XFA_VERSION_205;
   Reset();
@@ -247,10 +248,10 @@
 CXFA_FFWidget* CXFA_FFTabOrderPageWidgetIterator::MoveToFirst() {
   for (int32_t i = 0;
        i < pdfium::CollectionSize<int32_t>(m_TabOrderWidgetArray); i++) {
-    if (PageWidgetFilter(m_TabOrderWidgetArray[i], m_dwFilter, true,
-                         m_bIgnorerelevant)) {
+    if (PageWidgetFilter(m_TabOrderWidgetArray[i].Get(), m_dwFilter, true,
+                         m_bIgnoreRelevant)) {
       m_iCurWidget = i;
-      return m_TabOrderWidgetArray[m_iCurWidget];
+      return m_TabOrderWidgetArray[m_iCurWidget].Get();
     }
   }
   return nullptr;
@@ -259,10 +260,10 @@
 CXFA_FFWidget* CXFA_FFTabOrderPageWidgetIterator::MoveToLast() {
   for (int32_t i = pdfium::CollectionSize<int32_t>(m_TabOrderWidgetArray) - 1;
        i >= 0; i--) {
-    if (PageWidgetFilter(m_TabOrderWidgetArray[i], m_dwFilter, true,
-                         m_bIgnorerelevant)) {
+    if (PageWidgetFilter(m_TabOrderWidgetArray[i].Get(), m_dwFilter, true,
+                         m_bIgnoreRelevant)) {
       m_iCurWidget = i;
-      return m_TabOrderWidgetArray[m_iCurWidget];
+      return m_TabOrderWidgetArray[m_iCurWidget].Get();
     }
   }
   return nullptr;
@@ -271,10 +272,10 @@
 CXFA_FFWidget* CXFA_FFTabOrderPageWidgetIterator::MoveToNext() {
   for (int32_t i = m_iCurWidget + 1;
        i < pdfium::CollectionSize<int32_t>(m_TabOrderWidgetArray); i++) {
-    if (PageWidgetFilter(m_TabOrderWidgetArray[i], m_dwFilter, true,
-                         m_bIgnorerelevant)) {
+    if (PageWidgetFilter(m_TabOrderWidgetArray[i].Get(), m_dwFilter, true,
+                         m_bIgnoreRelevant)) {
       m_iCurWidget = i;
-      return m_TabOrderWidgetArray[m_iCurWidget];
+      return m_TabOrderWidgetArray[m_iCurWidget].Get();
     }
   }
   m_iCurWidget = -1;
@@ -283,10 +284,10 @@
 
 CXFA_FFWidget* CXFA_FFTabOrderPageWidgetIterator::MoveToPrevious() {
   for (int32_t i = m_iCurWidget - 1; i >= 0; i--) {
-    if (PageWidgetFilter(m_TabOrderWidgetArray[i], m_dwFilter, true,
-                         m_bIgnorerelevant)) {
+    if (PageWidgetFilter(m_TabOrderWidgetArray[i].Get(), m_dwFilter, true,
+                         m_bIgnoreRelevant)) {
       m_iCurWidget = i;
-      return m_TabOrderWidgetArray[m_iCurWidget];
+      return m_TabOrderWidgetArray[m_iCurWidget].Get();
     }
   }
   m_iCurWidget = -1;
@@ -294,7 +295,8 @@
 }
 
 CXFA_FFWidget* CXFA_FFTabOrderPageWidgetIterator::GetCurrentWidget() {
-  return m_iCurWidget >= 0 ? m_TabOrderWidgetArray[m_iCurWidget] : nullptr;
+  return m_iCurWidget >= 0 ? m_TabOrderWidgetArray[m_iCurWidget].Get()
+                           : nullptr;
 }
 
 bool CXFA_FFTabOrderPageWidgetIterator::SetCurrentWidget(
@@ -343,9 +345,9 @@
   while (pdfium::CollectionSize<int32_t>(m_TabOrderWidgetArray) <
          nWidgetCount) {
     if (!pdfium::ContainsValue(m_TabOrderWidgetArray, hWidget)) {
-      m_TabOrderWidgetArray.push_back(hWidget);
-      CXFA_WidgetAcc* pWidgetAcc = hWidget->GetNode()->GetWidgetAcc();
-      if (pWidgetAcc->GetUIType() == XFA_Element::ExclGroup) {
+      m_TabOrderWidgetArray.emplace_back(hWidget);
+      CXFA_Node* pNode = hWidget->GetNode();
+      if (pNode->GetFFWidgetType() == XFA_FFWidgetType::kExclGroup) {
         auto it = std::find(SpaceOrderWidgetArray.begin(),
                             SpaceOrderWidgetArray.end(), hWidget);
         int32_t iWidgetIndex = it != SpaceOrderWidgetArray.end()
@@ -354,10 +356,10 @@
         while (true) {
           CXFA_FFWidget* radio =
               SpaceOrderWidgetArray[iWidgetIndex % nWidgetCount];
-          if (radio->GetNode()->GetExclGroupIfExists() != pWidgetAcc->GetNode())
+          if (radio->GetNode()->GetExclGroupIfExists() != pNode)
             break;
           if (!pdfium::ContainsValue(m_TabOrderWidgetArray, hWidget))
-            m_TabOrderWidgetArray.push_back(radio);
+            m_TabOrderWidgetArray.emplace_back(radio);
 
           iWidgetIndex++;
         }
@@ -378,41 +380,41 @@
 
 void CXFA_FFTabOrderPageWidgetIterator::OrderContainer(
     CXFA_LayoutItemIterator* sIterator,
-    CXFA_LayoutItem* pContainerItem,
+    CXFA_LayoutItem* pViewItem,
     CXFA_TabParam* pContainer,
-    bool& bCurrentItem,
-    bool& bContentArea,
-    bool bMarsterPage) {
+    bool* bCurrentItem,
+    bool* bContentArea,
+    bool bMasterPage) {
   std::vector<std::unique_ptr<CXFA_TabParam>> tabParams;
   CXFA_LayoutItem* pSearchItem = sIterator->MoveToNext();
   while (pSearchItem) {
     if (!pSearchItem->IsContentLayoutItem()) {
-      bContentArea = true;
+      *bContentArea = true;
       pSearchItem = sIterator->MoveToNext();
       continue;
     }
-    if (bMarsterPage && bContentArea) {
+    if (bMasterPage && *bContentArea) {
       break;
     }
-    if (bMarsterPage || bContentArea) {
+    if (bMasterPage || *bContentArea) {
       CXFA_FFWidget* hWidget = GetWidget(pSearchItem);
       if (!hWidget) {
         pSearchItem = sIterator->MoveToNext();
         continue;
       }
-      if (pContainerItem && (pSearchItem->GetParent() != pContainerItem)) {
-        bCurrentItem = true;
+      if (pViewItem && (pSearchItem->GetParent() != pViewItem)) {
+        *bCurrentItem = true;
         break;
       }
       tabParams.push_back(pdfium::MakeUnique<CXFA_TabParam>(hWidget));
       if (IsLayoutElement(pSearchItem->GetFormNode()->GetElementType(), true)) {
         OrderContainer(sIterator, pSearchItem, tabParams.back().get(),
-                       bCurrentItem, bContentArea, bMarsterPage);
+                       bCurrentItem, bContentArea, bMasterPage);
       }
     }
-    if (bCurrentItem) {
+    if (*bCurrentItem) {
       pSearchItem = sIterator->GetCurrent();
-      bCurrentItem = false;
+      *bCurrentItem = false;
     } else {
       pSearchItem = sIterator->MoveToNext();
     }
@@ -422,7 +424,7 @@
                const std::unique_ptr<CXFA_TabParam>& arg2) {
               const CFX_RectF& rt1 = arg1->GetWidget()->GetWidgetRect();
               const CFX_RectF& rt2 = arg2->GetWidget()->GetWidgetRect();
-              if (rt1.top - rt2.top >= XFA_FLOAT_PERCISION)
+              if (rt1.top - rt2.top >= kXFAWidgetPrecision)
                 return rt1.top < rt2.top;
               return rt1.left < rt2.left;
             });
@@ -432,11 +434,12 @@
 
 void CXFA_FFTabOrderPageWidgetIterator::CreateSpaceOrderWidgetArray(
     std::vector<CXFA_FFWidget*>* WidgetArray) {
-  CXFA_LayoutItemIterator sIterator(m_pPageView);
+  CXFA_LayoutItemIterator sIterator(m_pPageView->GetLayoutItem());
   auto pParam = pdfium::MakeUnique<CXFA_TabParam>(nullptr);
   bool bCurrentItem = false;
   bool bContentArea = false;
-  OrderContainer(&sIterator, nullptr, pParam.get(), bCurrentItem, bContentArea);
+  OrderContainer(&sIterator, nullptr, pParam.get(), &bCurrentItem,
+                 &bContentArea, false);
   WidgetArray->insert(WidgetArray->end(), pParam->GetChildren().begin(),
                       pParam->GetChildren().end());
 
@@ -444,22 +447,23 @@
   bCurrentItem = false;
   bContentArea = false;
   pParam->ClearChildren();
-  OrderContainer(&sIterator, nullptr, pParam.get(), bCurrentItem, bContentArea,
-                 true);
+  OrderContainer(&sIterator, nullptr, pParam.get(), &bCurrentItem,
+                 &bContentArea, true);
   WidgetArray->insert(WidgetArray->end(), pParam->GetChildren().begin(),
                       pParam->GetChildren().end());
 }
 
 CXFA_FFWidget* CXFA_FFTabOrderPageWidgetIterator::GetWidget(
     CXFA_LayoutItem* pLayoutItem) {
-  if (CXFA_FFWidget* pWidget = XFA_GetWidgetFromLayoutItem(pLayoutItem)) {
-    if (!pWidget->IsLoaded() &&
-        (pWidget->GetStatus() & XFA_WidgetStatus_Visible)) {
-      pWidget->LoadWidget();
-    }
-    return pWidget;
+  CXFA_FFWidget* pWidget = XFA_GetWidgetFromLayoutItem(pLayoutItem);
+  if (!pWidget)
+    return nullptr;
+
+  if (!pWidget->IsLoaded() &&
+      pWidget->GetLayoutItem()->TestStatusBits(XFA_WidgetStatus_Visible)) {
+    pWidget->LoadWidget();
   }
-  return nullptr;
+  return pWidget;
 }
 
 CXFA_TabParam::CXFA_TabParam(CXFA_FFWidget* pWidget) : m_pWidget(pWidget) {}
diff --git a/xfa/fxfa/cxfa_ffpageview.h b/xfa/fxfa/cxfa_ffpageview.h
index b33e25f..65c0b95 100644
--- a/xfa/fxfa/cxfa_ffpageview.h
+++ b/xfa/fxfa/cxfa_ffpageview.h
@@ -1,4 +1,4 @@
-// Copyrig 2014 PDFium Authors. All rights reserved.
+// Copyright 2014 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.
 
@@ -10,35 +10,39 @@
 #include <memory>
 #include <vector>
 
-#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 "core/fxcrt/observed_ptr.h"
+#include "xfa/fxfa/layout/cxfa_contentlayoutitem.h"
+#include "xfa/fxfa/layout/cxfa_traversestrategy_layoutitem.h"
+#include "xfa/fxfa/layout/cxfa_viewlayoutitem.h"
 
 class CXFA_FFWidget;
 class CXFA_FFDocView;
 
-class CXFA_FFPageView : public CXFA_ContainerLayoutItem {
+class CXFA_FFPageView : public Observable {
  public:
   CXFA_FFPageView(CXFA_FFDocView* pDocView, CXFA_Node* pPageArea);
-  ~CXFA_FFPageView() override;
+  ~CXFA_FFPageView();
+
+  CXFA_ViewLayoutItem* GetLayoutItem() const { return m_pLayoutItem.Get(); }
+  void SetLayoutItem(CXFA_ViewLayoutItem* pItem) { m_pLayoutItem = pItem; }
 
   CXFA_FFDocView* GetDocView() const;
   CFX_RectF GetPageViewRect() const;
-  CFX_Matrix GetDisplayMatrix(const CFX_Rect& rtDisp, int32_t iRotate) const;
-  std::unique_ptr<IXFA_WidgetIterator> CreateWidgetIterator(
-      uint32_t dwTraverseWay,
+  CFX_Matrix GetDisplayMatrix(const FX_RECT& rtDisp, int32_t iRotate) const;
+
+  // These always return a non-null iterator.
+  std::unique_ptr<IXFA_WidgetIterator> CreateFormWidgetIterator(
+      uint32_t dwWidgetFilter);
+  std::unique_ptr<IXFA_WidgetIterator> CreateTraverseWidgetIterator(
       uint32_t dwWidgetFilter);
 
- protected:
+ private:
+  UnownedPtr<CXFA_Node> const m_pPageArea;
   UnownedPtr<CXFA_FFDocView> const m_pDocView;
+  UnownedPtr<CXFA_ViewLayoutItem> m_pLayoutItem;
 };
 
-using CXFA_LayoutItemIterator =
-    CXFA_NodeIteratorTemplate<CXFA_LayoutItem,
-                              CXFA_TraverseStrategy_LayoutItem>;
-
-class CXFA_FFPageWidgetIterator : public IXFA_WidgetIterator {
+class CXFA_FFPageWidgetIterator final : public IXFA_WidgetIterator {
  public:
   CXFA_FFPageWidgetIterator(CXFA_FFPageView* pPageView, uint32_t dwFilter);
   ~CXFA_FFPageWidgetIterator() override;
@@ -51,13 +55,13 @@
   CXFA_FFWidget* GetCurrentWidget() override;
   bool SetCurrentWidget(CXFA_FFWidget* hWidget) override;
 
- protected:
+ private:
   CXFA_FFWidget* GetWidget(CXFA_LayoutItem* pLayoutItem);
 
-  CXFA_FFPageView* m_pPageView;
-  CXFA_FFWidget* m_hCurWidget;
+  UnownedPtr<CXFA_FFPageView> m_pPageView;
+  UnownedPtr<CXFA_FFWidget> m_hCurWidget;
   uint32_t m_dwFilter;
-  bool m_bIgnorerelevant;
+  bool m_bIgnoreRelevant;
   CXFA_LayoutItemIterator m_sIterator;
 };
 
@@ -76,7 +80,7 @@
   std::vector<CXFA_FFWidget*> m_Children;
 };
 
-class CXFA_FFTabOrderPageWidgetIterator : public IXFA_WidgetIterator {
+class CXFA_FFTabOrderPageWidgetIterator final : public IXFA_WidgetIterator {
  public:
   CXFA_FFTabOrderPageWidgetIterator(CXFA_FFPageView* pPageView,
                                     uint32_t dwFilter);
@@ -90,7 +94,7 @@
   CXFA_FFWidget* GetCurrentWidget() override;
   bool SetCurrentWidget(CXFA_FFWidget* hWidget) override;
 
- protected:
+ private:
   CXFA_FFWidget* GetTraverseWidget(CXFA_FFWidget* pWidget);
   CXFA_FFWidget* FindWidgetByName(const WideString& wsWidgetName,
                                   CXFA_FFWidget* pRefWidget);
@@ -98,17 +102,17 @@
   void CreateSpaceOrderWidgetArray(std::vector<CXFA_FFWidget*>* WidgetArray);
   CXFA_FFWidget* GetWidget(CXFA_LayoutItem* pLayoutItem);
   void OrderContainer(CXFA_LayoutItemIterator* sIterator,
-                      CXFA_LayoutItem* pContainerItem,
+                      CXFA_LayoutItem* pViewItem,
                       CXFA_TabParam* pContainer,
-                      bool& bCurrentItem,
-                      bool& bContentArea,
-                      bool bMarsterPage = false);
+                      bool* bCurrentItem,
+                      bool* bContentArea,
+                      bool bMasterPage);
 
-  std::vector<CXFA_FFWidget*> m_TabOrderWidgetArray;
-  CXFA_FFPageView* m_pPageView;
+  std::vector<UnownedPtr<CXFA_FFWidget>> m_TabOrderWidgetArray;
+  UnownedPtr<CXFA_FFPageView> m_pPageView;
   uint32_t m_dwFilter;
   int32_t m_iCurWidget;
-  bool m_bIgnorerelevant;
+  bool m_bIgnoreRelevant;
 };
 
 #endif  // XFA_FXFA_CXFA_FFPAGEVIEW_H_
diff --git a/xfa/fxfa/cxfa_ffpasswordedit.cpp b/xfa/fxfa/cxfa_ffpasswordedit.cpp
index 15bd5fa..8019c5c 100644
--- a/xfa/fxfa/cxfa_ffpasswordedit.cpp
+++ b/xfa/fxfa/cxfa_ffpasswordedit.cpp
@@ -8,39 +8,43 @@
 
 #include <utility>
 
+#include "third_party/base/ptr_util.h"
 #include "xfa/fwl/cfwl_edit.h"
 #include "xfa/fwl/cfwl_notedriver.h"
 #include "xfa/fxfa/cxfa_ffdoc.h"
 #include "xfa/fxfa/parser/cxfa_node.h"
+#include "xfa/fxfa/parser/cxfa_passwordedit.h"
 
-CXFA_FFPasswordEdit::CXFA_FFPasswordEdit(CXFA_Node* pNode)
-    : CXFA_FFTextEdit(pNode) {}
+CXFA_FFPasswordEdit::CXFA_FFPasswordEdit(CXFA_Node* pNode,
+                                         CXFA_PasswordEdit* password_node)
+    : CXFA_FFTextEdit(pNode), password_node_(password_node) {}
 
-CXFA_FFPasswordEdit::~CXFA_FFPasswordEdit() {}
+CXFA_FFPasswordEdit::~CXFA_FFPasswordEdit() = default;
 
 bool CXFA_FFPasswordEdit::LoadWidget() {
+  ASSERT(!IsLoaded());
   auto pNewEdit = pdfium::MakeUnique<CFWL_Edit>(
       GetFWLApp(), pdfium::MakeUnique<CFWL_WidgetProperties>(), nullptr);
   CFWL_Edit* pWidget = pNewEdit.get();
-  m_pNormalWidget = std::move(pNewEdit);
-  m_pNormalWidget->SetLayoutItem(this);
+  SetNormalWidget(std::move(pNewEdit));
+  pWidget->SetAdapterIface(this);
 
-  CFWL_NoteDriver* pNoteDriver =
-      m_pNormalWidget->GetOwnerApp()->GetNoteDriver();
-  pNoteDriver->RegisterEventTarget(m_pNormalWidget.get(),
-                                   m_pNormalWidget.get());
-  m_pOldDelegate = m_pNormalWidget->GetDelegate();
-  m_pNormalWidget->SetDelegate(this);
-  m_pNormalWidget->LockUpdate();
+  CFWL_NoteDriver* pNoteDriver = pWidget->GetOwnerApp()->GetNoteDriver();
+  pNoteDriver->RegisterEventTarget(pWidget, pWidget);
+  m_pOldDelegate = pWidget->GetDelegate();
+  pWidget->SetDelegate(this);
 
-  pWidget->SetText(m_pNode->GetWidgetAcc()->GetValue(XFA_VALUEPICTURE_Display));
-  UpdateWidgetProperty();
-  m_pNormalWidget->UnlockUpdate();
+  {
+    CFWL_Widget::ScopedUpdateLock update_lock(pWidget);
+    pWidget->SetText(m_pNode->GetValue(XFA_VALUEPICTURE_Display));
+    UpdateWidgetProperty();
+  }
+
   return CXFA_FFField::LoadWidget();
 }
 
 void CXFA_FFPasswordEdit::UpdateWidgetProperty() {
-  CFWL_Edit* pWidget = static_cast<CFWL_Edit*>(m_pNormalWidget.get());
+  CFWL_Edit* pWidget = static_cast<CFWL_Edit*>(GetNormalWidget());
   if (!pWidget)
     return;
 
@@ -49,14 +53,14 @@
                              FWL_STYLEEXT_EDT_Password;
   dwExtendedStyle |= UpdateUIProperty();
 
-  WideString password = m_pNode->GetWidgetAcc()->GetPasswordChar();
+  WideString password = password_node_->GetPasswordChar();
   if (!password.IsEmpty())
     pWidget->SetAliasChar(password[0]);
-  if (!m_pNode->GetWidgetAcc()->IsHorizontalScrollPolicyOff())
+  if (!m_pNode->IsHorizontalScrollPolicyOff())
     dwExtendedStyle |= FWL_STYLEEXT_EDT_AutoHScroll;
   if (!m_pNode->IsOpenAccess() || !GetDoc()->GetXFADoc()->IsInteractive())
     dwExtendedStyle |= FWL_STYLEEXT_EDT_ReadOnly;
 
   dwExtendedStyle |= GetAlignment();
-  m_pNormalWidget->ModifyStylesEx(dwExtendedStyle, 0xFFFFFFFF);
+  GetNormalWidget()->ModifyStylesEx(dwExtendedStyle, 0xFFFFFFFF);
 }
diff --git a/xfa/fxfa/cxfa_ffpasswordedit.h b/xfa/fxfa/cxfa_ffpasswordedit.h
index da7279a..a96efa0 100644
--- a/xfa/fxfa/cxfa_ffpasswordedit.h
+++ b/xfa/fxfa/cxfa_ffpasswordedit.h
@@ -7,18 +7,22 @@
 #ifndef XFA_FXFA_CXFA_FFPASSWORDEDIT_H_
 #define XFA_FXFA_CXFA_FFPASSWORDEDIT_H_
 
+#include "core/fxcrt/unowned_ptr.h"
 #include "xfa/fxfa/cxfa_fftextedit.h"
 
-class CXFA_WidgetAcc;
+class CXFA_PasswordEdit;
 
-class CXFA_FFPasswordEdit : public CXFA_FFTextEdit {
+class CXFA_FFPasswordEdit final : public CXFA_FFTextEdit {
  public:
-  explicit CXFA_FFPasswordEdit(CXFA_Node* pNode);
+  CXFA_FFPasswordEdit(CXFA_Node* pNode, CXFA_PasswordEdit* password_node);
   ~CXFA_FFPasswordEdit() override;
 
   // CXFA_FFTextEdit
   bool LoadWidget() override;
   void UpdateWidgetProperty() override;
+
+ private:
+  UnownedPtr<CXFA_PasswordEdit> const password_node_;
 };
 
 #endif  // XFA_FXFA_CXFA_FFPASSWORDEDIT_H_
diff --git a/xfa/fxfa/cxfa_ffpushbutton.cpp b/xfa/fxfa/cxfa_ffpushbutton.cpp
index fdf7512..7f2a06e 100644
--- a/xfa/fxfa/cxfa_ffpushbutton.cpp
+++ b/xfa/fxfa/cxfa_ffpushbutton.cpp
@@ -8,6 +8,7 @@
 
 #include <utility>
 
+#include "core/fxge/render_defines.h"
 #include "third_party/base/ptr_util.h"
 #include "xfa/fwl/cfwl_notedriver.h"
 #include "xfa/fwl/cfwl_pushbutton.h"
@@ -19,80 +20,72 @@
 #include "xfa/fxfa/cxfa_textlayout.h"
 #include "xfa/fxfa/cxfa_textprovider.h"
 #include "xfa/fxfa/parser/cxfa_border.h"
+#include "xfa/fxfa/parser/cxfa_button.h"
 #include "xfa/fxfa/parser/cxfa_caption.h"
 #include "xfa/fxfa/parser/cxfa_edge.h"
 #include "xfa/fxgraphics/cxfa_gecolor.h"
 #include "xfa/fxgraphics/cxfa_gepath.h"
 
-CXFA_FFPushButton::CXFA_FFPushButton(CXFA_Node* pNode)
-    : CXFA_FFField(pNode), m_pOldDelegate(nullptr) {}
+CXFA_FFPushButton::CXFA_FFPushButton(CXFA_Node* pNode, CXFA_Button* button)
+    : CXFA_FFField(pNode), button_(button) {}
 
-CXFA_FFPushButton::~CXFA_FFPushButton() {
-  CXFA_FFPushButton::UnloadWidget();
-}
+CXFA_FFPushButton::~CXFA_FFPushButton() = default;
 
 void CXFA_FFPushButton::RenderWidget(CXFA_Graphics* pGS,
                                      const CFX_Matrix& matrix,
-                                     uint32_t dwStatus) {
-  if (!IsMatchVisibleStatus(dwStatus))
+                                     HighlightOption highlight) {
+  if (!HasVisibleStatus())
     return;
 
   CFX_Matrix mtRotate = GetRotateMatrix();
   mtRotate.Concat(matrix);
 
-  CXFA_FFWidget::RenderWidget(pGS, mtRotate, dwStatus);
+  CXFA_FFWidget::RenderWidget(pGS, mtRotate, highlight);
   RenderHighlightCaption(pGS, &mtRotate);
 
   CFX_RectF rtWidget = GetRectWithoutRotate();
   CFX_Matrix mt(1, 0, 0, 1, rtWidget.left, rtWidget.top);
   mt.Concat(mtRotate);
-  GetApp()->GetFWLWidgetMgr()->OnDrawWidget(m_pNormalWidget.get(), pGS, mt);
+  GetApp()->GetFWLWidgetMgr()->OnDrawWidget(GetNormalWidget(), pGS, mt);
 }
 
 bool CXFA_FFPushButton::LoadWidget() {
-  ASSERT(!m_pNormalWidget);
+  ASSERT(!IsLoaded());
   auto pNew = pdfium::MakeUnique<CFWL_PushButton>(GetFWLApp());
   CFWL_PushButton* pPushButton = pNew.get();
   m_pOldDelegate = pPushButton->GetDelegate();
   pPushButton->SetDelegate(this);
-  m_pNormalWidget = std::move(pNew);
-  m_pNormalWidget->SetLayoutItem(this);
+  SetNormalWidget(std::move(pNew));
+  pPushButton->SetAdapterIface(this);
 
-  CFWL_NoteDriver* pNoteDriver =
-      m_pNormalWidget->GetOwnerApp()->GetNoteDriver();
-  pNoteDriver->RegisterEventTarget(m_pNormalWidget.get(),
-                                   m_pNormalWidget.get());
-  m_pNormalWidget->LockUpdate();
-  UpdateWidgetProperty();
-  LoadHighlightCaption();
-  m_pNormalWidget->UnlockUpdate();
+  CFWL_NoteDriver* pNoteDriver = pPushButton->GetOwnerApp()->GetNoteDriver();
+  pNoteDriver->RegisterEventTarget(pPushButton, pPushButton);
+
+  {
+    CFWL_Widget::ScopedUpdateLock update_lock(pPushButton);
+    UpdateWidgetProperty();
+    LoadHighlightCaption();
+  }
+
   return CXFA_FFField::LoadWidget();
 }
 
 void CXFA_FFPushButton::UpdateWidgetProperty() {
   uint32_t dwStyleEx = 0;
-  switch (m_pNode->GetWidgetAcc()->GetButtonHighlight()) {
-    case XFA_AttributeEnum::Inverted:
+  switch (button_->GetHighlight()) {
+    case XFA_AttributeValue::Inverted:
       dwStyleEx = XFA_FWL_PSBSTYLEEXT_HiliteInverted;
       break;
-    case XFA_AttributeEnum::Outline:
+    case XFA_AttributeValue::Outline:
       dwStyleEx = XFA_FWL_PSBSTYLEEXT_HiliteOutLine;
       break;
-    case XFA_AttributeEnum::Push:
+    case XFA_AttributeValue::Push:
       dwStyleEx = XFA_FWL_PSBSTYLEEXT_HilitePush;
       break;
     default:
       break;
   }
-  m_pNormalWidget->ModifyStylesEx(dwStyleEx, 0xFFFFFFFF);
-}
-
-void CXFA_FFPushButton::UnloadWidget() {
-  m_pRolloverTextLayout.reset();
-  m_pDownTextLayout.reset();
-  m_pRollProvider.reset();
-  m_pDownProvider.reset();
-  CXFA_FFField::UnloadWidget();
+  GetNormalWidget()->ModifyStylesEx(dwStyleEx, 0xFFFFFFFF);
 }
 
 bool CXFA_FFPushButton::PerformLayout() {
@@ -101,27 +94,25 @@
 
   m_rtUI = rtWidget;
   CXFA_Margin* margin = m_pNode->GetMarginIfExists();
-  if (margin)
-    XFA_RectWithoutMargin(rtWidget, margin);
+  XFA_RectWithoutMargin(&rtWidget, margin);
 
   m_rtCaption = rtWidget;
 
   CXFA_Caption* caption = m_pNode->GetCaptionIfExists();
   CXFA_Margin* captionMargin = caption ? caption->GetMarginIfExists() : nullptr;
-  if (captionMargin)
-    XFA_RectWithoutMargin(m_rtCaption, captionMargin);
+  XFA_RectWithoutMargin(&m_rtCaption, captionMargin);
 
   LayoutHighlightCaption();
   SetFWLRect();
-  if (m_pNormalWidget)
-    m_pNormalWidget->Update();
+  if (GetNormalWidget())
+    GetNormalWidget()->Update();
 
   return true;
 }
 
 float CXFA_FFPushButton::GetLineWidth() {
   CXFA_Border* border = m_pNode->GetBorderIfExists();
-  if (border && border->GetPresence() == XFA_AttributeEnum::Visible) {
+  if (border && border->GetPresence() == XFA_AttributeValue::Visible) {
     CXFA_Edge* edge = border->GetEdgeIfExists(0);
     return edge ? edge->GetThickness() : 0;
   }
@@ -141,19 +132,19 @@
   if (!caption || caption->IsHidden())
     return;
 
-  if (m_pNode->GetWidgetAcc()->HasButtonRollover()) {
+  if (m_pNode->HasButtonRollover()) {
     if (!m_pRollProvider) {
       m_pRollProvider = pdfium::MakeUnique<CXFA_TextProvider>(
-          m_pNode->GetWidgetAcc(), XFA_TEXTPROVIDERTYPE_Rollover);
+          m_pNode.Get(), XFA_TEXTPROVIDERTYPE_Rollover);
     }
     m_pRolloverTextLayout =
         pdfium::MakeUnique<CXFA_TextLayout>(GetDoc(), m_pRollProvider.get());
   }
 
-  if (m_pNode->GetWidgetAcc()->HasButtonDown()) {
+  if (m_pNode->HasButtonDown()) {
     if (!m_pDownProvider) {
       m_pDownProvider = pdfium::MakeUnique<CXFA_TextProvider>(
-          m_pNode->GetWidgetAcc(), XFA_TEXTPROVIDERTYPE_Down);
+          m_pNode.Get(), XFA_TEXTPROVIDERTYPE_Down);
     }
     m_pDownTextLayout =
         pdfium::MakeUnique<CXFA_TextLayout>(GetDoc(), m_pDownProvider.get());
@@ -171,8 +162,7 @@
 
 void CXFA_FFPushButton::RenderHighlightCaption(CXFA_Graphics* pGS,
                                                CFX_Matrix* pMatrix) {
-  CXFA_TextLayout* pCapTextLayout =
-      m_pNode->GetWidgetAcc()->GetCaptionTextLayout();
+  CXFA_TextLayout* pCapTextLayout = m_pNode->GetCaptionTextLayout();
   CXFA_Caption* caption = m_pNode->GetCaptionIfExists();
   if (!caption || !caption->IsVisible())
     return;
@@ -186,7 +176,7 @@
     mt.Concat(*pMatrix);
   }
 
-  uint32_t dwState = m_pNormalWidget->GetStates();
+  uint32_t dwState = GetNormalWidget()->GetStates();
   if (m_pDownTextLayout && (dwState & FWL_STATE_PSB_Pressed) &&
       (dwState & FWL_STATE_PSB_Hovered)) {
     if (m_pDownTextLayout->DrawString(pRenderDevice, mt, rtClip, 0))
@@ -211,29 +201,30 @@
 
 void CXFA_FFPushButton::OnDrawWidget(CXFA_Graphics* pGraphics,
                                      const CFX_Matrix& matrix) {
-  if (m_pNormalWidget->GetStylesEx() & XFA_FWL_PSBSTYLEEXT_HiliteInverted) {
-    if ((m_pNormalWidget->GetStates() & FWL_STATE_PSB_Pressed) &&
-        (m_pNormalWidget->GetStates() & FWL_STATE_PSB_Hovered)) {
-      CFX_RectF rtFill(0, 0, m_pNormalWidget->GetWidgetRect().Size());
+  auto* pWidget = GetNormalWidget();
+  if (pWidget->GetStylesEx() & XFA_FWL_PSBSTYLEEXT_HiliteInverted) {
+    if ((pWidget->GetStates() & FWL_STATE_PSB_Pressed) &&
+        (pWidget->GetStates() & FWL_STATE_PSB_Hovered)) {
+      CFX_RectF rtFill(0, 0, pWidget->GetWidgetRect().Size());
       float fLineWith = GetLineWidth();
       rtFill.Deflate(fLineWith, fLineWith);
       CXFA_GEPath path;
       path.AddRectangle(rtFill.left, rtFill.top, rtFill.width, rtFill.height);
-      pGraphics->SetFillColor(CXFA_GEColor(FXARGB_MAKE(128, 128, 255, 255)));
+      pGraphics->SetFillColor(CXFA_GEColor(ArgbEncode(128, 128, 255, 255)));
       pGraphics->FillPath(&path, FXFILL_WINDING, &matrix);
     }
     return;
   }
 
-  if (m_pNormalWidget->GetStylesEx() & XFA_FWL_PSBSTYLEEXT_HiliteOutLine) {
-    if ((m_pNormalWidget->GetStates() & FWL_STATE_PSB_Pressed) &&
-        (m_pNormalWidget->GetStates() & FWL_STATE_PSB_Hovered)) {
+  if (pWidget->GetStylesEx() & XFA_FWL_PSBSTYLEEXT_HiliteOutLine) {
+    if ((pWidget->GetStates() & FWL_STATE_PSB_Pressed) &&
+        (pWidget->GetStates() & FWL_STATE_PSB_Hovered)) {
       float fLineWidth = GetLineWidth();
-      pGraphics->SetStrokeColor(CXFA_GEColor(FXARGB_MAKE(255, 128, 255, 255)));
+      pGraphics->SetStrokeColor(CXFA_GEColor(ArgbEncode(255, 128, 255, 255)));
       pGraphics->SetLineWidth(fLineWidth);
 
       CXFA_GEPath path;
-      CFX_RectF rect = m_pNormalWidget->GetWidgetRect();
+      CFX_RectF rect = pWidget->GetWidgetRect();
       path.AddRectangle(0, 0, rect.width, rect.height);
       pGraphics->StrokePath(&path, &matrix);
     }
diff --git a/xfa/fxfa/cxfa_ffpushbutton.h b/xfa/fxfa/cxfa_ffpushbutton.h
index 9b2a0ee..e4b34b5 100644
--- a/xfa/fxfa/cxfa_ffpushbutton.h
+++ b/xfa/fxfa/cxfa_ffpushbutton.h
@@ -9,25 +9,27 @@
 
 #include <memory>
 
+#include "core/fxcrt/unowned_ptr.h"
 #include "xfa/fxfa/cxfa_fffield.h"
 
 #define XFA_FWL_PSBSTYLEEXT_HiliteInverted (1L << 0)
 #define XFA_FWL_PSBSTYLEEXT_HilitePush (1L << 1)
 #define XFA_FWL_PSBSTYLEEXT_HiliteOutLine (1L << 2)
 
+class CXFA_Button;
+class CXFA_TextLayout;
 class CXFA_TextProvider;
 
-class CXFA_FFPushButton : public CXFA_FFField {
+class CXFA_FFPushButton final : public CXFA_FFField {
  public:
-  explicit CXFA_FFPushButton(CXFA_Node* pNode);
+  CXFA_FFPushButton(CXFA_Node* pNode, CXFA_Button* button);
   ~CXFA_FFPushButton() override;
 
   // CXFA_FFField
   void RenderWidget(CXFA_Graphics* pGS,
                     const CFX_Matrix& matrix,
-                    uint32_t dwStatus) override;
+                    HighlightOption highlight) override;
   bool LoadWidget() override;
-  void UnloadWidget() override;
   bool PerformLayout() override;
   void UpdateWidgetProperty() override;
   void OnProcessMessage(CFWL_Message* pMessage) override;
@@ -48,7 +50,8 @@
   std::unique_ptr<CXFA_TextLayout> m_pDownTextLayout;
   std::unique_ptr<CXFA_TextProvider> m_pRollProvider;
   std::unique_ptr<CXFA_TextProvider> m_pDownProvider;
-  IFWL_WidgetDelegate* m_pOldDelegate;
+  UnownedPtr<IFWL_WidgetDelegate> m_pOldDelegate;
+  UnownedPtr<CXFA_Button> const button_;
 };
 
 #endif  // XFA_FXFA_CXFA_FFPUSHBUTTON_H_
diff --git a/xfa/fxfa/cxfa_ffrectangle.cpp b/xfa/fxfa/cxfa_ffrectangle.cpp
index 46c1009..ff5e576 100644
--- a/xfa/fxfa/cxfa_ffrectangle.cpp
+++ b/xfa/fxfa/cxfa_ffrectangle.cpp
@@ -9,14 +9,14 @@
 #include "xfa/fxfa/parser/cxfa_rectangle.h"
 #include "xfa/fxfa/parser/cxfa_value.h"
 
-CXFA_FFRectangle::CXFA_FFRectangle(CXFA_Node* pNode) : CXFA_FFDraw(pNode) {}
+CXFA_FFRectangle::CXFA_FFRectangle(CXFA_Node* pNode) : CXFA_FFWidget(pNode) {}
 
 CXFA_FFRectangle::~CXFA_FFRectangle() {}
 
 void CXFA_FFRectangle::RenderWidget(CXFA_Graphics* pGS,
                                     const CFX_Matrix& matrix,
-                                    uint32_t dwStatus) {
-  if (!IsMatchVisibleStatus(dwStatus))
+                                    HighlightOption highlight) {
+  if (!HasVisibleStatus())
     return;
 
   CXFA_Value* value = m_pNode->GetFormValueIfExists();
@@ -25,11 +25,9 @@
 
   CFX_RectF rect = GetRectWithoutRotate();
   CXFA_Margin* margin = m_pNode->GetMarginIfExists();
-  if (margin)
-    XFA_RectWithoutMargin(rect, margin);
+  XFA_RectWithoutMargin(&rect, margin);
 
   CFX_Matrix mtRotate = GetRotateMatrix();
   mtRotate.Concat(matrix);
-
   DrawBorder(pGS, value->GetRectangleIfExists(), rect, mtRotate);
 }
diff --git a/xfa/fxfa/cxfa_ffrectangle.h b/xfa/fxfa/cxfa_ffrectangle.h
index 304c5c6..d78d5ff 100644
--- a/xfa/fxfa/cxfa_ffrectangle.h
+++ b/xfa/fxfa/cxfa_ffrectangle.h
@@ -7,9 +7,9 @@
 #ifndef XFA_FXFA_CXFA_FFRECTANGLE_H_
 #define XFA_FXFA_CXFA_FFRECTANGLE_H_
 
-#include "xfa/fxfa/cxfa_ffdraw.h"
+#include "xfa/fxfa/cxfa_ffwidget.h"
 
-class CXFA_FFRectangle : public CXFA_FFDraw {
+class CXFA_FFRectangle final : public CXFA_FFWidget {
  public:
   explicit CXFA_FFRectangle(CXFA_Node* pNode);
   ~CXFA_FFRectangle() override;
@@ -17,7 +17,7 @@
   // CXFA_FFWidget
   void RenderWidget(CXFA_Graphics* pGS,
                     const CFX_Matrix& matrix,
-                    uint32_t dwStatus) override;
+                    HighlightOption highlight) override;
 };
 
 #endif  // XFA_FXFA_CXFA_FFRECTANGLE_H_
diff --git a/xfa/fxfa/cxfa_ffsignature.cpp b/xfa/fxfa/cxfa_ffsignature.cpp
index 6e56b38..b138991 100644
--- a/xfa/fxfa/cxfa_ffsignature.cpp
+++ b/xfa/fxfa/cxfa_ffsignature.cpp
@@ -14,26 +14,27 @@
 
 CXFA_FFSignature::CXFA_FFSignature(CXFA_Node* pNode) : CXFA_FFField(pNode) {}
 
-CXFA_FFSignature::~CXFA_FFSignature() {}
+CXFA_FFSignature::~CXFA_FFSignature() = default;
 
 bool CXFA_FFSignature::LoadWidget() {
+  ASSERT(!IsLoaded());
   return CXFA_FFField::LoadWidget();
 }
 
 void CXFA_FFSignature::RenderWidget(CXFA_Graphics* pGS,
                                     const CFX_Matrix& matrix,
-                                    uint32_t dwStatus) {
-  if (!IsMatchVisibleStatus(dwStatus))
+                                    HighlightOption highlight) {
+  if (!HasVisibleStatus())
     return;
 
   CFX_Matrix mtRotate = GetRotateMatrix();
   mtRotate.Concat(matrix);
 
-  CXFA_FFWidget::RenderWidget(pGS, mtRotate, dwStatus);
+  CXFA_FFWidget::RenderWidget(pGS, mtRotate, highlight);
 
-  DrawBorder(pGS, m_pNode->GetWidgetAcc()->GetUIBorder(), m_rtUI, mtRotate);
+  DrawBorder(pGS, m_pNode->GetUIBorder(), m_rtUI, mtRotate);
   RenderCaption(pGS, &mtRotate);
-  DrawHighlight(pGS, &mtRotate, dwStatus, false);
+  DrawHighlight(pGS, &mtRotate, highlight, kSquareShape);
 }
 
 bool CXFA_FFSignature::OnMouseEnter() {
@@ -44,6 +45,12 @@
   return false;
 }
 
+bool CXFA_FFSignature::AcceptsFocusOnButtonDown(uint32_t dwFlags,
+                                                const CFX_PointF& point,
+                                                FWL_MouseCommand command) {
+  return false;
+}
+
 bool CXFA_FFSignature::OnLButtonDown(uint32_t dwFlags,
                                      const CFX_PointF& point) {
   return false;
@@ -94,12 +101,10 @@
   return false;
 }
 
-FWL_WidgetHit CXFA_FFSignature::OnHitTest(const CFX_PointF& point) {
-  if (m_pNormalWidget &&
-      m_pNormalWidget->HitTest(FWLToClient(point)) != FWL_WidgetHit::Unknown) {
+FWL_WidgetHit CXFA_FFSignature::HitTest(const CFX_PointF& point) {
+  auto* pNorm = GetNormalWidget();
+  if (pNorm && pNorm->HitTest(FWLToClient(point)) != FWL_WidgetHit::Unknown)
     return FWL_WidgetHit::Client;
-  }
-
   if (!GetRectWithoutRotate().Contains(point))
     return FWL_WidgetHit::Unknown;
   if (m_rtCaption.Contains(point))
diff --git a/xfa/fxfa/cxfa_ffsignature.h b/xfa/fxfa/cxfa_ffsignature.h
index bd09576..1aa00b6 100644
--- a/xfa/fxfa/cxfa_ffsignature.h
+++ b/xfa/fxfa/cxfa_ffsignature.h
@@ -17,8 +17,11 @@
   // CXFA_FFField
   void RenderWidget(CXFA_Graphics* pGS,
                     const CFX_Matrix& matrix,
-                    uint32_t dwStatus) override;
+                    HighlightOption highlight) override;
   bool LoadWidget() override;
+  bool AcceptsFocusOnButtonDown(uint32_t dwFlags,
+                                const CFX_PointF& point,
+                                FWL_MouseCommand command) override;
   bool OnMouseEnter() override;
   bool OnMouseExit() override;
   bool OnLButtonDown(uint32_t dwFlags, const CFX_PointF& point) override;
@@ -31,12 +34,11 @@
   bool OnRButtonDown(uint32_t dwFlags, const CFX_PointF& point) override;
   bool OnRButtonUp(uint32_t dwFlags, const CFX_PointF& point) override;
   bool OnRButtonDblClk(uint32_t dwFlags, const CFX_PointF& point) override;
-
   bool OnKeyDown(uint32_t dwKeyCode, uint32_t dwFlags) override;
   bool OnKeyUp(uint32_t dwKeyCode, uint32_t dwFlags) override;
   bool OnChar(uint32_t dwChar, uint32_t dwFlags) override;
-  FWL_WidgetHit OnHitTest(const CFX_PointF& point) override;
   bool OnSetCursor(const CFX_PointF& point) override;
+  FWL_WidgetHit HitTest(const CFX_PointF& point) override;
   FormFieldType GetFormFieldType() override;
 };
 
diff --git a/xfa/fxfa/cxfa_ffsubform.cpp b/xfa/fxfa/cxfa_ffsubform.cpp
deleted file mode 100644
index 97a0750..0000000
--- a/xfa/fxfa/cxfa_ffsubform.cpp
+++ /dev/null
@@ -1,16 +0,0 @@
-// Copyright 2014 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
-
-#include "xfa/fxfa/cxfa_ffsubform.h"
-
-#include "xfa/fxfa/cxfa_ffapp.h"
-#include "xfa/fxfa/cxfa_ffdoc.h"
-#include "xfa/fxfa/cxfa_ffpageview.h"
-#include "xfa/fxfa/cxfa_ffwidget.h"
-
-CXFA_FFSubForm::CXFA_FFSubForm(CXFA_Node* pNode) : CXFA_FFWidget(pNode) {}
-
-CXFA_FFSubForm::~CXFA_FFSubForm() {}
diff --git a/xfa/fxfa/cxfa_ffsubform.h b/xfa/fxfa/cxfa_ffsubform.h
deleted file mode 100644
index a69b571..0000000
--- a/xfa/fxfa/cxfa_ffsubform.h
+++ /dev/null
@@ -1,19 +0,0 @@
-// Copyright 2014 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_CXFA_FFSUBFORM_H_
-#define XFA_FXFA_CXFA_FFSUBFORM_H_
-
-#include "xfa/fxfa/cxfa_ffpageview.h"
-#include "xfa/fxfa/cxfa_ffwidget.h"
-
-class CXFA_FFSubForm : public CXFA_FFWidget {
- public:
-  explicit CXFA_FFSubForm(CXFA_Node* pNode);
-  ~CXFA_FFSubForm() override;
-};
-
-#endif  // XFA_FXFA_CXFA_FFSUBFORM_H_
diff --git a/xfa/fxfa/cxfa_fftext.cpp b/xfa/fxfa/cxfa_fftext.cpp
index 7ae3cb6..f4ddbe0 100644
--- a/xfa/fxfa/cxfa_fftext.cpp
+++ b/xfa/fxfa/cxfa_fftext.cpp
@@ -6,36 +6,34 @@
 
 #include "xfa/fxfa/cxfa_fftext.h"
 
-#include "xfa/fwl/fwl_widgetdef.h"
+#include "xfa/fgas/layout/cfx_linkuserdata.h"
 #include "xfa/fwl/fwl_widgethit.h"
 #include "xfa/fxfa/cxfa_ffapp.h"
 #include "xfa/fxfa/cxfa_ffdoc.h"
-#include "xfa/fxfa/cxfa_ffdraw.h"
 #include "xfa/fxfa/cxfa_ffpageview.h"
 #include "xfa/fxfa/cxfa_ffwidget.h"
-#include "xfa/fxfa/cxfa_linkuserdata.h"
 #include "xfa/fxfa/cxfa_pieceline.h"
 #include "xfa/fxfa/cxfa_textlayout.h"
 #include "xfa/fxfa/cxfa_textpiece.h"
 #include "xfa/fxfa/parser/cxfa_margin.h"
 #include "xfa/fxgraphics/cxfa_graphics.h"
 
-CXFA_FFText::CXFA_FFText(CXFA_Node* pNode) : CXFA_FFDraw(pNode) {}
+CXFA_FFText::CXFA_FFText(CXFA_Node* pNode) : CXFA_FFWidget(pNode) {}
 
 CXFA_FFText::~CXFA_FFText() {}
 
 void CXFA_FFText::RenderWidget(CXFA_Graphics* pGS,
                                const CFX_Matrix& matrix,
-                               uint32_t dwStatus) {
-  if (!IsMatchVisibleStatus(dwStatus))
+                               HighlightOption highlight) {
+  if (!HasVisibleStatus())
     return;
 
   CFX_Matrix mtRotate = GetRotateMatrix();
   mtRotate.Concat(matrix);
 
-  CXFA_FFWidget::RenderWidget(pGS, mtRotate, dwStatus);
+  CXFA_FFWidget::RenderWidget(pGS, mtRotate, highlight);
 
-  CXFA_TextLayout* pTextLayout = m_pNode->GetWidgetAcc()->GetTextLayout();
+  CXFA_TextLayout* pTextLayout = m_pNode->GetTextLayout();
   if (!pTextLayout)
     return;
 
@@ -43,9 +41,9 @@
   CFX_RectF rtText = GetRectWithoutRotate();
   CXFA_Margin* margin = m_pNode->GetMarginIfExists();
   if (margin) {
-    CXFA_LayoutItem* pItem = this;
+    CXFA_ContentLayoutItem* pItem = GetLayoutItem();
     if (!pItem->GetPrev() && !pItem->GetNext()) {
-      XFA_RectWithoutMargin(rtText, margin);
+      XFA_RectWithoutMargin(&rtText, margin);
     } else {
       float fTopInset = 0;
       float fBottomInset = 0;
@@ -62,24 +60,25 @@
   CFX_Matrix mt(1, 0, 0, 1, rtText.left, rtText.top);
   CFX_RectF rtClip = mtRotate.TransformRect(rtText);
   mt.Concat(mtRotate);
-  pTextLayout->DrawString(pRenderDevice, mt, rtClip, GetIndex());
+  pTextLayout->DrawString(pRenderDevice, mt, rtClip,
+                          GetLayoutItem()->GetIndex());
 }
 
 bool CXFA_FFText::IsLoaded() {
-  CXFA_TextLayout* pTextLayout = m_pNode->GetWidgetAcc()->GetTextLayout();
-  return pTextLayout && !pTextLayout->m_bHasBlock;
+  CXFA_TextLayout* pTextLayout = m_pNode->GetTextLayout();
+  return pTextLayout && !pTextLayout->HasBlock();
 }
 
 bool CXFA_FFText::PerformLayout() {
-  CXFA_FFDraw::PerformLayout();
-  CXFA_TextLayout* pTextLayout = m_pNode->GetWidgetAcc()->GetTextLayout();
+  CXFA_FFWidget::PerformLayout();
+  CXFA_TextLayout* pTextLayout = m_pNode->GetTextLayout();
   if (!pTextLayout)
     return false;
-  if (!pTextLayout->m_bHasBlock)
+  if (!pTextLayout->HasBlock())
     return true;
 
-  pTextLayout->m_Blocks.clear();
-  CXFA_LayoutItem* pItem = this;
+  pTextLayout->ClearBlocks();
+  CXFA_ContentLayoutItem* pItem = GetLayoutItem();
   if (!pItem->GetPrev() && !pItem->GetNext())
     return true;
 
@@ -96,11 +95,16 @@
     pTextLayout->ItemBlocks(rtText, pItem->GetIndex());
     pItem = pItem->GetNext();
   }
-  pTextLayout->m_bHasBlock = false;
+  pTextLayout->ResetHasBlock();
   return true;
 }
 
-bool CXFA_FFText::OnLButtonDown(uint32_t dwFlags, const CFX_PointF& point) {
+bool CXFA_FFText::AcceptsFocusOnButtonDown(uint32_t dwFlags,
+                                           const CFX_PointF& point,
+                                           FWL_MouseCommand command) {
+  if (command != FWL_MouseCommand::LeftButtonDown)
+    return false;
+
   if (!GetRectWithoutRotate().Contains(point))
     return false;
 
@@ -108,6 +112,10 @@
   if (!wsURLContent)
     return false;
 
+  return true;
+}
+
+bool CXFA_FFText::OnLButtonDown(uint32_t dwFlags, const CFX_PointF& point) {
   SetButtonDown(true);
   return true;
 }
@@ -130,7 +138,7 @@
   return true;
 }
 
-FWL_WidgetHit CXFA_FFText::OnHitTest(const CFX_PointF& point) {
+FWL_WidgetHit CXFA_FFText::HitTest(const CFX_PointF& point) {
   if (!GetRectWithoutRotate().Contains(point))
     return FWL_WidgetHit::Unknown;
   if (!GetLinkURLAtPoint(point))
@@ -139,7 +147,7 @@
 }
 
 const wchar_t* CXFA_FFText::GetLinkURLAtPoint(const CFX_PointF& point) {
-  CXFA_TextLayout* pTextLayout = m_pNode->GetWidgetAcc()->GetTextLayout();
+  CXFA_TextLayout* pTextLayout = m_pNode->GetTextLayout();
   if (!pTextLayout)
     return nullptr;
 
diff --git a/xfa/fxfa/cxfa_fftext.h b/xfa/fxfa/cxfa_fftext.h
index 8c32183..92eafb1 100644
--- a/xfa/fxfa/cxfa_fftext.h
+++ b/xfa/fxfa/cxfa_fftext.h
@@ -7,21 +7,24 @@
 #ifndef XFA_FXFA_CXFA_FFTEXT_H_
 #define XFA_FXFA_CXFA_FFTEXT_H_
 
-#include "xfa/fxfa/cxfa_ffdraw.h"
+#include "xfa/fxfa/cxfa_ffwidget.h"
 
-class CXFA_FFText : public CXFA_FFDraw {
+class CXFA_FFText final : public CXFA_FFWidget {
  public:
   explicit CXFA_FFText(CXFA_Node* pNode);
   ~CXFA_FFText() override;
 
   // CXFA_FFWidget
+  bool AcceptsFocusOnButtonDown(uint32_t dwFlags,
+                                const CFX_PointF& point,
+                                FWL_MouseCommand command) override;
   bool OnLButtonDown(uint32_t dwFlags, const CFX_PointF& point) override;
   bool OnLButtonUp(uint32_t dwFlags, const CFX_PointF& point) override;
   bool OnMouseMove(uint32_t dwFlags, const CFX_PointF& point) override;
-  FWL_WidgetHit OnHitTest(const CFX_PointF& point) override;
+  FWL_WidgetHit HitTest(const CFX_PointF& point) override;
   void RenderWidget(CXFA_Graphics* pGS,
                     const CFX_Matrix& matrix,
-                    uint32_t dwStatus) override;
+                    HighlightOption highlight) override;
   bool IsLoaded() override;
   bool PerformLayout() override;
 
diff --git a/xfa/fxfa/cxfa_fftextedit.cpp b/xfa/fxfa/cxfa_fftextedit.cpp
index fad9a9b..7b1c93b 100644
--- a/xfa/fxfa/cxfa_fftextedit.cpp
+++ b/xfa/fxfa/cxfa_fftextedit.cpp
@@ -8,17 +8,19 @@
 
 #include <utility>
 
+#include "third_party/base/ptr_util.h"
 #include "xfa/fwl/cfwl_datetimepicker.h"
 #include "xfa/fwl/cfwl_edit.h"
-#include "xfa/fwl/cfwl_eventcheckword.h"
 #include "xfa/fwl/cfwl_eventtarget.h"
-#include "xfa/fwl/cfwl_eventtextchanged.h"
+#include "xfa/fwl/cfwl_eventtextwillchange.h"
 #include "xfa/fwl/cfwl_messagekillfocus.h"
 #include "xfa/fwl/cfwl_messagesetfocus.h"
 #include "xfa/fwl/cfwl_notedriver.h"
 #include "xfa/fxfa/cxfa_eventparam.h"
 #include "xfa/fxfa/cxfa_ffapp.h"
 #include "xfa/fxfa/cxfa_ffdoc.h"
+#include "xfa/fxfa/cxfa_ffdocview.h"
+#include "xfa/fxfa/parser/cxfa_barcode.h"
 #include "xfa/fxfa/parser/cxfa_node.h"
 #include "xfa/fxfa/parser/cxfa_para.h"
 
@@ -30,41 +32,40 @@
 
 }  // namespace
 
-CXFA_FFTextEdit::CXFA_FFTextEdit(CXFA_Node* pNode)
-    : CXFA_FFField(pNode), m_pOldDelegate(nullptr) {}
+CXFA_FFTextEdit::CXFA_FFTextEdit(CXFA_Node* pNode) : CXFA_FFField(pNode) {}
 
 CXFA_FFTextEdit::~CXFA_FFTextEdit() {
-  if (m_pNormalWidget) {
+  if (GetNormalWidget()) {
     CFWL_NoteDriver* pNoteDriver =
-        m_pNormalWidget->GetOwnerApp()->GetNoteDriver();
-    pNoteDriver->UnregisterEventTarget(m_pNormalWidget.get());
+        GetNormalWidget()->GetOwnerApp()->GetNoteDriver();
+    pNoteDriver->UnregisterEventTarget(GetNormalWidget());
   }
 }
 
 bool CXFA_FFTextEdit::LoadWidget() {
   auto pNewWidget = pdfium::MakeUnique<CFWL_Edit>(
       GetFWLApp(), pdfium::MakeUnique<CFWL_WidgetProperties>(), nullptr);
+  ASSERT(!IsLoaded());
   CFWL_Edit* pFWLEdit = pNewWidget.get();
-  m_pNormalWidget = std::move(pNewWidget);
-  m_pNormalWidget->SetLayoutItem(this);
+  SetNormalWidget(std::move(pNewWidget));
+  pFWLEdit->SetAdapterIface(this);
 
-  CFWL_NoteDriver* pNoteDriver =
-      m_pNormalWidget->GetOwnerApp()->GetNoteDriver();
-  pNoteDriver->RegisterEventTarget(m_pNormalWidget.get(),
-                                   m_pNormalWidget.get());
-  m_pOldDelegate = m_pNormalWidget->GetDelegate();
-  m_pNormalWidget->SetDelegate(this);
-  m_pNormalWidget->LockUpdate();
-  UpdateWidgetProperty();
+  CFWL_NoteDriver* pNoteDriver = pFWLEdit->GetOwnerApp()->GetNoteDriver();
+  pNoteDriver->RegisterEventTarget(pFWLEdit, pFWLEdit);
+  m_pOldDelegate = pFWLEdit->GetDelegate();
+  pFWLEdit->SetDelegate(this);
 
-  pFWLEdit->SetText(
-      m_pNode->GetWidgetAcc()->GetValue(XFA_VALUEPICTURE_Display));
-  m_pNormalWidget->UnlockUpdate();
+  {
+    CFWL_Widget::ScopedUpdateLock update_lock(pFWLEdit);
+    UpdateWidgetProperty();
+    pFWLEdit->SetText(m_pNode->GetValue(XFA_VALUEPICTURE_Display));
+  }
+
   return CXFA_FFField::LoadWidget();
 }
 
 void CXFA_FFTextEdit::UpdateWidgetProperty() {
-  CFWL_Edit* pWidget = static_cast<CFWL_Edit*>(m_pNormalWidget.get());
+  CFWL_Edit* pWidget = ToEdit(GetNormalWidget());
   if (!pWidget)
     return;
 
@@ -72,13 +73,13 @@
   uint32_t dwExtendedStyle =
       FWL_STYLEEXT_EDT_ShowScrollbarFocus | FWL_STYLEEXT_EDT_OuterScrollbar;
   dwExtendedStyle |= UpdateUIProperty();
-  if (m_pNode->GetWidgetAcc()->IsMultiLine()) {
+  if (m_pNode->IsMultiLine()) {
     dwExtendedStyle |= FWL_STYLEEXT_EDT_MultiLine | FWL_STYLEEXT_EDT_WantReturn;
-    if (!m_pNode->GetWidgetAcc()->IsVerticalScrollPolicyOff()) {
+    if (!m_pNode->IsVerticalScrollPolicyOff()) {
       dwStyle |= FWL_WGTSTYLE_VScroll;
       dwExtendedStyle |= FWL_STYLEEXT_EDT_AutoVScroll;
     }
-  } else if (!m_pNode->GetWidgetAcc()->IsHorizontalScrollPolicyOff()) {
+  } else if (!m_pNode->IsHorizontalScrollPolicyOff()) {
     dwExtendedStyle |= FWL_STYLEEXT_EDT_AutoHScroll;
   }
   if (!m_pNode->IsOpenAccess() || !GetDoc()->GetXFADoc()->IsInteractive()) {
@@ -88,11 +89,11 @@
 
   XFA_Element eType;
   int32_t iMaxChars;
-  std::tie(eType, iMaxChars) = m_pNode->GetWidgetAcc()->GetMaxChars();
+  std::tie(eType, iMaxChars) = m_pNode->GetMaxChars();
   if (eType == XFA_Element::ExData)
     iMaxChars = 0;
 
-  Optional<int32_t> numCells = m_pNode->GetWidgetAcc()->GetNumberOfCells();
+  Optional<int32_t> numCells = m_pNode->GetNumberOfCells();
   if (!numCells) {
     pWidget->SetLimit(iMaxChars);
   } else if (*numCells == 0) {
@@ -104,46 +105,54 @@
   }
 
   dwExtendedStyle |= GetAlignment();
-  m_pNormalWidget->ModifyStyles(dwStyle, 0xFFFFFFFF);
-  m_pNormalWidget->ModifyStylesEx(dwExtendedStyle, 0xFFFFFFFF);
+  GetNormalWidget()->ModifyStyles(dwStyle, 0xFFFFFFFF);
+  GetNormalWidget()->ModifyStylesEx(dwExtendedStyle, 0xFFFFFFFF);
+}
+
+bool CXFA_FFTextEdit::AcceptsFocusOnButtonDown(uint32_t dwFlags,
+                                               const CFX_PointF& point,
+                                               FWL_MouseCommand command) {
+  if (command == FWL_MouseCommand::RightButtonDown && !m_pNode->IsOpenAccess())
+    return false;
+  if (!PtInActiveRect(point))
+    return false;
+
+  return true;
 }
 
 bool CXFA_FFTextEdit::OnLButtonDown(uint32_t dwFlags, const CFX_PointF& point) {
-  if (!PtInActiveRect(point))
-    return false;
+  ObservedPtr<CXFA_FFTextEdit> pWatched(this);
   if (!IsFocused()) {
-    m_dwStatus |= XFA_WidgetStatus_Focused;
+    GetLayoutItem()->SetStatusBits(XFA_WidgetStatus_Focused);
     UpdateFWLData();
-    AddInvalidateRect();
-  }
+    if (!pWatched)
+      return false;
 
+    InvalidateRect();
+  }
   SetButtonDown(true);
-  CFWL_MessageMouse ms(nullptr, m_pNormalWidget.get());
-  ms.m_dwCmd = FWL_MouseCommand::LeftButtonDown;
-  ms.m_dwFlags = dwFlags;
-  ms.m_pos = FWLToClient(point);
-  TranslateFWLMessage(&ms);
-  return true;
+  SendMessageToFWLWidget(pdfium::MakeUnique<CFWL_MessageMouse>(
+      GetNormalWidget(), FWL_MouseCommand::LeftButtonDown, dwFlags,
+      FWLToClient(point)));
+
+  return !!pWatched;
 }
 
 bool CXFA_FFTextEdit::OnRButtonDown(uint32_t dwFlags, const CFX_PointF& point) {
-  if (!m_pNode->IsOpenAccess())
-    return false;
-  if (!PtInActiveRect(point))
-    return false;
+  ObservedPtr<CXFA_FFTextEdit> pWatched(this);
   if (!IsFocused()) {
-    m_dwStatus |= XFA_WidgetStatus_Focused;
+    GetLayoutItem()->SetStatusBits(XFA_WidgetStatus_Focused);
     UpdateFWLData();
-    AddInvalidateRect();
-  }
+    if (!pWatched)
+      return false;
 
+    InvalidateRect();
+  }
   SetButtonDown(true);
-  CFWL_MessageMouse ms(nullptr, nullptr);
-  ms.m_dwCmd = FWL_MouseCommand::RightButtonDown;
-  ms.m_dwFlags = dwFlags;
-  ms.m_pos = FWLToClient(point);
-  TranslateFWLMessage(&ms);
-  return true;
+  SendMessageToFWLWidget(pdfium::MakeUnique<CFWL_MessageMouse>(
+      nullptr, FWL_MouseCommand::RightButtonDown, dwFlags, FWLToClient(point)));
+
+  return !!pWatched;
 }
 
 bool CXFA_FFTextEdit::OnRButtonUp(uint32_t dwFlags, const CFX_PointF& point) {
@@ -155,37 +164,57 @@
 }
 
 bool CXFA_FFTextEdit::OnSetFocus(CXFA_FFWidget* pOldWidget) {
-  m_dwStatus &= ~XFA_WidgetStatus_TextEditValueChanged;
+  ObservedPtr<CXFA_FFTextEdit> pWatched(this);
+  ObservedPtr<CXFA_FFWidget> pOldWatched(pOldWidget);
+  GetLayoutItem()->ClearStatusBits(XFA_WidgetStatus_TextEditValueChanged);
   if (!IsFocused()) {
-    m_dwStatus |= XFA_WidgetStatus_Focused;
+    GetLayoutItem()->SetStatusBits(XFA_WidgetStatus_Focused);
     UpdateFWLData();
-    AddInvalidateRect();
+    if (!pWatched)
+      return false;
+
+    InvalidateRect();
   }
-  CXFA_FFWidget::OnSetFocus(pOldWidget);
-  CFWL_MessageSetFocus ms(nullptr, m_pNormalWidget.get());
-  TranslateFWLMessage(&ms);
-  return true;
+  if (!CXFA_FFWidget::OnSetFocus(pOldWatched.Get()))
+    return false;
+
+  SendMessageToFWLWidget(
+      pdfium::MakeUnique<CFWL_MessageSetFocus>(nullptr, GetNormalWidget()));
+
+  return !!pWatched;
 }
 
 bool CXFA_FFTextEdit::OnKillFocus(CXFA_FFWidget* pNewWidget) {
-  CFWL_MessageKillFocus ms(nullptr, m_pNormalWidget.get());
-  TranslateFWLMessage(&ms);
-  m_dwStatus &= ~XFA_WidgetStatus_Focused;
+  ObservedPtr<CXFA_FFWidget> pWatched(this);
+  ObservedPtr<CXFA_FFWidget> pNewWatched(pNewWidget);
+  SendMessageToFWLWidget(
+      pdfium::MakeUnique<CFWL_MessageKillFocus>(nullptr, GetNormalWidget()));
 
+  if (!pWatched)
+    return false;
+
+  GetLayoutItem()->ClearStatusBits(XFA_WidgetStatus_Focused);
   SetEditScrollOffset();
   ProcessCommittedData();
   UpdateFWLData();
-  AddInvalidateRect();
-  CXFA_FFWidget::OnKillFocus(pNewWidget);
+  InvalidateRect();
+  if (!pWatched)
+    return false;
 
-  m_dwStatus &= ~XFA_WidgetStatus_TextEditValueChanged;
+  if (!CXFA_FFWidget::OnKillFocus(pNewWatched.Get()))
+    return false;
+
+  if (!pWatched)
+    return false;
+
+  GetLayoutItem()->ClearStatusBits(XFA_WidgetStatus_TextEditValueChanged);
   return true;
 }
 
 bool CXFA_FFTextEdit::CommitData() {
-  WideString wsText = static_cast<CFWL_Edit*>(m_pNormalWidget.get())->GetText();
-  if (m_pNode->GetWidgetAcc()->SetValue(XFA_VALUEPICTURE_Edit, wsText)) {
-    m_pNode->GetWidgetAcc()->UpdateUIDisplay(GetDoc()->GetDocView(), this);
+  WideString wsText = ToEdit(GetNormalWidget())->GetText();
+  if (m_pNode->SetValue(XFA_VALUEPICTURE_Edit, wsText)) {
+    GetDoc()->GetDocView()->UpdateUIDisplay(m_pNode.Get(), this);
     return true;
   }
   ValidateNumberField(wsText);
@@ -193,23 +222,22 @@
 }
 
 void CXFA_FFTextEdit::ValidateNumberField(const WideString& wsText) {
-  CXFA_WidgetAcc* pAcc = GetNode()->GetWidgetAcc();
-  if (!pAcc || pAcc->GetUIType() != XFA_Element::NumericEdit)
+  if (GetNode()->GetFFWidgetType() != XFA_FFWidgetType::kNumericEdit)
     return;
 
-  IXFA_AppProvider* pAppProvider = GetApp()->GetAppProvider();
+  IXFA_AppProvider* pAppProvider = GetAppProvider();
   if (!pAppProvider)
     return;
 
-  WideString wsSomField = pAcc->GetNode()->GetSOMExpression();
-  pAppProvider->MsgBox(WideString::Format(L"%ls can not contain %ls",
-                                          wsText.c_str(), wsSomField.c_str()),
-                       pAppProvider->GetAppTitle(), XFA_MBICON_Error,
-                       XFA_MB_OK);
+  WideString wsSomField = GetNode()->GetSOMExpression();
+  pAppProvider->MsgBox(
+      wsText + WideString::FromASCII(" can not contain ") + wsSomField,
+      pAppProvider->GetAppTitle(), static_cast<uint32_t>(AlertIcon::kError),
+      static_cast<uint32_t>(AlertButton::kOK));
 }
 
 bool CXFA_FFTextEdit::IsDataChanged() {
-  return (m_dwStatus & XFA_WidgetStatus_TextEditValueChanged) != 0;
+  return GetLayoutItem()->TestStatusBits(XFA_WidgetStatus_TextEditValueChanged);
 }
 
 uint32_t CXFA_FFTextEdit::GetAlignment() {
@@ -219,16 +247,16 @@
 
   uint32_t dwExtendedStyle = 0;
   switch (para->GetHorizontalAlign()) {
-    case XFA_AttributeEnum::Center:
+    case XFA_AttributeValue::Center:
       dwExtendedStyle |= FWL_STYLEEXT_EDT_HCenter;
       break;
-    case XFA_AttributeEnum::Justify:
+    case XFA_AttributeValue::Justify:
       dwExtendedStyle |= FWL_STYLEEXT_EDT_Justified;
       break;
-    case XFA_AttributeEnum::JustifyAll:
-    case XFA_AttributeEnum::Radix:
+    case XFA_AttributeValue::JustifyAll:
+    case XFA_AttributeValue::Radix:
       break;
-    case XFA_AttributeEnum::Right:
+    case XFA_AttributeValue::Right:
       dwExtendedStyle |= FWL_STYLEEXT_EDT_HFar;
       break;
     default:
@@ -237,10 +265,10 @@
   }
 
   switch (para->GetVerticalAlign()) {
-    case XFA_AttributeEnum::Middle:
+    case XFA_AttributeValue::Middle:
       dwExtendedStyle |= FWL_STYLEEXT_EDT_VCenter;
       break;
-    case XFA_AttributeEnum::Bottom:
+    case XFA_AttributeValue::Bottom:
       dwExtendedStyle |= FWL_STYLEEXT_EDT_VFar;
       break;
     default:
@@ -251,83 +279,77 @@
 }
 
 bool CXFA_FFTextEdit::UpdateFWLData() {
-  if (!m_pNormalWidget)
+  if (!GetNormalWidget())
     return false;
 
-  CFWL_Edit* pEdit = static_cast<CFWL_Edit*>(m_pNormalWidget.get());
+  CFWL_Edit* pEdit = ToEdit(GetNormalWidget());
   XFA_VALUEPICTURE eType = XFA_VALUEPICTURE_Display;
   if (IsFocused())
     eType = XFA_VALUEPICTURE_Edit;
 
   bool bUpdate = false;
-  if (m_pNode->GetWidgetAcc()->GetUIType() == XFA_Element::TextEdit &&
-      !m_pNode->GetWidgetAcc()->GetNumberOfCells()) {
+  if (m_pNode->GetFFWidgetType() == XFA_FFWidgetType::kTextEdit &&
+      !m_pNode->GetNumberOfCells()) {
     XFA_Element elementType;
     int32_t iMaxChars;
-    std::tie(elementType, iMaxChars) = m_pNode->GetWidgetAcc()->GetMaxChars();
+    std::tie(elementType, iMaxChars) = m_pNode->GetMaxChars();
     if (elementType == XFA_Element::ExData)
       iMaxChars = eType == XFA_VALUEPICTURE_Edit ? iMaxChars : 0;
     if (pEdit->GetLimit() != iMaxChars) {
       pEdit->SetLimit(iMaxChars);
       bUpdate = true;
     }
-  } else if (m_pNode->GetWidgetAcc()->GetUIType() == XFA_Element::Barcode) {
+  } else if (m_pNode->GetFFWidgetType() == XFA_FFWidgetType::kBarcode) {
     int32_t nDataLen = 0;
-    if (eType == XFA_VALUEPICTURE_Edit)
-      nDataLen = m_pNode->GetBarcodeAttribute_DataLength().value_or(0);
+    if (eType == XFA_VALUEPICTURE_Edit) {
+      nDataLen = static_cast<CXFA_Barcode*>(m_pNode->GetUIChildNode())
+                     ->GetDataLength()
+                     .value_or(0);
+    }
 
     pEdit->SetLimit(nDataLen);
     bUpdate = true;
   }
 
-  WideString wsText = m_pNode->GetWidgetAcc()->GetValue(eType);
+  WideString wsText = m_pNode->GetValue(eType);
   WideString wsOldText = pEdit->GetText();
   if (wsText != wsOldText || (eType == XFA_VALUEPICTURE_Edit && bUpdate)) {
-    pEdit->SetText(wsText);
+    pEdit->SetTextSkipNotify(wsText);
     bUpdate = true;
   }
   if (bUpdate)
-    m_pNormalWidget->Update();
+    GetNormalWidget()->Update();
 
   return true;
 }
 
-void CXFA_FFTextEdit::OnTextChanged(CFWL_Widget* pWidget,
-                                    const WideString& wsChanged,
-                                    const WideString& wsPrevText) {
-  m_dwStatus |= XFA_WidgetStatus_TextEditValueChanged;
+void CXFA_FFTextEdit::OnTextWillChange(CFWL_Widget* pWidget,
+                                       CFWL_EventTextWillChange* event) {
+  GetLayoutItem()->SetStatusBits(XFA_WidgetStatus_TextEditValueChanged);
+
   CXFA_EventParam eParam;
   eParam.m_eType = XFA_EVENT_Change;
-  eParam.m_wsChange = wsChanged;
-  eParam.m_pTarget = m_pNode->GetWidgetAcc();
-  eParam.m_wsPrevText = wsPrevText;
-  CFWL_Edit* pEdit = static_cast<CFWL_Edit*>(m_pNormalWidget.get());
-  if (m_pNode->GetWidgetAcc()->GetUIType() == XFA_Element::DateTimeEdit) {
-    CFWL_DateTimePicker* pDateTime = (CFWL_DateTimePicker*)pEdit;
-    eParam.m_wsNewText = pDateTime->GetEditText();
-    if (pDateTime->HasSelection()) {
-      size_t count;
-      std::tie(eParam.m_iSelStart, count) = pDateTime->GetSelection();
-      eParam.m_iSelEnd = eParam.m_iSelStart + count;
-    }
-  } else {
-    eParam.m_wsNewText = pEdit->GetText();
-    if (pEdit->HasSelection())
-      std::tie(eParam.m_iSelStart, eParam.m_iSelEnd) = pEdit->GetSelection();
-  }
-  m_pNode->ProcessEvent(GetDocView(), XFA_AttributeEnum::Change, &eParam);
+  eParam.m_wsChange = event->change_text;
+  eParam.m_pTarget = m_pNode.Get();
+  eParam.m_wsPrevText = event->previous_text;
+  eParam.m_iSelStart = static_cast<int32_t>(event->selection_start);
+  eParam.m_iSelEnd = static_cast<int32_t>(event->selection_end);
+
+  m_pNode->ProcessEvent(GetDocView(), XFA_AttributeValue::Change, &eParam);
+
+  // Copy the data back out of the EventParam and into the TextChanged event so
+  // it can propagate back to the calling widget.
+  event->cancelled = eParam.m_bCancelAction;
+  event->change_text = std::move(eParam.m_wsChange);
+  event->selection_start = static_cast<size_t>(eParam.m_iSelStart);
+  event->selection_end = static_cast<size_t>(eParam.m_iSelEnd);
 }
 
 void CXFA_FFTextEdit::OnTextFull(CFWL_Widget* pWidget) {
   CXFA_EventParam eParam;
   eParam.m_eType = XFA_EVENT_Full;
-  eParam.m_pTarget = m_pNode->GetWidgetAcc();
-  m_pNode->ProcessEvent(GetDocView(), XFA_AttributeEnum::Full, &eParam);
-}
-
-bool CXFA_FFTextEdit::CheckWord(const ByteStringView& sWord) {
-  return sWord.IsEmpty() ||
-         m_pNode->GetWidgetAcc()->GetUIType() != XFA_Element::TextEdit;
+  eParam.m_pTarget = m_pNode.Get();
+  m_pNode->ProcessEvent(GetDocView(), XFA_AttributeValue::Full, &eParam);
 }
 
 void CXFA_FFTextEdit::OnProcessMessage(CFWL_Message* pMessage) {
@@ -337,23 +359,13 @@
 void CXFA_FFTextEdit::OnProcessEvent(CFWL_Event* pEvent) {
   CXFA_FFField::OnProcessEvent(pEvent);
   switch (pEvent->GetType()) {
-    case CFWL_Event::Type::TextChanged: {
-      CFWL_EventTextChanged* event =
-          static_cast<CFWL_EventTextChanged*>(pEvent);
-      WideString wsChange;
-      OnTextChanged(m_pNormalWidget.get(), wsChange, event->wsPrevText);
+    case CFWL_Event::Type::TextWillChange:
+      OnTextWillChange(GetNormalWidget(),
+                       static_cast<CFWL_EventTextWillChange*>(pEvent));
       break;
-    }
-    case CFWL_Event::Type::TextFull: {
-      OnTextFull(m_pNormalWidget.get());
+    case CFWL_Event::Type::TextFull:
+      OnTextFull(GetNormalWidget());
       break;
-    }
-    case CFWL_Event::Type::CheckWord: {
-      WideString wstr(L"FWL_EVENT_DTP_SelectChanged");
-      CFWL_EventCheckWord* event = static_cast<CFWL_EventCheckWord*>(pEvent);
-      event->bCheckWord = CheckWord(event->bsWord.AsStringView());
-      break;
-    }
     default:
       break;
   }
@@ -366,62 +378,66 @@
 }
 
 bool CXFA_FFTextEdit::CanUndo() {
-  return ToEdit(m_pNormalWidget.get())->CanUndo();
+  return ToEdit(GetNormalWidget())->CanUndo();
 }
 
 bool CXFA_FFTextEdit::CanRedo() {
-  return ToEdit(m_pNormalWidget.get())->CanRedo();
+  return ToEdit(GetNormalWidget())->CanRedo();
 }
 
 bool CXFA_FFTextEdit::Undo() {
-  return ToEdit(m_pNormalWidget.get())->Undo();
+  return ToEdit(GetNormalWidget())->Undo();
 }
 
 bool CXFA_FFTextEdit::Redo() {
-  return ToEdit(m_pNormalWidget.get())->Redo();
+  return ToEdit(GetNormalWidget())->Redo();
 }
 
 bool CXFA_FFTextEdit::CanCopy() {
-  return ToEdit(m_pNormalWidget.get())->HasSelection();
+  return ToEdit(GetNormalWidget())->HasSelection();
 }
 
 bool CXFA_FFTextEdit::CanCut() {
-  if (ToEdit(m_pNormalWidget.get())->GetStylesEx() & FWL_STYLEEXT_EDT_ReadOnly)
+  if (ToEdit(GetNormalWidget())->GetStylesEx() & FWL_STYLEEXT_EDT_ReadOnly)
     return false;
-  return ToEdit(m_pNormalWidget.get())->HasSelection();
+  return ToEdit(GetNormalWidget())->HasSelection();
 }
 
 bool CXFA_FFTextEdit::CanPaste() {
-  return !(ToEdit(m_pNormalWidget.get())->GetStylesEx() &
+  return !(ToEdit(GetNormalWidget())->GetStylesEx() &
            FWL_STYLEEXT_EDT_ReadOnly);
 }
 
 bool CXFA_FFTextEdit::CanSelectAll() {
-  return ToEdit(m_pNormalWidget.get())->GetTextLength() > 0;
+  return ToEdit(GetNormalWidget())->GetTextLength() > 0;
 }
 
 Optional<WideString> CXFA_FFTextEdit::Copy() {
-  return ToEdit(m_pNormalWidget.get())->Copy();
+  return ToEdit(GetNormalWidget())->Copy();
 }
 
 Optional<WideString> CXFA_FFTextEdit::Cut() {
-  return ToEdit(m_pNormalWidget.get())->Cut();
+  return ToEdit(GetNormalWidget())->Cut();
 }
 
 bool CXFA_FFTextEdit::Paste(const WideString& wsPaste) {
-  return ToEdit(m_pNormalWidget.get())->Paste(wsPaste);
+  return ToEdit(GetNormalWidget())->Paste(wsPaste);
 }
 
 void CXFA_FFTextEdit::SelectAll() {
-  ToEdit(m_pNormalWidget.get())->SelectAll();
+  ToEdit(GetNormalWidget())->SelectAll();
 }
 
 void CXFA_FFTextEdit::Delete() {
-  ToEdit(m_pNormalWidget.get())->ClearText();
+  ToEdit(GetNormalWidget())->ClearText();
 }
 
 void CXFA_FFTextEdit::DeSelect() {
-  ToEdit(m_pNormalWidget.get())->ClearSelection();
+  ToEdit(GetNormalWidget())->ClearSelection();
+}
+
+WideString CXFA_FFTextEdit::GetText() {
+  return ToEdit(GetNormalWidget())->GetText();
 }
 
 FormFieldType CXFA_FFTextEdit::GetFormFieldType() {
diff --git a/xfa/fxfa/cxfa_fftextedit.h b/xfa/fxfa/cxfa_fftextedit.h
index e8edb46..09b9434 100644
--- a/xfa/fxfa/cxfa_fftextedit.h
+++ b/xfa/fxfa/cxfa_fftextedit.h
@@ -9,13 +9,14 @@
 
 #include "core/fxcrt/fx_coordinates.h"
 #include "core/fxcrt/fx_string.h"
+#include "core/fxcrt/unowned_ptr.h"
 #include "xfa/fxfa/cxfa_fffield.h"
 
 class CFWL_Event;
+class CFWL_EventTextWillChange;
 class CFWL_Widget;
 class CFX_Matrix;
 class CXFA_FFWidget;
-class CXFA_WidgetAcc;
 class IFWL_WidgetDelegate;
 
 class CXFA_FFTextEdit : public CXFA_FFField {
@@ -26,21 +27,21 @@
   // CXFA_FFField
   bool LoadWidget() override;
   void UpdateWidgetProperty() override;
+  bool AcceptsFocusOnButtonDown(uint32_t dwFlags,
+                                const CFX_PointF& point,
+                                FWL_MouseCommand command) override;
   bool OnLButtonDown(uint32_t dwFlags, const CFX_PointF& point) override;
   bool OnRButtonDown(uint32_t dwFlags, const CFX_PointF& point) override;
   bool OnRButtonUp(uint32_t dwFlags, const CFX_PointF& point) override;
-  bool OnSetFocus(CXFA_FFWidget* pOldWidget) override;
-  bool OnKillFocus(CXFA_FFWidget* pNewWidget) override;
+  bool OnSetFocus(CXFA_FFWidget* pOldWidget) override WARN_UNUSED_RESULT;
+  bool OnKillFocus(CXFA_FFWidget* pNewWidget) override WARN_UNUSED_RESULT;
   void OnProcessMessage(CFWL_Message* pMessage) override;
   void OnProcessEvent(CFWL_Event* pEvent) override;
   void OnDrawWidget(CXFA_Graphics* pGraphics,
                     const CFX_Matrix& matrix) override;
 
-  void OnTextChanged(CFWL_Widget* pWidget,
-                     const WideString& wsChanged,
-                     const WideString& wsPrevText);
+  void OnTextWillChange(CFWL_Widget* pWidget, CFWL_EventTextWillChange* change);
   void OnTextFull(CFWL_Widget* pWidget);
-  bool CheckWord(const ByteStringView& sWord);
 
   // CXFA_FFWidget
   bool CanUndo() override;
@@ -57,12 +58,13 @@
   void SelectAll() override;
   void Delete() override;
   void DeSelect() override;
+  WideString GetText() override;
   FormFieldType GetFormFieldType() override;
 
  protected:
   uint32_t GetAlignment();
 
-  IFWL_WidgetDelegate* m_pOldDelegate;
+  UnownedPtr<IFWL_WidgetDelegate> m_pOldDelegate;
 
  private:
   bool CommitData() override;
diff --git a/xfa/fxfa/cxfa_ffwidget.cpp b/xfa/fxfa/cxfa_ffwidget.cpp
index 71c45c7..881218c 100644
--- a/xfa/fxfa/cxfa_ffwidget.cpp
+++ b/xfa/fxfa/cxfa_ffwidget.cpp
@@ -12,24 +12,25 @@
 #include <utility>
 #include <vector>
 
-#include "core/fpdfapi/cpdf_modulemgr.h"
-#include "core/fxcodec/codec/ccodec_progressivedecoder.h"
 #include "core/fxcodec/fx_codec.h"
-#include "core/fxcrt/cfx_memorystream.h"
+#include "core/fxcodec/progressivedecoder.h"
 #include "core/fxcrt/maybe_owned.h"
 #include "core/fxge/cfx_pathdata.h"
+#include "core/fxge/cfx_renderdevice.h"
+#include "core/fxge/dib/cfx_dibitmap.h"
 #include "xfa/fwl/fwl_widgethit.h"
 #include "xfa/fxfa/cxfa_eventparam.h"
 #include "xfa/fxfa/cxfa_ffapp.h"
 #include "xfa/fxfa/cxfa_ffdoc.h"
 #include "xfa/fxfa/cxfa_ffdocview.h"
 #include "xfa/fxfa/cxfa_ffpageview.h"
+#include "xfa/fxfa/cxfa_ffwidgethandler.h"
 #include "xfa/fxfa/cxfa_imagerenderer.h"
-#include "xfa/fxfa/cxfa_widgetacc.h"
+#include "xfa/fxfa/layout/cxfa_layoutprocessor.h"
 #include "xfa/fxfa/parser/cxfa_border.h"
 #include "xfa/fxfa/parser/cxfa_box.h"
+#include "xfa/fxfa/parser/cxfa_edge.h"
 #include "xfa/fxfa/parser/cxfa_image.h"
-#include "xfa/fxfa/parser/cxfa_layoutprocessor.h"
 #include "xfa/fxfa/parser/cxfa_margin.h"
 #include "xfa/fxfa/parser/cxfa_node.h"
 #include "xfa/fxgraphics/cxfa_graphics.h"
@@ -41,16 +42,23 @@
                               int32_t iBitsPerComponent) {
   FXDIB_Format dibFormat = FXDIB_Argb;
   switch (type) {
-    case FXCODEC_IMAGE_BMP:
     case FXCODEC_IMAGE_JPG:
-    case FXCODEC_IMAGE_TIF: {
+#ifdef PDF_ENABLE_XFA_BMP
+    case FXCODEC_IMAGE_BMP:
+#endif  // PDF_ENABLE_XFA_BMP
+#ifdef PDF_ENABLE_XFA_TIFF
+    case FXCODEC_IMAGE_TIFF:
+#endif  // PDF_ENABLE_XFA_TIFF
+    {
       dibFormat = FXDIB_Rgb32;
       int32_t bpp = iComponents * iBitsPerComponent;
       if (bpp <= 24) {
         dibFormat = FXDIB_Rgb;
       }
     } break;
+#ifdef PDF_ENABLE_XFA_PNG
     case FXCODEC_IMAGE_PNG:
+#endif  // PDF_ENABLE_XFA_PNG
     default:
       break;
   }
@@ -59,9 +67,7 @@
 
 bool IsFXCodecErrorStatus(FXCODEC_STATUS status) {
   return (status == FXCODEC_STATUS_ERROR ||
-#ifdef PDF_ENABLE_XFA
           status == FXCODEC_STATUS_ERR_MEMORY ||
-#endif  // PDF_ENABLE_XFA
           status == FXCODEC_STATUS_ERR_READ ||
           status == FXCODEC_STATUS_ERR_FLUSH ||
           status == FXCODEC_STATUS_ERR_FORMAT ||
@@ -74,22 +80,20 @@
                    const CFX_RectF& rtImage,
                    const CFX_Matrix& matrix,
                    const RetainPtr<CFX_DIBitmap>& pDIBitmap,
-                   XFA_AttributeEnum iAspect,
-                   int32_t iImageXDpi,
-                   int32_t iImageYDpi,
-                   XFA_AttributeEnum iHorzAlign,
-                   XFA_AttributeEnum iVertAlign) {
+                   XFA_AttributeValue iAspect,
+                   const CFX_Size& dpi,
+                   XFA_AttributeValue iHorzAlign,
+                   XFA_AttributeValue iVertAlign) {
   if (rtImage.IsEmpty())
     return;
   if (!pDIBitmap || !pDIBitmap->GetBuffer())
     return;
 
-  CFX_RectF rtFit(
-      rtImage.TopLeft(),
-      XFA_UnitPx2Pt((float)pDIBitmap->GetWidth(), (float)iImageXDpi),
-      XFA_UnitPx2Pt((float)pDIBitmap->GetHeight(), (float)iImageYDpi));
+  CFX_RectF rtFit(rtImage.TopLeft(),
+                  XFA_UnitPx2Pt(pDIBitmap->GetWidth(), dpi.width),
+                  XFA_UnitPx2Pt(pDIBitmap->GetHeight(), dpi.height));
   switch (iAspect) {
-    case XFA_AttributeEnum::Fit: {
+    case XFA_AttributeValue::Fit: {
       float f1 = rtImage.height / rtFit.height;
       float f2 = rtImage.width / rtFit.width;
       f1 = std::min(f1, f2);
@@ -97,35 +101,35 @@
       rtFit.width = rtFit.width * f1;
       break;
     }
-    case XFA_AttributeEnum::Height: {
+    case XFA_AttributeValue::Height: {
       float f1 = rtImage.height / rtFit.height;
       rtFit.height = rtImage.height;
       rtFit.width = f1 * rtFit.width;
       break;
     }
-    case XFA_AttributeEnum::None:
+    case XFA_AttributeValue::None:
       rtFit.height = rtImage.height;
       rtFit.width = rtImage.width;
       break;
-    case XFA_AttributeEnum::Width: {
+    case XFA_AttributeValue::Width: {
       float f1 = rtImage.width / rtFit.width;
       rtFit.width = rtImage.width;
       rtFit.height = rtFit.height * f1;
       break;
     }
-    case XFA_AttributeEnum::Actual:
+    case XFA_AttributeValue::Actual:
     default:
       break;
   }
 
-  if (iHorzAlign == XFA_AttributeEnum::Center)
+  if (iHorzAlign == XFA_AttributeValue::Center)
     rtFit.left += (rtImage.width - rtFit.width) / 2;
-  else if (iHorzAlign == XFA_AttributeEnum::Right)
+  else if (iHorzAlign == XFA_AttributeValue::Right)
     rtFit.left = rtImage.right() - rtFit.width;
 
-  if (iVertAlign == XFA_AttributeEnum::Middle)
+  if (iVertAlign == XFA_AttributeValue::Middle)
     rtFit.top += (rtImage.height - rtFit.height) / 2;
-  else if (iVertAlign == XFA_AttributeEnum::Bottom)
+  else if (iVertAlign == XFA_AttributeValue::Bottom)
     rtFit.top = rtImage.bottom() - rtImage.height;
 
   CFX_RenderDevice* pRenderDevice = pGS->GetRenderDevice();
@@ -152,8 +156,8 @@
     FXCODEC_IMAGE_TYPE type,
     int32_t& iImageXDpi,
     int32_t& iImageYDpi) {
-  CCodec_ModuleMgr* pCodecMgr = CPDF_ModuleMgr::Get()->GetCodecModule();
-  std::unique_ptr<CCodec_ProgressiveDecoder> pProgressiveDecoder =
+  auto* pCodecMgr = fxcodec::ModuleMgr::GetInstance();
+  std::unique_ptr<ProgressiveDecoder> pProgressiveDecoder =
       pCodecMgr->CreateProgressiveDecoder();
 
   CFX_DIBAttribute dibAttr;
@@ -212,42 +216,46 @@
   return pBitmap;
 }
 
-void XFA_RectWithoutMargin(CFX_RectF& rt, const CXFA_Margin* margin, bool bUI) {
+void XFA_RectWithoutMargin(CFX_RectF* rt, const CXFA_Margin* margin) {
   if (!margin)
     return;
 
-  rt.Deflate(margin->GetLeftInset(), margin->GetTopInset(),
-             margin->GetRightInset(), margin->GetBottomInset());
+  rt->Deflate(margin->GetLeftInset(), margin->GetTopInset(),
+              margin->GetRightInset(), margin->GetBottomInset());
 }
 
 CXFA_FFWidget* XFA_GetWidgetFromLayoutItem(CXFA_LayoutItem* pLayoutItem) {
-  if (pLayoutItem->GetFormNode()->HasCreatedUIWidget())
-    return static_cast<CXFA_FFWidget*>(pLayoutItem);
-  return nullptr;
+  if (!pLayoutItem->GetFormNode()->HasCreatedUIWidget())
+    return nullptr;
+
+  return GetFFWidget(ToContentLayoutItem(pLayoutItem));
 }
 
-CXFA_CalcData::CXFA_CalcData() : m_iRefCount(0) {}
+CXFA_CalcData::CXFA_CalcData() = default;
 
-CXFA_CalcData::~CXFA_CalcData() {}
+CXFA_CalcData::~CXFA_CalcData() = default;
 
-CXFA_FFWidget::CXFA_FFWidget(CXFA_Node* node)
-    : CXFA_ContentLayoutItem(node), m_pNode(node) {}
+CXFA_FFWidget::CXFA_FFWidget(CXFA_Node* node) : m_pNode(node) {}
 
-CXFA_FFWidget::~CXFA_FFWidget() {}
+CXFA_FFWidget::~CXFA_FFWidget() = default;
 
 const CFWL_App* CXFA_FFWidget::GetFWLApp() {
   return GetPageView()->GetDocView()->GetDoc()->GetApp()->GetFWLApp();
 }
 
+CXFA_FFWidget* CXFA_FFWidget::GetNextFFWidget() const {
+  return GetFFWidget(GetLayoutItem()->GetNext());
+}
+
 const CFX_RectF& CXFA_FFWidget::GetWidgetRect() const {
-  if ((m_dwStatus & XFA_WidgetStatus_RectCached) == 0)
+  if (!GetLayoutItem()->TestStatusBits(XFA_WidgetStatus_RectCached))
     RecacheWidgetRect();
   return m_rtWidget;
 }
 
 const CFX_RectF& CXFA_FFWidget::RecacheWidgetRect() const {
-  m_dwStatus |= XFA_WidgetStatus_RectCached;
-  m_rtWidget = GetRect(false);
+  GetLayoutItem()->SetStatusBits(XFA_WidgetStatus_RectCached);
+  m_rtWidget = GetLayoutItem()->GetRect(false);
   return m_rtWidget;
 }
 
@@ -275,24 +283,25 @@
   return rtWidget;
 }
 
-uint32_t CXFA_FFWidget::GetStatus() {
-  return m_dwStatus;
-}
-
 void CXFA_FFWidget::ModifyStatus(uint32_t dwAdded, uint32_t dwRemoved) {
-  m_dwStatus = (m_dwStatus & ~dwRemoved) | dwAdded;
+  GetLayoutItem()->ClearStatusBits(dwRemoved);
+  GetLayoutItem()->SetStatusBits(dwAdded);
 }
 
-CFX_RectF CXFA_FFWidget::GetBBox(uint32_t dwStatus, bool bDrawFocus) {
-  if (bDrawFocus || !m_pPageView)
+CXFA_FFField* CXFA_FFWidget::AsField() {
+  return nullptr;
+}
+
+CFX_RectF CXFA_FFWidget::GetBBox(FocusOption focus) {
+  if (focus == kDrawFocus || !m_pPageView)
     return CFX_RectF();
   return m_pPageView->GetPageViewRect();
 }
 
 void CXFA_FFWidget::RenderWidget(CXFA_Graphics* pGS,
                                  const CFX_Matrix& matrix,
-                                 uint32_t dwStatus) {
-  if (!IsMatchVisibleStatus(dwStatus))
+                                 HighlightOption highlight) {
+  if (!HasVisibleStatus())
     return;
 
   CXFA_Border* border = m_pNode->GetBorderIfExists();
@@ -301,9 +310,7 @@
 
   CFX_RectF rtBorder = GetRectWithoutRotate();
   CXFA_Margin* margin = border->GetMarginIfExists();
-  if (margin)
-    XFA_RectWithoutMargin(rtBorder, margin);
-
+  XFA_RectWithoutMargin(&rtBorder, margin);
   rtBorder.Normalize();
   DrawBorder(pGS, border, rtBorder, matrix);
 }
@@ -317,8 +324,6 @@
   return true;
 }
 
-void CXFA_FFWidget::UnloadWidget() {}
-
 bool CXFA_FFWidget::PerformLayout() {
   RecacheWidgetRect();
   return true;
@@ -330,6 +335,22 @@
 
 void CXFA_FFWidget::UpdateWidgetProperty() {}
 
+bool CXFA_FFWidget::HasEventUnderHandler(XFA_EVENTTYPE eEventType,
+                                         CXFA_FFWidgetHandler* pHandler) {
+  CXFA_Node* pNode = GetNode();
+  return pNode->IsWidgetReady() && pHandler->HasEvent(pNode, eEventType);
+}
+
+bool CXFA_FFWidget::ProcessEventUnderHandler(CXFA_EventParam* params,
+                                             CXFA_FFWidgetHandler* pHandler) {
+  CXFA_Node* pNode = GetNode();
+  if (!pNode->IsWidgetReady())
+    return false;
+
+  params->m_pTarget = pNode;
+  return pHandler->ProcessEvent(pNode, params) == XFA_EventError::kSuccess;
+}
+
 void CXFA_FFWidget::DrawBorder(CXFA_Graphics* pGS,
                                CXFA_Box* box,
                                const CFX_RectF& rtBorder,
@@ -347,10 +368,10 @@
     box->Draw(pGS, rtBorder, matrix, forceRound);
 }
 
-void CXFA_FFWidget::AddInvalidateRect() {
-  CFX_RectF rtWidget = GetBBox(XFA_WidgetStatus_Focused);
+void CXFA_FFWidget::InvalidateRect() {
+  CFX_RectF rtWidget = GetBBox(kDoNotDrawFocus);
   rtWidget.Inflate(2, 2);
-  m_pDocView->AddInvalidateRect(m_pPageView, rtWidget);
+  m_pDocView->InvalidateRect(m_pPageView.Get(), rtWidget);
 }
 
 bool CXFA_FFWidget::OnMouseEnter() {
@@ -361,6 +382,12 @@
   return false;
 }
 
+bool CXFA_FFWidget::AcceptsFocusOnButtonDown(uint32_t dwFlags,
+                                             const CFX_PointF& point,
+                                             FWL_MouseCommand command) {
+  return false;
+}
+
 bool CXFA_FFWidget::OnLButtonDown(uint32_t dwFlags, const CFX_PointF& point) {
   return false;
 }
@@ -396,28 +423,48 @@
 }
 
 bool CXFA_FFWidget::OnSetFocus(CXFA_FFWidget* pOldWidget) {
-  CXFA_FFWidget* pParent = GetParent();
+  // OnSetFocus event may remove this widget.
+  ObservedPtr<CXFA_FFWidget> pWatched(this);
+  CXFA_FFWidget* pParent = GetFFWidget(ToContentLayoutItem(GetParent()));
   if (pParent && !pParent->IsAncestorOf(pOldWidget)) {
-    pParent->OnSetFocus(pOldWidget);
+    if (!pParent->OnSetFocus(pOldWidget))
+      return false;
   }
-  m_dwStatus |= XFA_WidgetStatus_Focused;
+  if (!pWatched)
+    return false;
+
+  GetLayoutItem()->SetStatusBits(XFA_WidgetStatus_Focused);
+
   CXFA_EventParam eParam;
   eParam.m_eType = XFA_EVENT_Enter;
-  eParam.m_pTarget = m_pNode->GetWidgetAcc();
-  m_pNode->ProcessEvent(GetDocView(), XFA_AttributeEnum::Enter, &eParam);
-  return true;
+  eParam.m_pTarget = m_pNode.Get();
+  m_pNode->ProcessEvent(GetDocView(), XFA_AttributeValue::Enter, &eParam);
+
+  return !!pWatched;
 }
 
 bool CXFA_FFWidget::OnKillFocus(CXFA_FFWidget* pNewWidget) {
-  m_dwStatus &= ~XFA_WidgetStatus_Focused;
+  // OnKillFocus event may remove these widgets.
+  ObservedPtr<CXFA_FFWidget> pWatched(this);
+  ObservedPtr<CXFA_FFWidget> pNewWatched(pNewWidget);
+  GetLayoutItem()->ClearStatusBits(XFA_WidgetStatus_Focused);
   EventKillFocus();
-  if (pNewWidget) {
-    CXFA_FFWidget* pParent = GetParent();
-    if (pParent && !pParent->IsAncestorOf(pNewWidget)) {
-      pParent->OnKillFocus(pNewWidget);
-    }
+  if (!pWatched)
+    return false;
+
+  if (!pNewWidget)
+    return true;
+
+  if (!pNewWatched)
+    return false;
+
+  // OnKillFocus event may remove |pNewWidget|.
+  CXFA_FFWidget* pParent = GetFFWidget(ToContentLayoutItem(GetParent()));
+  if (pParent && !pParent->IsAncestorOf(pNewWidget)) {
+    if (!pParent->OnKillFocus(pNewWidget))
+      return false;
   }
-  return true;
+  return pWatched && pNewWatched;
 }
 
 bool CXFA_FFWidget::OnKeyDown(uint32_t dwKeyCode, uint32_t dwFlags) {
@@ -432,7 +479,7 @@
   return false;
 }
 
-FWL_WidgetHit CXFA_FFWidget::OnHitTest(const CFX_PointF& point) {
+FWL_WidgetHit CXFA_FFWidget::HitTest(const CFX_PointF& point) {
   return FWL_WidgetHit::Unknown;
 }
 
@@ -498,20 +545,14 @@
 
 void CXFA_FFWidget::DeSelect() {}
 
+WideString CXFA_FFWidget::GetText() {
+  return WideString();
+}
+
 FormFieldType CXFA_FFWidget::GetFormFieldType() {
   return FormFieldType::kXFA;
 }
 
-void CXFA_FFWidget::GetSuggestWords(CFX_PointF pointf,
-                                    std::vector<ByteString>* pWords) {
-  pWords->clear();
-}
-
-bool CXFA_FFWidget::ReplaceSpellCheckWord(CFX_PointF pointf,
-                                          const ByteStringView& bsReplace) {
-  return false;
-}
-
 CFX_PointF CXFA_FFWidget::Rotate2Normal(const CFX_PointF& point) {
   CFX_Matrix mt = GetRotateMatrix();
   if (mt.IsIdentity())
@@ -556,23 +597,40 @@
   return mt;
 }
 
+void CXFA_FFWidget::DisplayCaret(bool bVisible, const CFX_RectF* pRtAnchor) {
+  IXFA_DocEnvironment* pDocEnvironment = GetDoc()->GetDocEnvironment();
+  if (!pDocEnvironment)
+    return;
+
+  pDocEnvironment->DisplayCaret(this, bVisible, pRtAnchor);
+}
+
+void CXFA_FFWidget::GetBorderColorAndThickness(FX_ARGB* cr, float* fWidth) {
+  ASSERT(GetNode()->IsWidgetReady());
+  CXFA_Border* borderUI = GetNode()->GetUIBorder();
+  if (!borderUI)
+    return;
+
+  CXFA_Edge* edge = borderUI->GetEdgeIfExists(0);
+  if (!edge)
+    return;
+
+  *cr = edge->GetColor();
+  *fWidth = edge->GetThickness();
+}
+
 bool CXFA_FFWidget::IsLayoutRectEmpty() {
   CFX_RectF rtLayout = GetRectWithoutRotate();
   return rtLayout.width < 0.1f && rtLayout.height < 0.1f;
 }
 
-CXFA_FFWidget* CXFA_FFWidget::GetParent() {
+CXFA_LayoutItem* CXFA_FFWidget::GetParent() {
   CXFA_Node* pParentNode = m_pNode->GetParent();
-  if (pParentNode) {
-    CXFA_WidgetAcc* pParentWidgetAcc =
-        static_cast<CXFA_WidgetAcc*>(pParentNode->GetWidgetAcc());
-    if (pParentWidgetAcc) {
-      CXFA_LayoutProcessor* layout = GetDocView()->GetXFALayout();
-      return static_cast<CXFA_FFWidget*>(
-          layout->GetLayoutItem(pParentWidgetAcc->GetNode()));
-    }
-  }
-  return nullptr;
+  if (!pParentNode)
+    return nullptr;
+
+  CXFA_LayoutProcessor* layout = GetDocView()->GetXFALayout();
+  return layout->GetLayoutItem(pParentNode);
 }
 
 bool CXFA_FFWidget::IsAncestorOf(CXFA_FFWidget* pWidget) {
@@ -593,14 +651,6 @@
   return GetWidgetRect().Contains(point);
 }
 
-CXFA_FFDocView* CXFA_FFWidget::GetDocView() {
-  return m_pDocView;
-}
-
-void CXFA_FFWidget::SetDocView(CXFA_FFDocView* pDocView) {
-  m_pDocView = pDocView;
-}
-
 CXFA_FFDoc* CXFA_FFWidget::GetDoc() {
   return m_pDocView->GetDoc();
 }
@@ -613,26 +663,30 @@
   return GetApp()->GetAppProvider();
 }
 
-bool CXFA_FFWidget::IsMatchVisibleStatus(uint32_t dwStatus) {
-  return !!(m_dwStatus & XFA_WidgetStatus_Visible);
+bool CXFA_FFWidget::HasVisibleStatus() const {
+  return GetLayoutItem()->TestStatusBits(XFA_WidgetStatus_Visible);
 }
 
 void CXFA_FFWidget::EventKillFocus() {
-  if (m_dwStatus & XFA_WidgetStatus_Access) {
-    m_dwStatus &= ~XFA_WidgetStatus_Access;
+  CXFA_ContentLayoutItem* pItem = GetLayoutItem();
+  if (pItem->TestStatusBits(XFA_WidgetStatus_Access)) {
+    pItem->ClearStatusBits(XFA_WidgetStatus_Access);
     return;
   }
   CXFA_EventParam eParam;
   eParam.m_eType = XFA_EVENT_Exit;
-  eParam.m_pTarget = m_pNode->GetWidgetAcc();
-  m_pNode->ProcessEvent(GetDocView(), XFA_AttributeEnum::Exit, &eParam);
+  eParam.m_pTarget = m_pNode.Get();
+  m_pNode->ProcessEvent(GetDocView(), XFA_AttributeValue::Exit, &eParam);
 }
 
 bool CXFA_FFWidget::IsButtonDown() {
-  return (m_dwStatus & XFA_WidgetStatus_ButtonDown) != 0;
+  return GetLayoutItem()->TestStatusBits(XFA_WidgetStatus_ButtonDown);
 }
 
 void CXFA_FFWidget::SetButtonDown(bool bSet) {
-  bSet ? m_dwStatus |= XFA_WidgetStatus_ButtonDown
-       : m_dwStatus &= ~XFA_WidgetStatus_ButtonDown;
+  CXFA_ContentLayoutItem* pItem = GetLayoutItem();
+  if (bSet)
+    pItem->SetStatusBits(XFA_WidgetStatus_ButtonDown);
+  else
+    pItem->ClearStatusBits(XFA_WidgetStatus_ButtonDown);
 }
diff --git a/xfa/fxfa/cxfa_ffwidget.h b/xfa/fxfa/cxfa_ffwidget.h
index 54aa191..4c362c1 100644
--- a/xfa/fxfa/cxfa_ffwidget.h
+++ b/xfa/fxfa/cxfa_ffwidget.h
@@ -11,35 +11,42 @@
 
 #include "core/fpdfdoc/cpdf_formfield.h"
 #include "core/fxcodec/fx_codec_def.h"
+#include "core/fxcrt/observed_ptr.h"
 #include "core/fxge/cfx_graphstatedata.h"
 #include "xfa/fwl/cfwl_app.h"
+#include "xfa/fwl/cfwl_messagemouse.h"
+#include "xfa/fwl/cfwl_widget.h"
+#include "xfa/fxfa/cxfa_eventparam.h"
 #include "xfa/fxfa/fxfa.h"
-#include "xfa/fxfa/parser/cxfa_contentlayoutitem.h"
+#include "xfa/fxfa/layout/cxfa_contentlayoutitem.h"
 
+class CFX_DIBitmap;
 class CXFA_Box;
-class CXFA_FFPageView;
-class CXFA_FFDocView;
-class CXFA_FFDoc;
 class CXFA_FFApp;
+class CXFA_FFDoc;
+class CXFA_FFDocView;
+class CXFA_FFField;
+class CXFA_FFPageView;
+class CXFA_FFWidgetHandler;
 class CXFA_Graphics;
 class CXFA_Image;
+class CXFA_Margin;
 enum class FWL_WidgetHit;
 
 inline float XFA_UnitPx2Pt(float fPx, float fDpi) {
   return fPx * 72.0f / fDpi;
 }
 
-#define XFA_FLOAT_PERCISION 0.001f
+constexpr float kXFAWidgetPrecision = 0.001f;
 
 void XFA_DrawImage(CXFA_Graphics* pGS,
                    const CFX_RectF& rtImage,
                    const CFX_Matrix& matrix,
                    const RetainPtr<CFX_DIBitmap>& pDIBitmap,
-                   XFA_AttributeEnum iAspect,
-                   int32_t iImageXDpi,
-                   int32_t iImageYDpi,
-                   XFA_AttributeEnum iHorzAlign = XFA_AttributeEnum::Left,
-                   XFA_AttributeEnum iVertAlign = XFA_AttributeEnum::Top);
+                   XFA_AttributeValue iAspect,
+                   const CFX_Size& dpi,
+                   XFA_AttributeValue iHorzAlign = XFA_AttributeValue::Left,
+                   XFA_AttributeValue iVertAlign = XFA_AttributeValue::Top);
 
 RetainPtr<CFX_DIBitmap> XFA_LoadImageFromBuffer(
     const RetainPtr<IFX_SeekableReadStream>& pImageFileRead,
@@ -47,9 +54,7 @@
     int32_t& iImageXDpi,
     int32_t& iImageYDpi);
 
-void XFA_RectWithoutMargin(CFX_RectF& rt,
-                           const CXFA_Margin* margin,
-                           bool bUI = false);
+void XFA_RectWithoutMargin(CFX_RectF* rt, const CXFA_Margin* margin);
 CXFA_FFWidget* XFA_GetWidgetFromLayoutItem(CXFA_LayoutItem* pLayoutItem);
 
 class CXFA_CalcData {
@@ -58,44 +63,66 @@
   ~CXFA_CalcData();
 
   std::vector<CXFA_Node*> m_Globals;
-  int32_t m_iRefCount;
 };
 
-class CXFA_FFWidget : public CXFA_ContentLayoutItem {
+class CXFA_FFWidget : public Observable, public CFWL_Widget::AdapterIface {
  public:
+  enum FocusOption { kDoNotDrawFocus = 0, kDrawFocus };
+  enum HighlightOption { kNoHighlight = 0, kHighlight };
+
   explicit CXFA_FFWidget(CXFA_Node* pNode);
   ~CXFA_FFWidget() override;
 
-  virtual CFX_RectF GetBBox(uint32_t dwStatus, bool bDrawFocus = false);
+  // CFWL_Widget::AdapterIface:
+  CFX_Matrix GetRotateMatrix() override;
+  void DisplayCaret(bool bVisible, const CFX_RectF* pRtAnchor) override;
+  void GetBorderColorAndThickness(FX_ARGB* cr, float* fWidth) override;
+
+  virtual CXFA_FFField* AsField();
+
+  virtual CFX_RectF GetBBox(FocusOption focus);
   virtual void RenderWidget(CXFA_Graphics* pGS,
                             const CFX_Matrix& matrix,
-                            uint32_t dwStatus);
+                            HighlightOption highlight);
   virtual bool IsLoaded();
   virtual bool LoadWidget();
-  virtual void UnloadWidget();
   virtual bool PerformLayout();
   virtual bool UpdateFWLData();
   virtual void UpdateWidgetProperty();
-  virtual bool OnMouseEnter();
-  virtual bool OnMouseExit();
-  virtual bool OnLButtonDown(uint32_t dwFlags, const CFX_PointF& point);
-  virtual bool OnLButtonUp(uint32_t dwFlags, const CFX_PointF& point);
-  virtual bool OnLButtonDblClk(uint32_t dwFlags, const CFX_PointF& point);
-  virtual bool OnMouseMove(uint32_t dwFlags, const CFX_PointF& point);
+  // |command| must be LeftButtonDown or RightButtonDown.
+  virtual bool AcceptsFocusOnButtonDown(uint32_t dwFlags,
+                                        const CFX_PointF& point,
+                                        FWL_MouseCommand command);
+
+  // Caution: Returning false from an On* method may mean |this| is destroyed.
+  virtual bool OnMouseEnter() WARN_UNUSED_RESULT;
+  virtual bool OnMouseExit() WARN_UNUSED_RESULT;
+  virtual bool OnLButtonDown(uint32_t dwFlags,
+                             const CFX_PointF& point) WARN_UNUSED_RESULT;
+  virtual bool OnLButtonUp(uint32_t dwFlags,
+                           const CFX_PointF& point) WARN_UNUSED_RESULT;
+  virtual bool OnLButtonDblClk(uint32_t dwFlags,
+                               const CFX_PointF& point) WARN_UNUSED_RESULT;
+  virtual bool OnMouseMove(uint32_t dwFlags,
+                           const CFX_PointF& point) WARN_UNUSED_RESULT;
   virtual bool OnMouseWheel(uint32_t dwFlags,
                             int16_t zDelta,
-                            const CFX_PointF& point);
-  virtual bool OnRButtonDown(uint32_t dwFlags, const CFX_PointF& point);
-  virtual bool OnRButtonUp(uint32_t dwFlags, const CFX_PointF& point);
-  virtual bool OnRButtonDblClk(uint32_t dwFlags, const CFX_PointF& point);
+                            const CFX_PointF& point) WARN_UNUSED_RESULT;
+  virtual bool OnRButtonDown(uint32_t dwFlags,
+                             const CFX_PointF& point) WARN_UNUSED_RESULT;
+  virtual bool OnRButtonUp(uint32_t dwFlags,
+                           const CFX_PointF& point) WARN_UNUSED_RESULT;
+  virtual bool OnRButtonDblClk(uint32_t dwFlags,
+                               const CFX_PointF& point) WARN_UNUSED_RESULT;
+  virtual bool OnSetFocus(CXFA_FFWidget* pOldWidget) WARN_UNUSED_RESULT;
+  virtual bool OnKillFocus(CXFA_FFWidget* pNewWidget) WARN_UNUSED_RESULT;
+  virtual bool OnKeyDown(uint32_t dwKeyCode,
+                         uint32_t dwFlags) WARN_UNUSED_RESULT;
+  virtual bool OnKeyUp(uint32_t dwKeyCode, uint32_t dwFlags) WARN_UNUSED_RESULT;
+  virtual bool OnChar(uint32_t dwChar, uint32_t dwFlags) WARN_UNUSED_RESULT;
+  virtual bool OnSetCursor(const CFX_PointF& point) WARN_UNUSED_RESULT;
 
-  virtual bool OnSetFocus(CXFA_FFWidget* pOldWidget);
-  virtual bool OnKillFocus(CXFA_FFWidget* pNewWidget);
-  virtual bool OnKeyDown(uint32_t dwKeyCode, uint32_t dwFlags);
-  virtual bool OnKeyUp(uint32_t dwKeyCode, uint32_t dwFlags);
-  virtual bool OnChar(uint32_t dwChar, uint32_t dwFlags);
-  virtual FWL_WidgetHit OnHitTest(const CFX_PointF& point);
-  virtual bool OnSetCursor(const CFX_PointF& point);
+  virtual FWL_WidgetHit HitTest(const CFX_PointF& point);
   virtual bool CanUndo();
   virtual bool CanRedo();
   virtual bool Undo();
@@ -112,37 +139,40 @@
   virtual void SelectAll();
   virtual void Delete();
   virtual void DeSelect();
-
+  virtual WideString GetText();
   virtual FormFieldType GetFormFieldType();
 
-  // TODO(tsepez): Implement or remove.
-  void GetSuggestWords(CFX_PointF pointf, std::vector<ByteString>* pWords);
-  bool ReplaceSpellCheckWord(CFX_PointF pointf,
-                             const ByteStringView& bsReplace);
-
-  CXFA_FFPageView* GetPageView() const { return m_pPageView; }
+  CXFA_Node* GetNode() const { return m_pNode.Get(); }
+  CXFA_ContentLayoutItem* GetLayoutItem() const { return m_pLayoutItem.Get(); }
+  void SetLayoutItem(CXFA_ContentLayoutItem* pItem) { m_pLayoutItem = pItem; }
+  CXFA_FFPageView* GetPageView() const { return m_pPageView.Get(); }
   void SetPageView(CXFA_FFPageView* pPageView) { m_pPageView = pPageView; }
+  CXFA_FFDocView* GetDocView() const { return m_pDocView.Get(); }
+  void SetDocView(CXFA_FFDocView* pDocView) { m_pDocView = pDocView; }
+
+  CXFA_FFWidget* GetNextFFWidget() const;
   const CFX_RectF& GetWidgetRect() const;
   const CFX_RectF& RecacheWidgetRect() const;
-  uint32_t GetStatus();
   void ModifyStatus(uint32_t dwAdded, uint32_t dwRemoved);
 
-  CXFA_Node* GetNode() { return m_pNode.Get(); }
-
-  CXFA_FFDocView* GetDocView();
-  void SetDocView(CXFA_FFDocView* pDocView);
   CXFA_FFDoc* GetDoc();
   CXFA_FFApp* GetApp();
   IXFA_AppProvider* GetAppProvider();
-  void AddInvalidateRect();
-  bool IsFocused() const { return !!(m_dwStatus & XFA_WidgetStatus_Focused); }
+  void InvalidateRect();
+  bool IsFocused() const {
+    return GetLayoutItem()->TestStatusBits(XFA_WidgetStatus_Focused);
+  }
   CFX_PointF Rotate2Normal(const CFX_PointF& point);
-  CFX_Matrix GetRotateMatrix();
   bool IsLayoutRectEmpty();
-  CXFA_FFWidget* GetParent();
+  CXFA_LayoutItem* GetParent();
   bool IsAncestorOf(CXFA_FFWidget* pWidget);
   const CFWL_App* GetFWLApp();
 
+  bool HasEventUnderHandler(XFA_EVENTTYPE eEventType,
+                            CXFA_FFWidgetHandler* pHandler);
+  bool ProcessEventUnderHandler(CXFA_EventParam* params,
+                                CXFA_FFWidgetHandler* pHandler);
+
  protected:
   virtual bool PtInActiveRect(const CFX_PointF& point);
 
@@ -157,15 +187,20 @@
                           bool forceRound);
 
   CFX_RectF GetRectWithoutRotate();
-  bool IsMatchVisibleStatus(uint32_t dwStatus);
+  bool HasVisibleStatus() const;
   void EventKillFocus();
   bool IsButtonDown();
   void SetButtonDown(bool bSet);
 
-  CXFA_FFDocView* m_pDocView = nullptr;
-  CXFA_FFPageView* m_pPageView = nullptr;
+  UnownedPtr<CXFA_ContentLayoutItem> m_pLayoutItem;
+  UnownedPtr<CXFA_FFDocView> m_pDocView;
+  UnownedPtr<CXFA_FFPageView> m_pPageView;
   UnownedPtr<CXFA_Node> const m_pNode;
   mutable CFX_RectF m_rtWidget;
 };
 
+inline CXFA_FFField* ToField(CXFA_FFWidget* widget) {
+  return widget ? widget->AsField() : nullptr;
+}
+
 #endif  // XFA_FXFA_CXFA_FFWIDGET_H_
diff --git a/xfa/fxfa/cxfa_ffwidget_type.h b/xfa/fxfa/cxfa_ffwidget_type.h
new file mode 100644
index 0000000..69fbcd2
--- /dev/null
+++ b/xfa/fxfa/cxfa_ffwidget_type.h
@@ -0,0 +1,31 @@
+// Copyright 2019 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_CXFA_FFWIDGET_TYPE_H_
+#define XFA_FXFA_CXFA_FFWIDGET_TYPE_H_
+
+enum class XFA_FFWidgetType {
+  kNone = 0,
+  kBarcode,
+  kButton,
+  kCheckButton,
+  kChoiceList,
+  kDateTimeEdit,
+  kImageEdit,
+  kNumericEdit,
+  kPasswordEdit,
+  kSignature,
+  kTextEdit,
+  kArc,
+  kLine,
+  kRectangle,
+  kText,
+  kImage,
+  kSubform,
+  kExclGroup
+};
+
+#endif  // XFA_FXFA_CXFA_FFWIDGET_TYPE_H_
diff --git a/xfa/fxfa/cxfa_ffwidgethandler.cpp b/xfa/fxfa/cxfa_ffwidgethandler.cpp
index c124c91..aa5dc3a 100644
--- a/xfa/fxfa/cxfa_ffwidgethandler.cpp
+++ b/xfa/fxfa/cxfa_ffwidgethandler.cpp
@@ -14,9 +14,9 @@
 #include "xfa/fxfa/cxfa_fffield.h"
 #include "xfa/fxfa/cxfa_ffwidget.h"
 #include "xfa/fxfa/cxfa_fwladapterwidgetmgr.h"
+#include "xfa/fxfa/layout/cxfa_layoutprocessor.h"
 #include "xfa/fxfa/parser/cxfa_calculate.h"
 #include "xfa/fxfa/parser/cxfa_checkbutton.h"
-#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_ui.h"
@@ -47,10 +47,14 @@
                                          uint32_t dwFlags,
                                          const CFX_PointF& point) {
   m_pDocView->LockUpdate();
-  bool bRet = hWidget->OnLButtonDown(dwFlags, hWidget->Rotate2Normal(point));
-  if (bRet && m_pDocView->SetFocus(hWidget)) {
-    m_pDocView->GetDoc()->GetDocEnvironment()->SetFocusWidget(
-        m_pDocView->GetDoc(), hWidget);
+  bool bRet = hWidget->AcceptsFocusOnButtonDown(
+      dwFlags, hWidget->Rotate2Normal(point), FWL_MouseCommand::LeftButtonDown);
+  if (bRet) {
+    if (m_pDocView->SetFocus(hWidget)) {
+      m_pDocView->GetDoc()->GetDocEnvironment()->SetFocusWidget(
+          m_pDocView->GetDoc(), hWidget);
+    }
+    bRet = hWidget->OnLButtonDown(dwFlags, hWidget->Rotate2Normal(point));
   }
   m_pDocView->UnlockUpdate();
   m_pDocView->UpdateDocView();
@@ -72,7 +76,6 @@
                                            uint32_t dwFlags,
                                            const CFX_PointF& point) {
   bool bRet = hWidget->OnLButtonDblClk(dwFlags, hWidget->Rotate2Normal(point));
-  m_pDocView->RunInvalidate();
   return bRet;
 }
 
@@ -80,7 +83,6 @@
                                        uint32_t dwFlags,
                                        const CFX_PointF& point) {
   bool bRet = hWidget->OnMouseMove(dwFlags, hWidget->Rotate2Normal(point));
-  m_pDocView->RunInvalidate();
   return bRet;
 }
 
@@ -90,19 +92,22 @@
                                         const CFX_PointF& point) {
   bool bRet =
       hWidget->OnMouseWheel(dwFlags, zDelta, hWidget->Rotate2Normal(point));
-  m_pDocView->RunInvalidate();
   return bRet;
 }
 
 bool CXFA_FFWidgetHandler::OnRButtonDown(CXFA_FFWidget* hWidget,
                                          uint32_t dwFlags,
                                          const CFX_PointF& point) {
-  bool bRet = hWidget->OnRButtonDown(dwFlags, hWidget->Rotate2Normal(point));
-  if (bRet && m_pDocView->SetFocus(hWidget)) {
-    m_pDocView->GetDoc()->GetDocEnvironment()->SetFocusWidget(
-        m_pDocView->GetDoc(), hWidget);
+  bool bRet =
+      hWidget->AcceptsFocusOnButtonDown(dwFlags, hWidget->Rotate2Normal(point),
+                                        FWL_MouseCommand::RightButtonDown);
+  if (bRet) {
+    if (m_pDocView->SetFocus(hWidget)) {
+      m_pDocView->GetDoc()->GetDocEnvironment()->SetFocusWidget(
+          m_pDocView->GetDoc(), hWidget);
+    }
+    bRet = hWidget->OnRButtonDown(dwFlags, hWidget->Rotate2Normal(point));
   }
-  m_pDocView->RunInvalidate();
   return bRet;
 }
 
@@ -110,7 +115,6 @@
                                        uint32_t dwFlags,
                                        const CFX_PointF& point) {
   bool bRet = hWidget->OnRButtonUp(dwFlags, hWidget->Rotate2Normal(point));
-  m_pDocView->RunInvalidate();
   return bRet;
 }
 
@@ -118,7 +122,6 @@
                                            uint32_t dwFlags,
                                            const CFX_PointF& point) {
   bool bRet = hWidget->OnRButtonDblClk(dwFlags, hWidget->Rotate2Normal(point));
-  m_pDocView->RunInvalidate();
   return bRet;
 }
 
@@ -126,7 +129,6 @@
                                      uint32_t dwKeyCode,
                                      uint32_t dwFlags) {
   bool bRet = hWidget->OnKeyDown(dwKeyCode, dwFlags);
-  m_pDocView->RunInvalidate();
   m_pDocView->UpdateDocView();
   return bRet;
 }
@@ -135,7 +137,6 @@
                                    uint32_t dwKeyCode,
                                    uint32_t dwFlags) {
   bool bRet = hWidget->OnKeyUp(dwKeyCode, dwFlags);
-  m_pDocView->RunInvalidate();
   return bRet;
 }
 
@@ -143,10 +144,13 @@
                                   uint32_t dwChar,
                                   uint32_t dwFlags) {
   bool bRet = hWidget->OnChar(dwChar, dwFlags);
-  m_pDocView->RunInvalidate();
   return bRet;
 }
 
+WideString CXFA_FFWidgetHandler::GetText(CXFA_FFWidget* widget) {
+  return widget->GetText();
+}
+
 WideString CXFA_FFWidgetHandler::GetSelectedText(CXFA_FFWidget* widget) {
   if (!widget->CanCopy())
     return WideString();
@@ -162,11 +166,27 @@
   widget->Paste(text);
 }
 
-FWL_WidgetHit CXFA_FFWidgetHandler::OnHitTest(CXFA_FFWidget* hWidget,
-                                              const CFX_PointF& point) {
-  if (!(hWidget->GetStatus() & XFA_WidgetStatus_Visible))
+bool CXFA_FFWidgetHandler::CanUndo(CXFA_FFWidget* widget) {
+  return widget->CanUndo();
+}
+
+bool CXFA_FFWidgetHandler::CanRedo(CXFA_FFWidget* widget) {
+  return widget->CanRedo();
+}
+
+bool CXFA_FFWidgetHandler::Undo(CXFA_FFWidget* widget) {
+  return widget->Undo();
+}
+
+bool CXFA_FFWidgetHandler::Redo(CXFA_FFWidget* widget) {
+  return widget->Redo();
+}
+
+FWL_WidgetHit CXFA_FFWidgetHandler::HitTest(CXFA_FFWidget* pWidget,
+                                            const CFX_PointF& point) {
+  if (!pWidget->GetLayoutItem()->TestStatusBits(XFA_WidgetStatus_Visible))
     return FWL_WidgetHit::Unknown;
-  return hWidget->OnHitTest(hWidget->Rotate2Normal(point));
+  return pWidget->HitTest(pWidget->Rotate2Normal(point));
 }
 
 bool CXFA_FFWidgetHandler::OnSetCursor(CXFA_FFWidget* hWidget,
@@ -178,399 +198,62 @@
                                         CXFA_Graphics* pGS,
                                         const CFX_Matrix& matrix,
                                         bool bHighlight) {
-  hWidget->RenderWidget(pGS, matrix,
-                        bHighlight ? XFA_WidgetStatus_Highlight : 0);
+  hWidget->RenderWidget(
+      pGS, matrix,
+      bHighlight ? CXFA_FFWidget::kHighlight : CXFA_FFWidget::kNoHighlight);
 }
 
-bool CXFA_FFWidgetHandler::HasEvent(CXFA_WidgetAcc* pWidgetAcc,
+bool CXFA_FFWidgetHandler::HasEvent(CXFA_Node* pNode,
                                     XFA_EVENTTYPE eEventType) {
   if (eEventType == XFA_EVENT_Unknown)
     return false;
-  if (!pWidgetAcc)
-    return false;
-
-  CXFA_Node* node = pWidgetAcc->GetNode();
-  if (!node || node->GetElementType() == XFA_Element::Draw)
+  if (!pNode || pNode->GetElementType() == XFA_Element::Draw)
     return false;
 
   switch (eEventType) {
     case XFA_EVENT_Calculate: {
-      CXFA_Calculate* calc = node->GetCalculateIfExists();
+      CXFA_Calculate* calc = pNode->GetCalculateIfExists();
       return calc && calc->GetScriptIfExists();
     }
     case XFA_EVENT_Validate: {
-      CXFA_Validate* validate = node->GetValidateIfExists();
+      CXFA_Validate* validate = pNode->GetValidateIfExists();
       return validate && validate->GetScriptIfExists();
     }
     default:
       break;
   }
-  return !pWidgetAcc->GetEventByActivity(gs_EventActivity[eEventType], false)
+  return !pNode->GetEventByActivity(gs_EventActivity[eEventType], false)
               .empty();
 }
 
-int32_t CXFA_FFWidgetHandler::ProcessEvent(CXFA_WidgetAcc* pWidgetAcc,
-                                           CXFA_EventParam* pParam) {
+XFA_EventError CXFA_FFWidgetHandler::ProcessEvent(CXFA_Node* pNode,
+                                                  CXFA_EventParam* pParam) {
   if (!pParam || pParam->m_eType == XFA_EVENT_Unknown)
-    return XFA_EVENTERROR_NotExist;
-  if (!pWidgetAcc)
-    return XFA_EVENTERROR_NotExist;
-
-  CXFA_Node* node = pWidgetAcc->GetNode();
-  if (!node || node->GetElementType() == XFA_Element::Draw)
-    return XFA_EVENTERROR_NotExist;
+    return XFA_EventError::kNotExist;
+  if (!pNode || pNode->GetElementType() == XFA_Element::Draw)
+    return XFA_EventError::kNotExist;
 
   switch (pParam->m_eType) {
     case XFA_EVENT_Calculate:
-      return node->ProcessCalculate(m_pDocView);
+      return pNode->ProcessCalculate(m_pDocView.Get());
     case XFA_EVENT_Validate:
       if (m_pDocView->GetDoc()->GetDocEnvironment()->IsValidationsEnabled(
               m_pDocView->GetDoc())) {
-        return node->ProcessValidate(m_pDocView, 0);
+        return pNode->ProcessValidate(m_pDocView.Get(), 0);
       }
-      return XFA_EVENTERROR_Disabled;
+      return XFA_EventError::kDisabled;
     case XFA_EVENT_InitCalculate: {
-      CXFA_Calculate* calc = node->GetCalculateIfExists();
+      CXFA_Calculate* calc = pNode->GetCalculateIfExists();
       if (!calc)
-        return XFA_EVENTERROR_NotExist;
-      if (node->IsUserInteractive())
-        return XFA_EVENTERROR_Disabled;
-      return node->ExecuteScript(m_pDocView, calc->GetScriptIfExists(), pParam);
+        return XFA_EventError::kNotExist;
+      if (pNode->IsUserInteractive())
+        return XFA_EventError::kDisabled;
+      return pNode->ExecuteScript(m_pDocView.Get(), calc->GetScriptIfExists(),
+                                  pParam);
     }
     default:
       break;
   }
-  int32_t iRet =
-      node->ProcessEvent(m_pDocView, gs_EventActivity[pParam->m_eType], pParam);
-  return iRet;
-}
-
-CXFA_FFWidget* CXFA_FFWidgetHandler::CreateWidget(CXFA_FFWidget* hParent,
-                                                  XFA_WIDGETTYPE eType,
-                                                  CXFA_FFWidget* hBefore) {
-  CXFA_Node* pParentFormItem = hParent ? hParent->GetNode() : nullptr;
-  CXFA_Node* pBeforeFormItem = hBefore ? hBefore->GetNode() : nullptr;
-  CXFA_Node* pNewFormItem =
-      CreateWidgetFormItem(eType, pParentFormItem, pBeforeFormItem);
-  if (!pNewFormItem)
-    return nullptr;
-
-  CXFA_Node* templateNode = pNewFormItem->GetTemplateNodeIfExists();
-  if (!templateNode)
-    return nullptr;
-
-  templateNode->SetFlag(XFA_NodeFlag_Initialized, true);
-  pNewFormItem->SetFlag(XFA_NodeFlag_Initialized, true);
-  m_pDocView->RunLayout();
-  CXFA_LayoutItem* pLayout =
-      m_pDocView->GetXFALayout()->GetLayoutItem(pNewFormItem);
-  return static_cast<CXFA_FFWidget*>(pLayout);
-}
-
-CXFA_Node* CXFA_FFWidgetHandler::CreateWidgetFormItem(
-    XFA_WIDGETTYPE eType,
-    CXFA_Node* pParent,
-    CXFA_Node* pBefore) const {
-  switch (eType) {
-    case XFA_WIDGETTYPE_Barcode:
-      return nullptr;
-    case XFA_WIDGETTYPE_PushButton:
-      return CreatePushButton(pParent, pBefore);
-    case XFA_WIDGETTYPE_CheckButton:
-      return CreateCheckButton(pParent, pBefore);
-    case XFA_WIDGETTYPE_ExcludeGroup:
-      return CreateExclGroup(pParent, pBefore);
-    case XFA_WIDGETTYPE_RadioButton:
-      return CreateRadioButton(pParent, pBefore);
-    case XFA_WIDGETTYPE_Arc:
-      return CreateArc(pParent, pBefore);
-    case XFA_WIDGETTYPE_Rectangle:
-      return CreateRectangle(pParent, pBefore);
-    case XFA_WIDGETTYPE_Image:
-      return CreateImage(pParent, pBefore);
-    case XFA_WIDGETTYPE_Line:
-      return CreateLine(pParent, pBefore);
-    case XFA_WIDGETTYPE_Text:
-      return CreateText(pParent, pBefore);
-    case XFA_WIDGETTYPE_DatetimeEdit:
-      return CreateDatetimeEdit(pParent, pBefore);
-    case XFA_WIDGETTYPE_DecimalField:
-      return CreateDecimalField(pParent, pBefore);
-    case XFA_WIDGETTYPE_NumericField:
-      return CreateNumericField(pParent, pBefore);
-    case XFA_WIDGETTYPE_Signature:
-      return CreateSignature(pParent, pBefore);
-    case XFA_WIDGETTYPE_TextEdit:
-      return CreateTextEdit(pParent, pBefore);
-    case XFA_WIDGETTYPE_DropdownList:
-      return CreateDropdownList(pParent, pBefore);
-    case XFA_WIDGETTYPE_ListBox:
-      return CreateListBox(pParent, pBefore);
-    case XFA_WIDGETTYPE_ImageField:
-      return CreateImageField(pParent, pBefore);
-    case XFA_WIDGETTYPE_PasswordEdit:
-      return CreatePasswordEdit(pParent, pBefore);
-    case XFA_WIDGETTYPE_Subform:
-      return CreateSubform(pParent, pBefore);
-    default:
-      return nullptr;
-  }
-}
-
-CXFA_Node* CXFA_FFWidgetHandler::CreatePushButton(CXFA_Node* pParent,
-                                                  CXFA_Node* pBefore) const {
-  CXFA_Node* pField = CreateField(XFA_Element::Button, pParent, pBefore);
-  CXFA_Node* pCaption = CreateCopyNode(XFA_Element::Caption, pField);
-  CXFA_Node* pValue = CreateCopyNode(XFA_Element::Value, pCaption);
-  CXFA_Node* pText = CreateCopyNode(XFA_Element::Text, pValue);
-  pText->JSObject()->SetContent(L"Button", L"Button", false, false, true);
-
-  CXFA_Node* pPara = CreateCopyNode(XFA_Element::Para, pCaption);
-  pPara->JSObject()->SetEnum(XFA_Attribute::VAlign, XFA_AttributeEnum::Middle,
-                             false);
-  pPara->JSObject()->SetEnum(XFA_Attribute::HAlign, XFA_AttributeEnum::Center,
-                             false);
-  CreateFontNode(pCaption);
-
-  CXFA_Node* pBorder = CreateCopyNode(XFA_Element::Border, pField);
-  pBorder->JSObject()->SetEnum(XFA_Attribute::Hand, XFA_AttributeEnum::Right,
-                               false);
-
-  CXFA_Node* pEdge = CreateCopyNode(XFA_Element::Edge, pBorder);
-  pEdge->JSObject()->SetEnum(XFA_Attribute::Stroke, XFA_AttributeEnum::Raised,
-                             false);
-
-  CXFA_Node* pFill = CreateCopyNode(XFA_Element::Fill, pBorder);
-  CXFA_Node* pColor = CreateCopyNode(XFA_Element::Color, pFill);
-  pColor->JSObject()->SetCData(XFA_Attribute::Value, L"212, 208, 200", false,
-                               false);
-
-  CXFA_Node* pBind = CreateCopyNode(XFA_Element::Bind, pField);
-  pBind->JSObject()->SetEnum(XFA_Attribute::Match, XFA_AttributeEnum::None,
-                             false);
-
-  return pField;
-}
-
-CXFA_Node* CXFA_FFWidgetHandler::CreateCheckButton(CXFA_Node* pParent,
-                                                   CXFA_Node* pBefore) const {
-  return CreateField(XFA_Element::CheckButton, pParent, pBefore);
-}
-
-CXFA_Node* CXFA_FFWidgetHandler::CreateExclGroup(CXFA_Node* pParent,
-                                                 CXFA_Node* pBefore) const {
-  return CreateFormItem(XFA_Element::ExclGroup, pParent, pBefore);
-}
-
-CXFA_Node* CXFA_FFWidgetHandler::CreateRadioButton(CXFA_Node* pParent,
-                                                   CXFA_Node* pBefore) const {
-  CXFA_Node* pField = CreateField(XFA_Element::CheckButton, pParent, pBefore);
-  CXFA_Ui* pUi = pField->GetFirstChildByClass<CXFA_Ui>(XFA_Element::Ui);
-  CXFA_CheckButton* pWidget =
-      pUi->GetFirstChildByClass<CXFA_CheckButton>(XFA_Element::CheckButton);
-  pWidget->JSObject()->SetEnum(XFA_Attribute::Shape, XFA_AttributeEnum::Round,
-                               false);
-  return pField;
-}
-
-CXFA_Node* CXFA_FFWidgetHandler::CreateDatetimeEdit(CXFA_Node* pParent,
-                                                    CXFA_Node* pBefore) const {
-  CXFA_Node* pField = CreateField(XFA_Element::DateTimeEdit, pParent, pBefore);
-  CreateValueNode(XFA_Element::Date, pField);
-  return pField;
-}
-
-CXFA_Node* CXFA_FFWidgetHandler::CreateDecimalField(CXFA_Node* pParent,
-                                                    CXFA_Node* pBefore) const {
-  CXFA_Node* pField = CreateNumericField(pParent, pBefore);
-  CreateValueNode(XFA_Element::Decimal, pField);
-  return pField;
-}
-
-CXFA_Node* CXFA_FFWidgetHandler::CreateNumericField(CXFA_Node* pParent,
-                                                    CXFA_Node* pBefore) const {
-  return CreateField(XFA_Element::NumericEdit, pParent, pBefore);
-}
-
-CXFA_Node* CXFA_FFWidgetHandler::CreateSignature(CXFA_Node* pParent,
-                                                 CXFA_Node* pBefore) const {
-  return CreateField(XFA_Element::Signature, pParent, pBefore);
-}
-
-CXFA_Node* CXFA_FFWidgetHandler::CreateTextEdit(CXFA_Node* pParent,
-                                                CXFA_Node* pBefore) const {
-  return CreateField(XFA_Element::TextEdit, pParent, pBefore);
-}
-
-CXFA_Node* CXFA_FFWidgetHandler::CreateDropdownList(CXFA_Node* pParent,
-                                                    CXFA_Node* pBefore) const {
-  return CreateField(XFA_Element::ChoiceList, pParent, pBefore);
-}
-
-CXFA_Node* CXFA_FFWidgetHandler::CreateListBox(CXFA_Node* pParent,
-                                               CXFA_Node* pBefore) const {
-  CXFA_Node* pField = CreateDropdownList(pParent, pBefore);
-  CXFA_Node* pUi = pField->GetFirstChild();
-  CXFA_Node* pListBox = pUi->GetFirstChild();
-  pListBox->JSObject()->SetEnum(XFA_Attribute::Open, XFA_AttributeEnum::Always,
-                                false);
-  pListBox->JSObject()->SetEnum(XFA_Attribute::CommitOn,
-                                XFA_AttributeEnum::Exit, false);
-  return pField;
-}
-
-CXFA_Node* CXFA_FFWidgetHandler::CreateImageField(CXFA_Node* pParent,
-                                                  CXFA_Node* pBefore) const {
-  return CreateField(XFA_Element::ImageEdit, pParent, pBefore);
-}
-
-CXFA_Node* CXFA_FFWidgetHandler::CreatePasswordEdit(CXFA_Node* pParent,
-                                                    CXFA_Node* pBefore) const {
-  CXFA_Node* pField = CreateField(XFA_Element::PasswordEdit, pParent, pBefore);
-  CXFA_Node* pBind = CreateCopyNode(XFA_Element::Bind, pField);
-  pBind->JSObject()->SetEnum(XFA_Attribute::Match, XFA_AttributeEnum::None,
-                             false);
-  return pField;
-}
-
-CXFA_Node* CXFA_FFWidgetHandler::CreateField(XFA_Element eElement,
-                                             CXFA_Node* pParent,
-                                             CXFA_Node* pBefore) const {
-  CXFA_Node* pField = CreateFormItem(XFA_Element::Field, pParent, pBefore);
-  CreateCopyNode(eElement, CreateCopyNode(XFA_Element::Ui, pField));
-  CreateFontNode(pField);
-  return pField;
-}
-
-CXFA_Node* CXFA_FFWidgetHandler::CreateArc(CXFA_Node* pParent,
-                                           CXFA_Node* pBefore) const {
-  return CreateDraw(XFA_Element::Arc, pParent, pBefore);
-}
-
-CXFA_Node* CXFA_FFWidgetHandler::CreateRectangle(CXFA_Node* pParent,
-                                                 CXFA_Node* pBefore) const {
-  return CreateDraw(XFA_Element::Rectangle, pParent, pBefore);
-}
-
-CXFA_Node* CXFA_FFWidgetHandler::CreateImage(CXFA_Node* pParent,
-                                             CXFA_Node* pBefore) const {
-  CXFA_Node* pField = CreateDraw(XFA_Element::Image, pParent, pBefore);
-  CreateCopyNode(XFA_Element::ImageEdit,
-                 CreateCopyNode(XFA_Element::Ui, pField));
-  return pField;
-}
-
-CXFA_Node* CXFA_FFWidgetHandler::CreateLine(CXFA_Node* pParent,
-                                            CXFA_Node* pBefore) const {
-  return CreateDraw(XFA_Element::Line, pParent, pBefore);
-}
-
-CXFA_Node* CXFA_FFWidgetHandler::CreateText(CXFA_Node* pParent,
-                                            CXFA_Node* pBefore) const {
-  CXFA_Node* pField = CreateDraw(XFA_Element::Text, pParent, pBefore);
-  CreateCopyNode(XFA_Element::TextEdit,
-                 CreateCopyNode(XFA_Element::Ui, pField));
-  CreateFontNode(pField);
-  return pField;
-}
-
-CXFA_Node* CXFA_FFWidgetHandler::CreateDraw(XFA_Element eElement,
-                                            CXFA_Node* pParent,
-                                            CXFA_Node* pBefore) const {
-  CXFA_Node* pDraw = CreateFormItem(XFA_Element::Draw, pParent, pBefore);
-  CreateValueNode(eElement, pDraw);
-  return pDraw;
-}
-
-CXFA_Node* CXFA_FFWidgetHandler::CreateSubform(CXFA_Node* pParent,
-                                               CXFA_Node* pBefore) const {
-  return CreateFormItem(XFA_Element::Subform, pParent, pBefore);
-}
-
-CXFA_Node* CXFA_FFWidgetHandler::CreateFormItem(XFA_Element eElement,
-                                                CXFA_Node* pParent,
-                                                CXFA_Node* pBefore) const {
-  if (!pParent)
-    return nullptr;
-
-  CXFA_Node* pTemplateParent = pParent->GetTemplateNodeIfExists();
-  if (!pTemplateParent)
-    return nullptr;
-
-  CXFA_Node* pNewFormItem = pTemplateParent->CloneTemplateToForm(false);
-  if (pParent)
-    pParent->InsertChild(pNewFormItem, pBefore);
-  return pNewFormItem;
-}
-
-CXFA_Node* CXFA_FFWidgetHandler::CreateCopyNode(XFA_Element eElement,
-                                                CXFA_Node* pParent,
-                                                CXFA_Node* pBefore) const {
-  if (!pParent)
-    return nullptr;
-
-  CXFA_Node* pTemplateParent = pParent->GetTemplateNodeIfExists();
-  CXFA_Node* pNewNode =
-      CreateTemplateNode(eElement, pTemplateParent,
-                         pBefore ? pBefore->GetTemplateNodeIfExists() : nullptr)
-          ->Clone(false);
-  if (pParent)
-    pParent->InsertChild(pNewNode, pBefore);
-  return pNewNode;
-}
-
-CXFA_Node* CXFA_FFWidgetHandler::CreateTemplateNode(XFA_Element eElement,
-                                                    CXFA_Node* pParent,
-                                                    CXFA_Node* pBefore) const {
-  CXFA_Document* pXFADoc = GetXFADoc();
-  CXFA_Node* pNewTemplateNode =
-      pXFADoc->CreateNode(XFA_PacketType::Template, eElement);
-  if (pParent)
-    pParent->InsertChild(pNewTemplateNode, pBefore);
-  return pNewTemplateNode;
-}
-
-CXFA_Node* CXFA_FFWidgetHandler::CreateFontNode(CXFA_Node* pParent) const {
-  CXFA_Node* pFont = CreateCopyNode(XFA_Element::Font, pParent);
-  pFont->JSObject()->SetCData(XFA_Attribute::Typeface, L"Myriad Pro", false,
-                              false);
-  return pFont;
-}
-
-CXFA_Node* CXFA_FFWidgetHandler::CreateMarginNode(CXFA_Node* pParent,
-                                                  uint32_t dwFlags,
-                                                  float fInsets[4]) const {
-  CXFA_Node* pMargin = CreateCopyNode(XFA_Element::Margin, pParent);
-  if (dwFlags & 0x01)
-    pMargin->JSObject()->SetMeasure(XFA_Attribute::LeftInset,
-                                    CXFA_Measurement(fInsets[0], XFA_Unit::Pt),
-                                    false);
-  if (dwFlags & 0x02)
-    pMargin->JSObject()->SetMeasure(XFA_Attribute::TopInset,
-                                    CXFA_Measurement(fInsets[1], XFA_Unit::Pt),
-                                    false);
-  if (dwFlags & 0x04)
-    pMargin->JSObject()->SetMeasure(XFA_Attribute::RightInset,
-                                    CXFA_Measurement(fInsets[2], XFA_Unit::Pt),
-                                    false);
-  if (dwFlags & 0x08)
-    pMargin->JSObject()->SetMeasure(XFA_Attribute::BottomInset,
-                                    CXFA_Measurement(fInsets[3], XFA_Unit::Pt),
-                                    false);
-  return pMargin;
-}
-
-CXFA_Node* CXFA_FFWidgetHandler::CreateValueNode(XFA_Element eValue,
-                                                 CXFA_Node* pParent) const {
-  CXFA_Node* pValue = CreateCopyNode(XFA_Element::Value, pParent);
-  CreateCopyNode(eValue, pValue);
-  return pValue;
-}
-
-CXFA_Document* CXFA_FFWidgetHandler::GetObjFactory() const {
-  return GetXFADoc();
-}
-
-CXFA_Document* CXFA_FFWidgetHandler::GetXFADoc() const {
-  return m_pDocView->GetDoc()->GetXFADoc();
+  return pNode->ProcessEvent(m_pDocView.Get(),
+                             gs_EventActivity[pParam->m_eType], pParam);
 }
diff --git a/xfa/fxfa/cxfa_ffwidgethandler.h b/xfa/fxfa/cxfa_ffwidgethandler.h
index 1ef8854..172a8c6 100644
--- a/xfa/fxfa/cxfa_ffwidgethandler.h
+++ b/xfa/fxfa/cxfa_ffwidgethandler.h
@@ -7,8 +7,7 @@
 #ifndef XFA_FXFA_CXFA_FFWIDGETHANDLER_H_
 #define XFA_FXFA_CXFA_FFWIDGETHANDLER_H_
 
-#include <vector>
-
+#include "core/fxcrt/unowned_ptr.h"
 #include "xfa/fxfa/cxfa_eventparam.h"
 #include "xfa/fxfa/fxfa.h"
 #include "xfa/fxfa/parser/cxfa_document.h"
@@ -22,10 +21,6 @@
   explicit CXFA_FFWidgetHandler(CXFA_FFDocView* pDocView);
   ~CXFA_FFWidgetHandler();
 
-  CXFA_FFWidget* CreateWidget(CXFA_FFWidget* hParent,
-                              XFA_WIDGETTYPE eType,
-                              CXFA_FFWidget* hBefore = nullptr);
-
   bool OnMouseEnter(CXFA_FFWidget* hWidget);
   bool OnMouseExit(CXFA_FFWidget* hWidget);
   bool OnLButtonDown(CXFA_FFWidget* hWidget,
@@ -54,70 +49,29 @@
                        uint32_t dwFlags,
                        const CFX_PointF& point);
 
+  WideString GetText(CXFA_FFWidget* widget);
   WideString GetSelectedText(CXFA_FFWidget* widget);
   void PasteText(CXFA_FFWidget* widget, const WideString& text);
 
+  bool CanUndo(CXFA_FFWidget* widget);
+  bool CanRedo(CXFA_FFWidget* widget);
+  bool Undo(CXFA_FFWidget* widget);
+  bool Redo(CXFA_FFWidget* widget);
+
   bool OnKeyDown(CXFA_FFWidget* hWidget, uint32_t dwKeyCode, uint32_t dwFlags);
   bool OnKeyUp(CXFA_FFWidget* hWidget, uint32_t dwKeyCode, uint32_t dwFlags);
   bool OnChar(CXFA_FFWidget* hWidget, uint32_t dwChar, uint32_t dwFlags);
-  FWL_WidgetHit OnHitTest(CXFA_FFWidget* hWidget, const CFX_PointF& point);
   bool OnSetCursor(CXFA_FFWidget* hWidget, const CFX_PointF& point);
+  FWL_WidgetHit HitTest(CXFA_FFWidget* pWidget, const CFX_PointF& point);
   void RenderWidget(CXFA_FFWidget* hWidget,
                     CXFA_Graphics* pGS,
                     const CFX_Matrix& matrix,
                     bool bHighlight);
-  bool HasEvent(CXFA_WidgetAcc* pWidgetAcc, XFA_EVENTTYPE eEventType);
-  int32_t ProcessEvent(CXFA_WidgetAcc* pWidgetAcc, CXFA_EventParam* pParam);
+  bool HasEvent(CXFA_Node* pNode, XFA_EVENTTYPE eEventType);
+  XFA_EventError ProcessEvent(CXFA_Node* pNode, CXFA_EventParam* pParam);
 
  private:
-  CXFA_Node* CreateWidgetFormItem(XFA_WIDGETTYPE eType,
-                                  CXFA_Node* pParent,
-                                  CXFA_Node* pBefore) const;
-
-  CXFA_Node* CreatePushButton(CXFA_Node* pParent, CXFA_Node* pBefore) const;
-  CXFA_Node* CreateCheckButton(CXFA_Node* pParent, CXFA_Node* pBefore) const;
-  CXFA_Node* CreateExclGroup(CXFA_Node* pParent, CXFA_Node* pBefore) const;
-  CXFA_Node* CreateRadioButton(CXFA_Node* pParent, CXFA_Node* pBefore) const;
-  CXFA_Node* CreateDatetimeEdit(CXFA_Node* pParent, CXFA_Node* pBefore) const;
-  CXFA_Node* CreateDecimalField(CXFA_Node* pParent, CXFA_Node* pBefore) const;
-  CXFA_Node* CreateNumericField(CXFA_Node* pParent, CXFA_Node* pBefore) const;
-  CXFA_Node* CreateSignature(CXFA_Node* pParent, CXFA_Node* pBefore) const;
-  CXFA_Node* CreateTextEdit(CXFA_Node* pParent, CXFA_Node* pBefore) const;
-  CXFA_Node* CreateDropdownList(CXFA_Node* pParent, CXFA_Node* pBefore) const;
-  CXFA_Node* CreateListBox(CXFA_Node* pParent, CXFA_Node* pBefore) const;
-  CXFA_Node* CreateImageField(CXFA_Node* pParent, CXFA_Node* pBefore) const;
-  CXFA_Node* CreatePasswordEdit(CXFA_Node* pParent, CXFA_Node* pBefore) const;
-  CXFA_Node* CreateField(XFA_Element eElement,
-                         CXFA_Node* pParent,
-                         CXFA_Node* pBefore) const;
-  CXFA_Node* CreateArc(CXFA_Node* pParent, CXFA_Node* pBefore) const;
-  CXFA_Node* CreateRectangle(CXFA_Node* pParent, CXFA_Node* pBefore) const;
-  CXFA_Node* CreateImage(CXFA_Node* pParent, CXFA_Node* pBefore) const;
-  CXFA_Node* CreateLine(CXFA_Node* pParent, CXFA_Node* pBefore) const;
-  CXFA_Node* CreateText(CXFA_Node* pParent, CXFA_Node* pBefore) const;
-  CXFA_Node* CreateDraw(XFA_Element eElement,
-                        CXFA_Node* pParent,
-                        CXFA_Node* pBefore) const;
-
-  CXFA_Node* CreateSubform(CXFA_Node* pParent, CXFA_Node* pBefore) const;
-  CXFA_Node* CreateFormItem(XFA_Element eElement,
-                            CXFA_Node* pParent,
-                            CXFA_Node* pBefore) const;
-  CXFA_Node* CreateCopyNode(XFA_Element eElement,
-                            CXFA_Node* pParent,
-                            CXFA_Node* pBefore = nullptr) const;
-  CXFA_Node* CreateTemplateNode(XFA_Element eElement,
-                                CXFA_Node* pParent,
-                                CXFA_Node* pBefore) const;
-  CXFA_Node* CreateFontNode(CXFA_Node* pParent) const;
-  CXFA_Node* CreateMarginNode(CXFA_Node* pParent,
-                              uint32_t dwFlags,
-                              float fInsets[4]) const;
-  CXFA_Node* CreateValueNode(XFA_Element eValue, CXFA_Node* pParent) const;
-  CXFA_Document* GetObjFactory() const;
-  CXFA_Document* GetXFADoc() const;
-
-  CXFA_FFDocView* m_pDocView;
+  UnownedPtr<CXFA_FFDocView> m_pDocView;
 };
 
 #endif  //  XFA_FXFA_CXFA_FFWIDGETHANDLER_H_
diff --git a/xfa/fxfa/cxfa_fontmgr.cpp b/xfa/fxfa/cxfa_fontmgr.cpp
index 0956806..7259f6c 100644
--- a/xfa/fxfa/cxfa_fontmgr.cpp
+++ b/xfa/fxfa/cxfa_fontmgr.cpp
@@ -10,23 +10,23 @@
 #include <memory>
 #include <utility>
 
-#include "core/fpdfapi/font/cpdf_font.h"
 #include "core/fpdfapi/parser/cpdf_dictionary.h"
 #include "core/fpdfapi/parser/cpdf_document.h"
-#include "third_party/base/ptr_util.h"
+#include "core/fxge/cfx_fontmgr.h"
+#include "core/fxge/cfx_gemodule.h"
+#include "xfa/fgas/font/cfgas_defaultfontmanager.h"
 #include "xfa/fgas/font/cfgas_gefont.h"
 #include "xfa/fgas/font/fgas_fontutils.h"
 #include "xfa/fxfa/cxfa_ffapp.h"
 #include "xfa/fxfa/cxfa_ffdoc.h"
 
-CXFA_FontMgr::CXFA_FontMgr() {}
+CXFA_FontMgr::CXFA_FontMgr() = default;
 
-CXFA_FontMgr::~CXFA_FontMgr() {}
+CXFA_FontMgr::~CXFA_FontMgr() = default;
 
-RetainPtr<CFGAS_GEFont> CXFA_FontMgr::GetFont(
-    CXFA_FFDoc* hDoc,
-    const WideStringView& wsFontFamily,
-    uint32_t dwFontStyles) {
+RetainPtr<CFGAS_GEFont> CXFA_FontMgr::GetFont(CXFA_FFDoc* hDoc,
+                                              WideStringView wsFontFamily,
+                                              uint32_t dwFontStyles) {
   uint32_t dwHash = FX_HashCode_GetW(wsFontFamily, false);
   ByteString bsKey = ByteString::Format("%u%u%u", dwHash, dwFontStyles, 0xFFFF);
   auto iter = m_FontMap.find(bsKey);
@@ -34,43 +34,33 @@
     return iter->second;
 
   WideString wsEnglishName = FGAS_FontNameToEnglishName(wsFontFamily);
-
   CFGAS_PDFFontMgr* pMgr = hDoc->GetPDFFontMgr();
-  CPDF_Font* pPDFFont = nullptr;
   RetainPtr<CFGAS_GEFont> pFont;
   if (pMgr) {
-    pFont = pMgr->GetFont(wsEnglishName.AsStringView(), dwFontStyles, &pPDFFont,
-                          true);
+    pFont = pMgr->GetFont(wsEnglishName.AsStringView(), dwFontStyles, true);
     if (pFont)
       return pFont;
   }
-  if (!pFont && m_pDefFontMgr)
-    pFont = m_pDefFontMgr->GetFont(hDoc->GetApp()->GetFDEFontMgr(),
-                                   wsFontFamily, dwFontStyles);
-
+  if (!pFont) {
+    pFont = CFGAS_DefaultFontManager::GetFont(hDoc->GetApp()->GetFDEFontMgr(),
+                                              wsFontFamily, dwFontStyles);
+  }
   if (!pFont && pMgr) {
-    pPDFFont = nullptr;
-    pFont = pMgr->GetFont(wsEnglishName.AsStringView(), dwFontStyles, &pPDFFont,
-                          false);
+    pFont = pMgr->GetFont(wsEnglishName.AsStringView(), dwFontStyles, false);
     if (pFont)
       return pFont;
   }
-  if (!pFont && m_pDefFontMgr) {
-    pFont = m_pDefFontMgr->GetDefaultFont(hDoc->GetApp()->GetFDEFontMgr(),
-                                          wsFontFamily, dwFontStyles);
+  if (!pFont) {
+    pFont = CFGAS_DefaultFontManager::GetDefaultFont(
+        hDoc->GetApp()->GetFDEFontMgr(), wsFontFamily, dwFontStyles);
   }
-
-  if (pFont) {
-    if (pPDFFont) {
-      pMgr->SetFont(pFont, pPDFFont);
-      pFont->SetFontProvider(pMgr);
-    }
+  if (!pFont) {
+    pFont = CFGAS_GEFont::LoadStockFont(
+        hDoc->GetPDFDoc(), hDoc->GetApp()->GetFDEFontMgr(),
+        ByteString::Format("%ls", WideString(wsFontFamily).c_str()));
+  }
+  if (pFont)
     m_FontMap[bsKey] = pFont;
-  }
-  return pFont;
-}
 
-void CXFA_FontMgr::SetDefFontMgr(
-    std::unique_ptr<CFGAS_DefaultFontManager> pFontMgr) {
-  m_pDefFontMgr = std::move(pFontMgr);
+  return pFont;
 }
diff --git a/xfa/fxfa/cxfa_fontmgr.h b/xfa/fxfa/cxfa_fontmgr.h
index a940faf..2ad45dc 100644
--- a/xfa/fxfa/cxfa_fontmgr.h
+++ b/xfa/fxfa/cxfa_fontmgr.h
@@ -8,18 +8,11 @@
 #define XFA_FXFA_CXFA_FONTMGR_H_
 
 #include <map>
-#include <memory>
-#include <vector>
 
-#include "core/fxcrt/fx_extension.h"
-#include "core/fxcrt/fx_system.h"
-#include "core/fxcrt/retain_ptr.h"
-#include "xfa/fgas/font/cfgas_defaultfontmanager.h"
-#include "xfa/fgas/font/cfgas_fontmgr.h"
-#include "xfa/fgas/font/cfgas_pdffontmgr.h"
-#include "xfa/fxfa/fxfa.h"
+#include "core/fxcrt/fx_string.h"
 
-class CPDF_Font;
+class CFGAS_GEFont;
+class CXFA_FFDoc;
 
 class CXFA_FontMgr {
  public:
@@ -27,12 +20,10 @@
   ~CXFA_FontMgr();
 
   RetainPtr<CFGAS_GEFont> GetFont(CXFA_FFDoc* hDoc,
-                                  const WideStringView& wsFontFamily,
+                                  WideStringView wsFontFamily,
                                   uint32_t dwFontStyles);
-  void SetDefFontMgr(std::unique_ptr<CFGAS_DefaultFontManager> pFontMgr);
 
  private:
-  std::unique_ptr<CFGAS_DefaultFontManager> m_pDefFontMgr;
   std::map<ByteString, RetainPtr<CFGAS_GEFont>> m_FontMap;
 };
 
diff --git a/xfa/fxfa/cxfa_fwladapterwidgetmgr.cpp b/xfa/fxfa/cxfa_fwladapterwidgetmgr.cpp
index 6fdd553..a67bf08 100644
--- a/xfa/fxfa/cxfa_fwladapterwidgetmgr.cpp
+++ b/xfa/fxfa/cxfa_fwladapterwidgetmgr.cpp
@@ -17,22 +17,22 @@
   if (!pWidget)
     return;
 
-  CXFA_FFWidget* pFFWidget = pWidget->GetLayoutItem();
+  auto* pFFWidget = static_cast<CXFA_FFWidget*>(pWidget->GetAdapterIface());
   if (!pFFWidget)
     return;
 
-  pFFWidget->AddInvalidateRect();
+  pFFWidget->InvalidateRect();
 }
 
 bool CXFA_FWLAdapterWidgetMgr::GetPopupPos(CFWL_Widget* pWidget,
                                            float fMinHeight,
                                            float fMaxHeight,
                                            const CFX_RectF& rtAnchor,
-                                           CFX_RectF& rtPopup) {
-  CXFA_FFWidget* pFFWidget = pWidget->GetLayoutItem();
+                                           CFX_RectF* pPopupRect) {
+  auto* pFFWidget = static_cast<CXFA_FFWidget*>(pWidget->GetAdapterIface());
   CFX_RectF rtRotateAnchor =
       pFFWidget->GetRotateMatrix().TransformRect(rtAnchor);
   pFFWidget->GetDoc()->GetDocEnvironment()->GetPopupPos(
-      pFFWidget, fMinHeight, fMaxHeight, rtRotateAnchor, rtPopup);
+      pFFWidget, fMinHeight, fMaxHeight, rtRotateAnchor, pPopupRect);
   return true;
 }
diff --git a/xfa/fxfa/cxfa_fwladapterwidgetmgr.h b/xfa/fxfa/cxfa_fwladapterwidgetmgr.h
index f5c4ce1..4a50c28 100644
--- a/xfa/fxfa/cxfa_fwladapterwidgetmgr.h
+++ b/xfa/fxfa/cxfa_fwladapterwidgetmgr.h
@@ -9,20 +9,21 @@
 
 #include "core/fxcrt/fx_coordinates.h"
 #include "core/fxcrt/fx_system.h"
+#include "xfa/fwl/cfwl_widgetmgr.h"
 
 class CFWL_Widget;
 
-class CXFA_FWLAdapterWidgetMgr {
+class CXFA_FWLAdapterWidgetMgr : public CFWL_WidgetMgr::AdapterIface {
  public:
   CXFA_FWLAdapterWidgetMgr();
-  ~CXFA_FWLAdapterWidgetMgr();
+  ~CXFA_FWLAdapterWidgetMgr() override;
 
-  void RepaintWidget(CFWL_Widget* pWidget);
+  void RepaintWidget(CFWL_Widget* pWidget) override;
   bool GetPopupPos(CFWL_Widget* pWidget,
                    float fMinHeight,
                    float fMaxHeight,
                    const CFX_RectF& rtAnchor,
-                   CFX_RectF& rtPopup);
+                   CFX_RectF* pPopupRect) override;
 };
 
 #endif  // XFA_FXFA_CXFA_FWLADAPTERWIDGETMGR_H_
diff --git a/xfa/fxfa/cxfa_fwltheme.cpp b/xfa/fxfa/cxfa_fwltheme.cpp
index 9209682..4c2c8da 100644
--- a/xfa/fxfa/cxfa_fwltheme.cpp
+++ b/xfa/fxfa/cxfa_fwltheme.cpp
@@ -7,6 +7,7 @@
 #include "xfa/fxfa/cxfa_fwltheme.h"
 
 #include "core/fxcrt/fx_codepage.h"
+#include "third_party/base/ptr_util.h"
 #include "xfa/fde/cfde_textout.h"
 #include "xfa/fgas/font/cfgas_gefont.h"
 #include "xfa/fwl/cfwl_barcode.h"
@@ -22,6 +23,7 @@
 #include "xfa/fwl/cfwl_scrollbar.h"
 #include "xfa/fwl/cfwl_themebackground.h"
 #include "xfa/fwl/cfwl_themetext.h"
+#include "xfa/fwl/theme/cfwl_widgettp.h"
 #include "xfa/fxfa/cxfa_ffapp.h"
 #include "xfa/fxfa/cxfa_ffwidget.h"
 #include "xfa/fxfa/parser/cxfa_para.h"
@@ -35,15 +37,14 @@
 
 const float kLineHeight = 12.0f;
 
-}  // namespace
-
 CXFA_FFWidget* XFA_ThemeGetOuterWidget(CFWL_Widget* pWidget) {
-  CFWL_Widget* pOuter = pWidget;
-  while (pOuter && pOuter->GetOuter())
-    pOuter = pOuter->GetOuter();
-  return pOuter ? pOuter->GetLayoutItem() : nullptr;
+  CFWL_Widget* pOuter = pWidget ? pWidget->GetOutmost() : nullptr;
+  return pOuter ? static_cast<CXFA_FFWidget*>(pOuter->GetAdapterIface())
+                : nullptr;
 }
 
+}  // namespace
+
 CXFA_FWLTheme::CXFA_FWLTheme(CXFA_FFApp* pApp)
     : m_pCheckBoxTP(pdfium::MakeUnique<CFWL_CheckBoxTP>()),
       m_pListBoxTP(pdfium::MakeUnique<CFWL_ListBoxTP>()),
@@ -57,108 +58,105 @@
       m_pCaretTP(pdfium::MakeUnique<CFWL_CaretTP>()),
       m_pBarcodeTP(pdfium::MakeUnique<CFWL_BarcodeTP>()),
       m_pTextOut(pdfium::MakeUnique<CFDE_TextOut>()),
-      m_pCalendarFont(nullptr),
       m_pApp(pApp) {
-  m_Rect.Reset();
+}
 
+bool CXFA_FWLTheme::LoadCalendarFont(CXFA_FFDoc* doc) {
   for (size_t i = 0; !m_pCalendarFont && i < FX_ArraySize(g_FWLTheme_CalFonts);
        ++i) {
-    m_pCalendarFont = CFGAS_GEFont::LoadFont(g_FWLTheme_CalFonts[i], 0, 0,
-                                             m_pApp->GetFDEFontMgr());
-  }
-  if (!m_pCalendarFont) {
-    m_pCalendarFont = m_pApp->GetFDEFontMgr()->GetFontByCodePage(
-        FX_CODEPAGE_MSWin_WesternEuropean, 0, nullptr);
+    m_pCalendarFont =
+        m_pApp->GetXFAFontMgr()->GetFont(doc, g_FWLTheme_CalFonts[i], 0);
   }
 
-  ASSERT(m_pCalendarFont);
+  if (!m_pCalendarFont) {
+    CFGAS_FontMgr* font_mgr = m_pApp->GetFDEFontMgr();
+    if (font_mgr) {
+      m_pCalendarFont = font_mgr->GetFontByCodePage(
+          FX_CODEPAGE_MSWin_WesternEuropean, 0, nullptr);
+    }
+  }
+
+  return m_pCalendarFont != nullptr;
 }
 
 CXFA_FWLTheme::~CXFA_FWLTheme() {
   m_pTextOut.reset();
-  FWLTHEME_Release();
+  CFWL_FontManager::DestroyInstance();
 }
 
-void CXFA_FWLTheme::DrawBackground(CFWL_ThemeBackground* pParams) {
-  GetTheme(pParams->m_pWidget)->DrawBackground(pParams);
+void CXFA_FWLTheme::DrawBackground(const CFWL_ThemeBackground& pParams) {
+  GetTheme(pParams.m_pWidget)->DrawBackground(pParams);
 }
 
-void CXFA_FWLTheme::DrawText(CFWL_ThemeText* pParams) {
-  if (pParams->m_wsText.IsEmpty())
+void CXFA_FWLTheme::DrawText(const CFWL_ThemeText& pParams) {
+  if (pParams.m_wsText.IsEmpty())
     return;
 
-  if (pParams->m_pWidget->GetClassID() == FWL_Type::MonthCalendar) {
-    CXFA_FFWidget* pWidget = XFA_ThemeGetOuterWidget(pParams->m_pWidget);
+  if (pParams.m_pWidget->GetClassID() == FWL_Type::MonthCalendar) {
+    CXFA_FFWidget* pWidget = XFA_ThemeGetOuterWidget(pParams.m_pWidget);
     if (!pWidget)
       return;
 
-    m_pTextOut->SetStyles(pParams->m_dwTTOStyles);
-    m_pTextOut->SetAlignment(pParams->m_iTTOAlign);
+    m_pTextOut->SetStyles(pParams.m_dwTTOStyles);
+    m_pTextOut->SetAlignment(pParams.m_iTTOAlign);
     m_pTextOut->SetFont(m_pCalendarFont);
     m_pTextOut->SetFontSize(FWLTHEME_CAPACITY_FontSize);
     m_pTextOut->SetTextColor(FWLTHEME_CAPACITY_TextColor);
-    if ((pParams->m_iPart == CFWL_Part::DatesIn) &&
-        !(pParams->m_dwStates & FWL_ITEMSTATE_MCD_Flag) &&
-        (pParams->m_dwStates &
+    if ((pParams.m_iPart == CFWL_Part::DatesIn) &&
+        !(pParams.m_dwStates & FWL_ITEMSTATE_MCD_Flag) &&
+        (pParams.m_dwStates &
          (CFWL_PartState_Hovered | CFWL_PartState_Selected))) {
-      m_pTextOut->SetTextColor(0xFFFFFFFF);
+      m_pTextOut->SetTextColor(0xFF888888);
     }
-    if (pParams->m_iPart == CFWL_Part::Caption)
+    if (pParams.m_iPart == CFWL_Part::Caption)
       m_pTextOut->SetTextColor(ArgbEncode(0xff, 0, 153, 255));
 
-    CXFA_Graphics* pGraphics = pParams->m_pGraphics;
+    CXFA_Graphics* pGraphics = pParams.m_pGraphics;
     CFX_RenderDevice* pRenderDevice = pGraphics->GetRenderDevice();
-    if (!pRenderDevice)
-      return;
-
-    CFX_Matrix mtPart = pParams->m_matrix;
+    CFX_Matrix mtPart = pParams.m_matrix;
     const CFX_Matrix* pMatrix = pGraphics->GetMatrix();
     if (pMatrix)
       mtPart.Concat(*pMatrix);
 
     m_pTextOut->SetMatrix(mtPart);
-    m_pTextOut->DrawLogicText(pRenderDevice, pParams->m_wsText.AsStringView(),
-                              pParams->m_rtPart);
+    m_pTextOut->DrawLogicText(pRenderDevice, pParams.m_wsText.AsStringView(),
+                              pParams.m_rtPart);
     return;
   }
-  CXFA_FFWidget* pWidget = XFA_ThemeGetOuterWidget(pParams->m_pWidget);
+  CXFA_FFWidget* pWidget = XFA_ThemeGetOuterWidget(pParams.m_pWidget);
   if (!pWidget)
     return;
 
   CXFA_Node* pNode = pWidget->GetNode();
-  CXFA_Graphics* pGraphics = pParams->m_pGraphics;
+  CXFA_Graphics* pGraphics = pParams.m_pGraphics;
   CFX_RenderDevice* pRenderDevice = pGraphics->GetRenderDevice();
-  if (!pRenderDevice)
-    return;
-
-  m_pTextOut->SetStyles(pParams->m_dwTTOStyles);
-  m_pTextOut->SetAlignment(pParams->m_iTTOAlign);
-  m_pTextOut->SetFont(pNode->GetWidgetAcc()->GetFDEFont(pWidget->GetDoc()));
+  m_pTextOut->SetStyles(pParams.m_dwTTOStyles);
+  m_pTextOut->SetAlignment(pParams.m_iTTOAlign);
+  m_pTextOut->SetFont(pNode->GetFDEFont(pWidget->GetDoc()));
   m_pTextOut->SetFontSize(pNode->GetFontSize());
   m_pTextOut->SetTextColor(pNode->GetTextColor());
-  CFX_Matrix mtPart = pParams->m_matrix;
+  CFX_Matrix mtPart = pParams.m_matrix;
   const CFX_Matrix* pMatrix = pGraphics->GetMatrix();
   if (pMatrix)
     mtPart.Concat(*pMatrix);
 
   m_pTextOut->SetMatrix(mtPart);
-  m_pTextOut->DrawLogicText(pRenderDevice, pParams->m_wsText.AsStringView(),
-                            pParams->m_rtPart);
+  m_pTextOut->DrawLogicText(pRenderDevice, pParams.m_wsText.AsStringView(),
+                            pParams.m_rtPart);
 }
 
-CFX_RectF CXFA_FWLTheme::GetUIMargin(CFWL_ThemePart* pThemePart) const {
-  CFX_RectF rect;
-  CXFA_FFWidget* pWidget = XFA_ThemeGetOuterWidget(pThemePart->m_pWidget);
+CFX_RectF CXFA_FWLTheme::GetUIMargin(const CFWL_ThemePart& pThemePart) const {
+  CXFA_FFWidget* pWidget = XFA_ThemeGetOuterWidget(pThemePart.m_pWidget);
   if (!pWidget)
-    return rect;
+    return CFX_RectF();
 
-  CXFA_LayoutItem* pItem = pWidget;
-  CXFA_WidgetAcc* pWidgetAcc = pWidget->GetNode()->GetWidgetAcc();
-  rect = pWidgetAcc->GetUIMargin();
-  CXFA_Para* para = pWidgetAcc->GetNode()->GetParaIfExists();
+  CXFA_ContentLayoutItem* pItem = pWidget->GetLayoutItem();
+  CXFA_Node* pNode = pWidget->GetNode();
+  CFX_RectF rect = pNode->GetUIMargin();
+  CXFA_Para* para = pNode->GetParaIfExists();
   if (para) {
     rect.left += para->GetMarginLeft();
-    if (pWidgetAcc->IsMultiLine())
+    if (pNode->IsMultiLine())
       rect.width += para->GetMarginRight();
   }
   if (!pItem->GetPrev()) {
@@ -181,21 +179,21 @@
   return 1.0f;
 }
 
-float CXFA_FWLTheme::GetFontSize(CFWL_ThemePart* pThemePart) const {
-  if (CXFA_FFWidget* pWidget = XFA_ThemeGetOuterWidget(pThemePart->m_pWidget))
+float CXFA_FWLTheme::GetFontSize(const CFWL_ThemePart& pThemePart) const {
+  if (CXFA_FFWidget* pWidget = XFA_ThemeGetOuterWidget(pThemePart.m_pWidget))
     return pWidget->GetNode()->GetFontSize();
   return FWLTHEME_CAPACITY_FontSize;
 }
 
 RetainPtr<CFGAS_GEFont> CXFA_FWLTheme::GetFont(
-    CFWL_ThemePart* pThemePart) const {
-  if (CXFA_FFWidget* pWidget = XFA_ThemeGetOuterWidget(pThemePart->m_pWidget))
-    return pWidget->GetNode()->GetWidgetAcc()->GetFDEFont(pWidget->GetDoc());
-  return GetTheme(pThemePart->m_pWidget)->GetFont();
+    const CFWL_ThemePart& pThemePart) const {
+  if (CXFA_FFWidget* pWidget = XFA_ThemeGetOuterWidget(pThemePart.m_pWidget))
+    return pWidget->GetNode()->GetFDEFont(pWidget->GetDoc());
+  return GetTheme(pThemePart.m_pWidget)->GetFont();
 }
 
-float CXFA_FWLTheme::GetLineHeight(CFWL_ThemePart* pThemePart) const {
-  if (CXFA_FFWidget* pWidget = XFA_ThemeGetOuterWidget(pThemePart->m_pWidget))
+float CXFA_FWLTheme::GetLineHeight(const CFWL_ThemePart& pThemePart) const {
+  if (CXFA_FFWidget* pWidget = XFA_ThemeGetOuterWidget(pThemePart.m_pWidget))
     return pWidget->GetNode()->GetLineHeight();
   return kLineHeight;
 }
@@ -204,15 +202,17 @@
   return 9.0f;
 }
 
-FX_COLORREF CXFA_FWLTheme::GetTextColor(CFWL_ThemePart* pThemePart) const {
-  if (CXFA_FFWidget* pWidget = XFA_ThemeGetOuterWidget(pThemePart->m_pWidget))
+FX_COLORREF CXFA_FWLTheme::GetTextColor(
+    const CFWL_ThemePart& pThemePart) const {
+  if (CXFA_FFWidget* pWidget = XFA_ThemeGetOuterWidget(pThemePart.m_pWidget))
     return pWidget->GetNode()->GetTextColor();
   return FWLTHEME_CAPACITY_TextColor;
 }
 
-CFX_SizeF CXFA_FWLTheme::GetSpaceAboveBelow(CFWL_ThemePart* pThemePart) const {
+CFX_SizeF CXFA_FWLTheme::GetSpaceAboveBelow(
+    const CFWL_ThemePart& pThemePart) const {
   CFX_SizeF sizeAboveBelow;
-  if (CXFA_FFWidget* pWidget = XFA_ThemeGetOuterWidget(pThemePart->m_pWidget)) {
+  if (CXFA_FFWidget* pWidget = XFA_ThemeGetOuterWidget(pThemePart.m_pWidget)) {
     CXFA_Para* para = pWidget->GetNode()->GetParaIfExists();
     if (para) {
       sizeAboveBelow.width = para->GetSpaceAbove();
@@ -222,34 +222,32 @@
   return sizeAboveBelow;
 }
 
-void CXFA_FWLTheme::CalcTextRect(CFWL_ThemeText* pParams, CFX_RectF& rect) {
-  if (pParams->m_pWidget->GetClassID() == FWL_Type::MonthCalendar) {
-    CXFA_FFWidget* pWidget = XFA_ThemeGetOuterWidget(pParams->m_pWidget);
-    if (!pWidget || !pParams || !m_pTextOut)
-      return;
+void CXFA_FWLTheme::CalcTextRect(const CFWL_ThemeText& pParams,
+                                 CFX_RectF* pRect) {
+  if (!m_pTextOut)
+    return;
 
-    m_pTextOut->SetFont(m_pCalendarFont);
-    m_pTextOut->SetFontSize(FWLTHEME_CAPACITY_FontSize);
-    m_pTextOut->SetTextColor(FWLTHEME_CAPACITY_TextColor);
-    m_pTextOut->SetAlignment(pParams->m_iTTOAlign);
-    m_pTextOut->SetStyles(pParams->m_dwTTOStyles);
-    m_pTextOut->CalcLogicSize(pParams->m_wsText, rect);
-  }
-
-  CXFA_FFWidget* pWidget = XFA_ThemeGetOuterWidget(pParams->m_pWidget);
+  CXFA_FFWidget* pWidget = XFA_ThemeGetOuterWidget(pParams.m_pWidget);
   if (!pWidget)
     return;
 
+  if (pParams.m_pWidget->GetClassID() == FWL_Type::MonthCalendar) {
+    m_pTextOut->SetFont(m_pCalendarFont);
+    m_pTextOut->SetFontSize(FWLTHEME_CAPACITY_FontSize);
+    m_pTextOut->SetTextColor(FWLTHEME_CAPACITY_TextColor);
+    m_pTextOut->SetAlignment(pParams.m_iTTOAlign);
+    m_pTextOut->SetStyles(pParams.m_dwTTOStyles);
+    m_pTextOut->CalcLogicSize(pParams.m_wsText.AsStringView(), pRect);
+    return;
+  }
+
   CXFA_Node* pNode = pWidget->GetNode();
-  m_pTextOut->SetFont(pNode->GetWidgetAcc()->GetFDEFont(pWidget->GetDoc()));
+  m_pTextOut->SetFont(pNode->GetFDEFont(pWidget->GetDoc()));
   m_pTextOut->SetFontSize(pNode->GetFontSize());
   m_pTextOut->SetTextColor(pNode->GetTextColor());
-  if (!pParams)
-    return;
-
-  m_pTextOut->SetAlignment(pParams->m_iTTOAlign);
-  m_pTextOut->SetStyles(pParams->m_dwTTOStyles);
-  m_pTextOut->CalcLogicSize(pParams->m_wsText, rect);
+  m_pTextOut->SetAlignment(pParams.m_iTTOAlign);
+  m_pTextOut->SetStyles(pParams.m_dwTTOStyles);
+  m_pTextOut->CalcLogicSize(pParams.m_wsText.AsStringView(), pRect);
 }
 
 CFWL_WidgetTP* CXFA_FWLTheme::GetTheme(CFWL_Widget* pWidget) const {
diff --git a/xfa/fxfa/cxfa_fwltheme.h b/xfa/fxfa/cxfa_fwltheme.h
index bdab7cf..11f2584 100644
--- a/xfa/fxfa/cxfa_fwltheme.h
+++ b/xfa/fxfa/cxfa_fwltheme.h
@@ -29,19 +29,22 @@
   explicit CXFA_FWLTheme(CXFA_FFApp* pApp);
   ~CXFA_FWLTheme() override;
 
+  bool LoadCalendarFont(CXFA_FFDoc* doc);
+
   // IFWL_ThemeProvider:
-  void DrawBackground(CFWL_ThemeBackground* pParams) override;
-  void DrawText(CFWL_ThemeText* pParams) override;
-  void CalcTextRect(CFWL_ThemeText* pParams, CFX_RectF& rect) override;
+  void DrawBackground(const CFWL_ThemeBackground& pParams) override;
+  void DrawText(const CFWL_ThemeText& pParams) override;
+  void CalcTextRect(const CFWL_ThemeText& pParams, CFX_RectF* pRect) override;
   float GetCXBorderSize() const override;
   float GetCYBorderSize() const override;
-  CFX_RectF GetUIMargin(CFWL_ThemePart* pThemePart) const override;
-  float GetFontSize(CFWL_ThemePart* pThemePart) const override;
-  RetainPtr<CFGAS_GEFont> GetFont(CFWL_ThemePart* pThemePart) const override;
-  float GetLineHeight(CFWL_ThemePart* pThemePart) const override;
+  CFX_RectF GetUIMargin(const CFWL_ThemePart& pThemePart) const override;
+  float GetFontSize(const CFWL_ThemePart& pThemePart) const override;
+  RetainPtr<CFGAS_GEFont> GetFont(
+      const CFWL_ThemePart& pThemePart) const override;
+  float GetLineHeight(const CFWL_ThemePart& pThemePart) const override;
   float GetScrollBarWidth() const override;
-  FX_COLORREF GetTextColor(CFWL_ThemePart* pThemePart) const override;
-  CFX_SizeF GetSpaceAboveBelow(CFWL_ThemePart* pThemePart) const override;
+  FX_COLORREF GetTextColor(const CFWL_ThemePart& pThemePart) const override;
+  CFX_SizeF GetSpaceAboveBelow(const CFWL_ThemePart& pThemePart) const override;
 
  private:
   CFWL_WidgetTP* GetTheme(CFWL_Widget* pWidget) const;
@@ -64,6 +67,4 @@
   CFX_RectF m_Rect;
 };
 
-CXFA_FFWidget* XFA_ThemeGetOuterWidget(CFWL_Widget* pWidget);
-
 #endif  // XFA_FXFA_CXFA_FWLTHEME_H_
diff --git a/xfa/fxfa/cxfa_imagerenderer.cpp b/xfa/fxfa/cxfa_imagerenderer.cpp
index f6cb5e9..d3b66c8 100644
--- a/xfa/fxfa/cxfa_imagerenderer.cpp
+++ b/xfa/fxfa/cxfa_imagerenderer.cpp
@@ -7,25 +7,24 @@
 #include "xfa/fxfa/cxfa_imagerenderer.h"
 
 #include "core/fxge/cfx_renderdevice.h"
-#include "core/fxge/dib/cfx_dibsource.h"
+#include "core/fxge/dib/cfx_dibbase.h"
+#include "core/fxge/dib/cfx_dibitmap.h"
 #include "core/fxge/dib/cfx_imagerenderer.h"
 #include "core/fxge/dib/cfx_imagetransformer.h"
 #include "third_party/base/ptr_util.h"
 
-CXFA_ImageRenderer::CXFA_ImageRenderer(
-    CFX_RenderDevice* pDevice,
-    const RetainPtr<CFX_DIBSource>& pDIBSource,
-    const CFX_Matrix* pImage2Device)
-    : m_pDevice(pDevice),
-      m_ImageMatrix(*pImage2Device),
-      m_pDIBSource(pDIBSource) {}
+CXFA_ImageRenderer::CXFA_ImageRenderer(CFX_RenderDevice* pDevice,
+                                       const RetainPtr<CFX_DIBBase>& pDIBBase,
+                                       const CFX_Matrix* pImage2Device)
+    : m_pDevice(pDevice), m_ImageMatrix(*pImage2Device), m_pDIBBase(pDIBBase) {}
 
-CXFA_ImageRenderer::~CXFA_ImageRenderer() {}
+CXFA_ImageRenderer::~CXFA_ImageRenderer() = default;
 
 bool CXFA_ImageRenderer::Start() {
-  if (m_pDevice->StartDIBitsWithBlend(m_pDIBSource, 255, 0, &m_ImageMatrix,
-                                      FXDIB_INTERPOL, &m_DeviceHandle,
-                                      FXDIB_BLEND_NORMAL)) {
+  FXDIB_ResampleOptions options;
+  options.bInterpolateBilinear = true;
+  if (m_pDevice->StartDIBits(m_pDIBBase, 255, 0, m_ImageMatrix, options,
+                             &m_DeviceHandle)) {
     if (m_DeviceHandle) {
       m_Status = 3;
       return true;
@@ -38,11 +37,11 @@
   int dest_height = image_rect.Height();
   if ((fabs(m_ImageMatrix.b) >= 0.5f || m_ImageMatrix.a == 0) ||
       (fabs(m_ImageMatrix.c) >= 0.5f || m_ImageMatrix.d == 0)) {
-    RetainPtr<CFX_DIBSource> pDib = m_pDIBSource;
-    if (m_pDIBSource->HasAlpha() &&
+    RetainPtr<CFX_DIBBase> pDib = m_pDIBBase;
+    if (m_pDIBBase->HasAlpha() &&
         !(m_pDevice->GetRenderCaps() & FXRC_ALPHA_IMAGE) &&
         !(m_pDevice->GetRenderCaps() & FXRC_GET_BITS)) {
-      m_pCloneConvert = m_pDIBSource->CloneConvert(FXDIB_Rgb);
+      m_pCloneConvert = m_pDIBBase->CloneConvert(FXDIB_Rgb);
       if (!m_pCloneConvert)
         return false;
 
@@ -52,7 +51,7 @@
     clip_box.Intersect(image_rect);
     m_Status = 2;
     m_pTransformer = pdfium::MakeUnique<CFX_ImageTransformer>(
-        pDib, &m_ImageMatrix, FXDIB_INTERPOL, &clip_box);
+        pDib, m_ImageMatrix, options, &clip_box);
     return true;
   }
   if (m_ImageMatrix.a < 0)
@@ -62,17 +61,17 @@
   int dest_left, dest_top;
   dest_left = dest_width > 0 ? image_rect.left : image_rect.right;
   dest_top = dest_height > 0 ? image_rect.top : image_rect.bottom;
-  if (m_pDIBSource->IsOpaqueImage()) {
+  if (m_pDIBBase->IsOpaqueImage()) {
     if (m_pDevice->StretchDIBitsWithFlagsAndBlend(
-            m_pDIBSource, dest_left, dest_top, dest_width, dest_height,
-            FXDIB_INTERPOL, FXDIB_BLEND_NORMAL)) {
+            m_pDIBBase, dest_left, dest_top, dest_width, dest_height, options,
+            BlendMode::kNormal)) {
       return false;
     }
   }
-  if (m_pDIBSource->IsAlphaMask()) {
-    if (m_pDevice->StretchBitMaskWithFlags(m_pDIBSource, dest_left, dest_top,
+  if (m_pDIBBase->IsAlphaMask()) {
+    if (m_pDevice->StretchBitMaskWithFlags(m_pDIBBase, dest_left, dest_top,
                                            dest_width, dest_height, 0,
-                                           FXDIB_INTERPOL)) {
+                                           options)) {
       return false;
     }
   }
@@ -83,8 +82,8 @@
   FX_RECT dest_clip(
       dest_rect.left - image_rect.left, dest_rect.top - image_rect.top,
       dest_rect.right - image_rect.left, dest_rect.bottom - image_rect.top);
-  RetainPtr<CFX_DIBitmap> pStretched = m_pDIBSource->StretchTo(
-      dest_width, dest_height, FXDIB_INTERPOL, &dest_clip);
+  RetainPtr<CFX_DIBitmap> pStretched =
+      m_pDIBBase->StretchTo(dest_width, dest_height, options, &dest_clip);
   if (pStretched)
     CompositeDIBitmap(pStretched, dest_rect.left, dest_rect.top);
 
@@ -106,7 +105,7 @@
     } else {
       m_pDevice->SetDIBitsWithBlend(pBitmap, m_pTransformer->result().left,
                                     m_pTransformer->result().top,
-                                    FXDIB_BLEND_NORMAL);
+                                    BlendMode::kNormal);
     }
     return false;
   }
@@ -137,7 +136,7 @@
     if (pDIBitmap->IsAlphaMask())
       return;
 
-    m_pDevice->SetDIBitsWithBlend(pDIBitmap, left, top, FXDIB_BLEND_NORMAL);
+    m_pDevice->SetDIBitsWithBlend(pDIBitmap, left, top, BlendMode::kNormal);
     return;
   }
   if (!pDIBitmap->HasAlpha() ||
@@ -149,7 +148,8 @@
   if (!pCloneConvert)
     return;
 
-  CXFA_ImageRenderer imageRender(m_pDevice, pCloneConvert, &m_ImageMatrix);
+  CXFA_ImageRenderer imageRender(m_pDevice.Get(), pCloneConvert,
+                                 &m_ImageMatrix);
   if (!imageRender.Start())
     return;
 
diff --git a/xfa/fxfa/cxfa_imagerenderer.h b/xfa/fxfa/cxfa_imagerenderer.h
index 8ed9ab0..37e45d0 100644
--- a/xfa/fxfa/cxfa_imagerenderer.h
+++ b/xfa/fxfa/cxfa_imagerenderer.h
@@ -11,10 +11,10 @@
 
 #include "core/fxcrt/fx_coordinates.h"
 #include "core/fxcrt/retain_ptr.h"
-#include "core/fxge/fx_dib.h"
+#include "core/fxcrt/unowned_ptr.h"
 
 class CFX_RenderDevice;
-class CFX_DIBSource;
+class CFX_DIBBase;
 class CFX_DIBitmap;
 class CFX_ImageTransformer;
 class CFX_ImageRenderer;
@@ -22,7 +22,7 @@
 class CXFA_ImageRenderer {
  public:
   CXFA_ImageRenderer(CFX_RenderDevice* pDevice,
-                     const RetainPtr<CFX_DIBSource>& pDIBSource,
+                     const RetainPtr<CFX_DIBBase>& pDIBBase,
                      const CFX_Matrix* pImage2Device);
   ~CXFA_ImageRenderer();
 
@@ -34,10 +34,10 @@
                          int left,
                          int top);
 
-  CFX_RenderDevice* m_pDevice;
+  UnownedPtr<CFX_RenderDevice> m_pDevice;
   int m_Status = 0;
   CFX_Matrix m_ImageMatrix;
-  RetainPtr<CFX_DIBSource> m_pDIBSource;
+  RetainPtr<CFX_DIBBase> m_pDIBBase;
   RetainPtr<CFX_DIBitmap> m_pCloneConvert;
   std::unique_ptr<CFX_ImageTransformer> m_pTransformer;
   std::unique_ptr<CFX_ImageRenderer> m_DeviceHandle;
diff --git a/xfa/fxfa/cxfa_linkuserdata.cpp b/xfa/fxfa/cxfa_linkuserdata.cpp
deleted file mode 100644
index c32b746..0000000
--- a/xfa/fxfa/cxfa_linkuserdata.cpp
+++ /dev/null
@@ -1,12 +0,0 @@
-// 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
-
-#include "xfa/fxfa/cxfa_linkuserdata.h"
-
-CXFA_LinkUserData::CXFA_LinkUserData(wchar_t* pszText)
-    : m_wsURLContent(pszText) {}
-
-CXFA_LinkUserData::~CXFA_LinkUserData() {}
diff --git a/xfa/fxfa/cxfa_loadercontext.cpp b/xfa/fxfa/cxfa_loadercontext.cpp
index 05ba9f1..5f66050 100644
--- a/xfa/fxfa/cxfa_loadercontext.cpp
+++ b/xfa/fxfa/cxfa_loadercontext.cpp
@@ -6,16 +6,8 @@
 
 #include "xfa/fxfa/cxfa_loadercontext.h"
 
-CXFA_LoaderContext::CXFA_LoaderContext()
-    : m_bSaveLineHeight(false),
-      m_fWidth(0),
-      m_fHeight(0),
-      m_fLastPos(0),
-      m_fStartLineOffset(0),
-      m_iChar(0),
-      m_iTotalLines(-1),
-      m_dwFlags(0),
-      m_pXMLNode(nullptr),
-      m_pNode(nullptr) {}
+#include "core/fxcrt/css/cfx_csscomputedstyle.h"
 
-CXFA_LoaderContext::~CXFA_LoaderContext() {}
+CXFA_LoaderContext::CXFA_LoaderContext() = default;
+
+CXFA_LoaderContext::~CXFA_LoaderContext() = default;
diff --git a/xfa/fxfa/cxfa_loadercontext.h b/xfa/fxfa/cxfa_loadercontext.h
index 06e3f11..ddcb909 100644
--- a/xfa/fxfa/cxfa_loadercontext.h
+++ b/xfa/fxfa/cxfa_loadercontext.h
@@ -9,31 +9,37 @@
 
 #include <vector>
 
-#include "core/fxcrt/css/cfx_csscomputedstyle.h"
 #include "core/fxcrt/fx_system.h"
+#include "core/fxcrt/retain_ptr.h"
+#include "core/fxcrt/unowned_ptr.h"
 
+class CFX_CSSComputedStyle;
 class CFX_XMLNode;
 class CXFA_Node;
 
-class CXFA_LoaderContext {
- public:
+struct CXFA_BlockHeight {
+  size_t szBlockIndex;
+  float fHeight;
+};
+
+struct CXFA_LoaderContext {
   CXFA_LoaderContext();
   ~CXFA_LoaderContext();
 
-  bool m_bSaveLineHeight;
-  float m_fWidth;
-  float m_fHeight;
-  float m_fLastPos;
-  float m_fStartLineOffset;
-  int32_t m_iChar;
-  int32_t m_iLines;
-  int32_t m_iTotalLines;
-  uint32_t m_dwFlags;
-  CFX_XMLNode* m_pXMLNode;
-  CXFA_Node* m_pNode;
-  RetainPtr<CFX_CSSComputedStyle> m_pParentStyle;
-  std::vector<float> m_lineHeights;
-  std::vector<float> m_BlocksHeight;
+  bool bSaveLineHeight = false;
+  bool bFilterSpace = false;
+  float fWidth = 0;
+  float fHeight = 0;
+  float fLastPos = 0;
+  float fStartLineOffset = 0;
+  int32_t iChar = 0;
+  // TODO(thestig): Make this size_t?
+  int32_t iTotalLines = -1;
+  UnownedPtr<const CFX_XMLNode> pXMLNode;
+  UnownedPtr<CXFA_Node> pNode;
+  RetainPtr<CFX_CSSComputedStyle> pParentStyle;
+  std::vector<float> lineHeights;
+  std::vector<CXFA_BlockHeight> blockHeights;
 };
 
 #endif  // XFA_FXFA_CXFA_LOADERCONTEXT_H_
diff --git a/xfa/fxfa/cxfa_pieceline.h b/xfa/fxfa/cxfa_pieceline.h
index dc95e73..0e233ac 100644
--- a/xfa/fxfa/cxfa_pieceline.h
+++ b/xfa/fxfa/cxfa_pieceline.h
@@ -18,7 +18,7 @@
   ~CXFA_PieceLine();
 
   std::vector<std::unique_ptr<CXFA_TextPiece>> m_textPieces;
-  std::vector<int32_t> m_charCounts;
+  std::vector<size_t> m_charCounts;
 };
 
 #endif  // XFA_FXFA_CXFA_PIECELINE_H_
diff --git a/xfa/fxfa/cxfa_readynodeiterator.cpp b/xfa/fxfa/cxfa_readynodeiterator.cpp
new file mode 100644
index 0000000..728d9d6
--- /dev/null
+++ b/xfa/fxfa/cxfa_readynodeiterator.cpp
@@ -0,0 +1,31 @@
+// 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
+
+#include "xfa/fxfa/cxfa_readynodeiterator.h"
+
+#include "xfa/fxfa/parser/cxfa_node.h"
+
+CXFA_ReadyNodeIterator::CXFA_ReadyNodeIterator(CXFA_Node* pTravelRoot)
+    : m_ContentIterator(pTravelRoot) {}
+
+CXFA_ReadyNodeIterator::~CXFA_ReadyNodeIterator() {}
+
+CXFA_Node* CXFA_ReadyNodeIterator::MoveToNext() {
+  CXFA_Node* pItem = m_pCurNode ? m_ContentIterator.MoveToNext()
+                                : m_ContentIterator.GetCurrent();
+  while (pItem) {
+    m_pCurNode = pItem->IsWidgetReady() ? pItem : nullptr;
+    if (m_pCurNode)
+      return m_pCurNode.Get();
+    pItem = m_ContentIterator.MoveToNext();
+  }
+  return nullptr;
+}
+
+void CXFA_ReadyNodeIterator::SkipTree() {
+  m_ContentIterator.SkipChildrenAndMoveToNext();
+  m_pCurNode = nullptr;
+}
diff --git a/xfa/fxfa/cxfa_readynodeiterator.h b/xfa/fxfa/cxfa_readynodeiterator.h
new file mode 100644
index 0000000..d3cd901
--- /dev/null
+++ b/xfa/fxfa/cxfa_readynodeiterator.h
@@ -0,0 +1,28 @@
+// 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_CXFA_READYNODEITERATOR_H_
+#define XFA_FXFA_CXFA_READYNODEITERATOR_H_
+
+#include "core/fxcrt/unowned_ptr.h"
+#include "xfa/fxfa/parser/cxfa_traversestrategy_xfacontainernode.h"
+
+class CXFA_Node;
+
+class CXFA_ReadyNodeIterator {
+ public:
+  explicit CXFA_ReadyNodeIterator(CXFA_Node* pTravelRoot);
+  ~CXFA_ReadyNodeIterator();
+
+  CXFA_Node* MoveToNext();
+  void SkipTree();
+
+ private:
+  CXFA_ContainerIterator m_ContentIterator;
+  UnownedPtr<CXFA_Node> m_pCurNode;
+};
+
+#endif  // XFA_FXFA_CXFA_READYNODEITERATOR_H_
diff --git a/xfa/fxfa/cxfa_rendercontext.cpp b/xfa/fxfa/cxfa_rendercontext.cpp
index 6667d46..106fcbe 100644
--- a/xfa/fxfa/cxfa_rendercontext.cpp
+++ b/xfa/fxfa/cxfa_rendercontext.cpp
@@ -8,29 +8,25 @@
 
 #include "xfa/fxfa/cxfa_ffpageview.h"
 #include "xfa/fxfa/cxfa_ffwidget.h"
-#include "xfa/fxgraphics/cxfa_graphics.h"
 
 CXFA_RenderContext::CXFA_RenderContext(CXFA_FFPageView* pPageView,
                                        const CFX_RectF& clipRect,
                                        const CFX_Matrix& matrix)
-    : m_pWidget(nullptr), m_matrix(matrix), m_rtClipRect(clipRect) {
-  matrix.GetInverse().TransformRect(m_rtClipRect);
+    : m_pWidgetIterator(pPageView->CreateFormWidgetIterator(
+          XFA_WidgetStatus_Visible | XFA_WidgetStatus_Viewable)),
+      m_pWidget(m_pWidgetIterator->MoveToNext()),
+      m_matrix(matrix),
+      m_rtClipRect(clipRect) {}
 
-  m_pWidgetIterator = pPageView->CreateWidgetIterator(
-      XFA_TRAVERSEWAY_Form,
-      XFA_WidgetStatus_Visible | XFA_WidgetStatus_Viewable);
-  m_pWidget = m_pWidgetIterator->MoveToNext();
-}
-
-CXFA_RenderContext::~CXFA_RenderContext() {}
+CXFA_RenderContext::~CXFA_RenderContext() = default;
 
 void CXFA_RenderContext::DoRender(CXFA_Graphics* gs) {
   while (m_pWidget) {
-    CFX_RectF rtWidgetBox = m_pWidget->GetBBox(XFA_WidgetStatus_Visible);
-    rtWidgetBox.width += 1;
-    rtWidgetBox.height += 1;
+    CFX_RectF rtWidgetBox = m_pWidget->GetBBox(CXFA_FFWidget::kDoNotDrawFocus);
+    ++rtWidgetBox.width;
+    ++rtWidgetBox.height;
     if (rtWidgetBox.IntersectWith(m_rtClipRect))
-      m_pWidget->RenderWidget(gs, m_matrix, XFA_WidgetStatus_Highlight);
+      m_pWidget->RenderWidget(gs, m_matrix, CXFA_FFWidget::kHighlight);
 
     m_pWidget = m_pWidgetIterator->MoveToNext();
   }
diff --git a/xfa/fxfa/cxfa_rendercontext.h b/xfa/fxfa/cxfa_rendercontext.h
index 411830d..457c62f 100644
--- a/xfa/fxfa/cxfa_rendercontext.h
+++ b/xfa/fxfa/cxfa_rendercontext.h
@@ -9,9 +9,13 @@
 
 #include <memory>
 
-#include "xfa/fxfa/fxfa.h"
+#include "core/fxcrt/fx_coordinates.h"
+#include "core/fxcrt/unowned_ptr.h"
 
 class CXFA_Graphics;
+class CXFA_FFPageView;
+class CXFA_FFWidget;
+class IXFA_WidgetIterator;
 
 class CXFA_RenderContext {
  public:
@@ -23,10 +27,10 @@
   void DoRender(CXFA_Graphics* gs);
 
  private:
-  std::unique_ptr<IXFA_WidgetIterator> m_pWidgetIterator;
-  CXFA_FFWidget* m_pWidget;
-  CFX_Matrix m_matrix;
-  CFX_RectF m_rtClipRect;
+  std::unique_ptr<IXFA_WidgetIterator> const m_pWidgetIterator;
+  UnownedPtr<CXFA_FFWidget> m_pWidget;
+  const CFX_Matrix m_matrix;
+  const CFX_RectF m_rtClipRect;
 };
 
 #endif  // XFA_FXFA_CXFA_RENDERCONTEXT_H_
diff --git a/xfa/fxfa/cxfa_textlayout.cpp b/xfa/fxfa/cxfa_textlayout.cpp
index ebb9e8a..45f682c 100644
--- a/xfa/fxfa/cxfa_textlayout.cpp
+++ b/xfa/fxfa/cxfa_textlayout.cpp
@@ -16,35 +16,59 @@
 #include "core/fxcrt/xml/cfx_xmltext.h"
 #include "core/fxge/cfx_graphstatedata.h"
 #include "core/fxge/cfx_pathdata.h"
+#include "core/fxge/cfx_renderdevice.h"
+#include "core/fxge/text_char_pos.h"
 #include "fxjs/xfa/cjx_object.h"
 #include "third_party/base/ptr_util.h"
 #include "third_party/base/stl_util.h"
 #include "xfa/fde/cfde_textout.h"
 #include "xfa/fgas/font/cfgas_gefont.h"
-#include "xfa/fxfa/cxfa_linkuserdata.h"
+#include "xfa/fgas/layout/cfx_linkuserdata.h"
+#include "xfa/fgas/layout/cfx_rtfbreak.h"
+#include "xfa/fgas/layout/cfx_textuserdata.h"
 #include "xfa/fxfa/cxfa_loadercontext.h"
 #include "xfa/fxfa/cxfa_pieceline.h"
 #include "xfa/fxfa/cxfa_textparsecontext.h"
 #include "xfa/fxfa/cxfa_textpiece.h"
 #include "xfa/fxfa/cxfa_textprovider.h"
 #include "xfa/fxfa/cxfa_texttabstopscontext.h"
-#include "xfa/fxfa/cxfa_textuserdata.h"
 #include "xfa/fxfa/parser/cxfa_font.h"
 #include "xfa/fxfa/parser/cxfa_node.h"
 #include "xfa/fxfa/parser/cxfa_para.h"
 
-#define XFA_LOADERCNTXTFLG_FILTERSPACE 0x001
+namespace {
+
+constexpr float kHeightTolerance = 0.001f;
+
+void ProcessText(WideString* pText) {
+  int32_t iLen = pText->GetLength();
+  if (iLen == 0)
+    return;
+
+  int32_t iTrimLeft = 0;
+  {
+    // Span's lifetime must end before ReleaseBuffer() below.
+    pdfium::span<wchar_t> psz = pText->GetBuffer(iLen);
+    wchar_t wPrev = 0;
+    for (int32_t i = 0; i < iLen; i++) {
+      wchar_t wch = psz[i];
+      if (wch < 0x20)
+        wch = 0x20;
+      if (wch == 0x20 && wPrev == 0x20)
+        continue;
+
+      wPrev = wch;
+      psz[iTrimLeft++] = wch;
+    }
+  }
+  pText->ReleaseBuffer(iTrimLeft);
+}
+
+}  // namespace
 
 CXFA_TextLayout::CXFA_TextLayout(CXFA_FFDoc* doc,
                                  CXFA_TextProvider* pTextProvider)
-    : m_bHasBlock(false),
-      m_pDoc(doc),
-      m_pTextProvider(pTextProvider),
-      m_pTextDataNode(nullptr),
-      m_bRichText(false),
-      m_iLines(0),
-      m_fMaxWidth(0),
-      m_bBlockContinue(true) {
+    : m_pDoc(doc), m_pTextProvider(pTextProvider) {
   ASSERT(m_pTextProvider);
 }
 
@@ -59,10 +83,7 @@
 }
 
 void CXFA_TextLayout::GetTextDataNode() {
-  if (!m_pTextProvider)
-    return;
-
-  CXFA_Node* pNode = m_pTextProvider->GetTextNode(m_bRichText);
+  CXFA_Node* pNode = m_pTextProvider->GetTextNode(&m_bRichText);
   if (pNode && m_bRichText)
     m_textParser.Reset();
 
@@ -77,20 +98,16 @@
   if (!pXMLRoot)
     return nullptr;
 
-  CFX_XMLNode* pXMLContainer = nullptr;
-  for (CFX_XMLNode* pXMLChild = pXMLRoot->GetNodeItem(CFX_XMLNode::FirstChild);
-       pXMLChild;
-       pXMLChild = pXMLChild->GetNodeItem(CFX_XMLNode::NextSibling)) {
-    if (pXMLChild->GetType() == FX_XMLNODE_Element) {
-      CFX_XMLElement* pXMLElement = static_cast<CFX_XMLElement*>(pXMLChild);
-      WideString wsTag = pXMLElement->GetLocalTagName();
-      if (wsTag == L"body" || wsTag == L"html") {
-        pXMLContainer = pXMLChild;
-        break;
-      }
-    }
+  for (CFX_XMLNode* pXMLChild = pXMLRoot->GetFirstChild(); pXMLChild;
+       pXMLChild = pXMLChild->GetNextSibling()) {
+    CFX_XMLElement* pXMLElement = ToXMLElement(pXMLChild);
+    if (!pXMLElement)
+      continue;
+    WideString wsTag = pXMLElement->GetLocalTagName();
+    if (wsTag.EqualsASCII("body") || wsTag.EqualsASCII("html"))
+      return pXMLChild;
   }
-  return pXMLContainer;
+  return nullptr;
 }
 
 std::unique_ptr<CFX_RTFBreak> CXFA_TextLayout::CreateBreak(bool bDefault) {
@@ -100,7 +117,7 @@
 
   auto pBreak = pdfium::MakeUnique<CFX_RTFBreak>(dwStyle);
   pBreak->SetLineBreakTolerance(1);
-  pBreak->SetFont(m_textParser.GetFont(m_pDoc, m_pTextProvider, nullptr));
+  pBreak->SetFont(m_textParser.GetFont(m_pDoc.Get(), m_pTextProvider, nullptr));
   pBreak->SetFontSize(m_textParser.GetFontSize(m_pTextProvider, nullptr));
   return pBreak;
 }
@@ -112,20 +129,20 @@
   if (para) {
     CFX_RTFLineAlignment iAlign = CFX_RTFLineAlignment::Left;
     switch (para->GetHorizontalAlign()) {
-      case XFA_AttributeEnum::Center:
+      case XFA_AttributeValue::Center:
         iAlign = CFX_RTFLineAlignment::Center;
         break;
-      case XFA_AttributeEnum::Right:
+      case XFA_AttributeValue::Right:
         iAlign = CFX_RTFLineAlignment::Right;
         break;
-      case XFA_AttributeEnum::Justify:
+      case XFA_AttributeValue::Justify:
         iAlign = CFX_RTFLineAlignment::Justified;
         break;
-      case XFA_AttributeEnum::JustifyAll:
+      case XFA_AttributeValue::JustifyAll:
         iAlign = CFX_RTFLineAlignment::Distributed;
         break;
-      case XFA_AttributeEnum::Left:
-      case XFA_AttributeEnum::Radix:
+      case XFA_AttributeValue::Left:
+      case XFA_AttributeValue::Radix:
         break;
       default:
         NOTREACHED();
@@ -162,14 +179,15 @@
 
   float fFontSize = m_textParser.GetFontSize(m_pTextProvider, nullptr);
   m_pBreak->SetFontSize(fFontSize);
-  m_pBreak->SetFont(m_textParser.GetFont(m_pDoc, m_pTextProvider, nullptr));
+  m_pBreak->SetFont(
+      m_textParser.GetFont(m_pDoc.Get(), m_pTextProvider, nullptr));
   m_pBreak->SetLineBreakTolerance(fFontSize * 0.2f);
 }
 
 void CXFA_TextLayout::InitBreak(CFX_CSSComputedStyle* pStyle,
                                 CFX_CSSDisplay eDisplay,
                                 float fLineWidth,
-                                CFX_XMLNode* pXMLNode,
+                                const CFX_XMLNode* pXMLNode,
                                 CFX_CSSComputedStyle* pParentStyle) {
   if (!pStyle) {
     InitBreak(fLineWidth);
@@ -242,7 +260,8 @@
   float fFontSize = m_textParser.GetFontSize(m_pTextProvider, pStyle);
   m_pBreak->SetFontSize(fFontSize);
   m_pBreak->SetLineBreakTolerance(fFontSize * 0.2f);
-  m_pBreak->SetFont(m_textParser.GetFont(m_pDoc, m_pTextProvider, pStyle));
+  m_pBreak->SetFont(
+      m_textParser.GetFont(m_pDoc.Get(), m_pTextProvider, pStyle));
   m_pBreak->SetHorizontalScale(
       m_textParser.GetHorScale(m_pTextProvider, pStyle, pXMLNode));
   m_pBreak->SetVerticalScale(m_textParser.GetVerScale(m_pTextProvider, pStyle));
@@ -253,19 +272,19 @@
   if (!m_pLoader)
     return 0;
 
-  if (m_pLoader->m_lineHeights.empty() && m_pLoader->m_fWidth > 0) {
-    CFX_SizeF szMax(m_pLoader->m_fWidth, m_pLoader->m_fHeight);
-    m_pLoader->m_bSaveLineHeight = true;
-    m_pLoader->m_fLastPos = 0;
+  if (m_pLoader->lineHeights.empty() && m_pLoader->fWidth > 0) {
+    CFX_SizeF szMax(m_pLoader->fWidth, m_pLoader->fHeight);
+    m_pLoader->bSaveLineHeight = true;
+    m_pLoader->fLastPos = 0;
     CFX_SizeF szDef = CalcSize(szMax, szMax);
-    m_pLoader->m_bSaveLineHeight = false;
+    m_pLoader->bSaveLineHeight = false;
     return szDef.height;
   }
 
-  float fHeight = m_pLoader->m_fHeight;
+  float fHeight = m_pLoader->fHeight;
   if (fHeight < 0.1f) {
     fHeight = 0;
-    for (float value : m_pLoader->m_lineHeights)
+    for (float value : m_pLoader->lineHeights)
       fHeight += value;
   }
   return fHeight;
@@ -276,107 +295,119 @@
     m_pLoader = pdfium::MakeUnique<CXFA_LoaderContext>();
 
   if (fWidth < 0 ||
-      (m_pLoader->m_fWidth > -1 && fabs(fWidth - m_pLoader->m_fWidth) > 0)) {
-    m_pLoader->m_lineHeights.clear();
+      (m_pLoader->fWidth > -1 && fabs(fWidth - m_pLoader->fWidth) > 0)) {
+    m_pLoader->lineHeights.clear();
     m_Blocks.clear();
     Unload();
-    m_pLoader->m_fStartLineOffset = 0;
+    m_pLoader->fStartLineOffset = 0;
   }
-  m_pLoader->m_fWidth = fWidth;
+  m_pLoader->fWidth = fWidth;
 
   if (fWidth >= 0)
     return fWidth;
 
   CFX_SizeF szMax;
 
-  m_pLoader->m_bSaveLineHeight = true;
-  m_pLoader->m_fLastPos = 0;
+  m_pLoader->bSaveLineHeight = true;
+  m_pLoader->fLastPos = 0;
   CFX_SizeF szDef = CalcSize(szMax, szMax);
-  m_pLoader->m_bSaveLineHeight = false;
+  m_pLoader->bSaveLineHeight = false;
   return szDef.width;
 }
 
-float CXFA_TextLayout::DoLayout(int32_t iBlockIndex,
-                                float fCalcHeight,
-                                float fContentAreaHeight,
-                                float fTextHeight) {
+float CXFA_TextLayout::DoLayout(float fTextHeight) {
+  if (!m_pLoader)
+    return fTextHeight;
+
+  UpdateLoaderHeight(fTextHeight);
+  return fTextHeight;
+}
+
+float CXFA_TextLayout::DoSplitLayout(size_t szBlockIndex,
+                                     float fCalcHeight,
+                                     float fTextHeight) {
   if (!m_pLoader)
     return fCalcHeight;
 
-  int32_t iBlockCount = pdfium::CollectionSize<int32_t>(m_Blocks);
-  float fHeight = fTextHeight;
-  if (fHeight < 0)
-    fHeight = GetLayoutHeight();
+  UpdateLoaderHeight(fTextHeight);
 
-  m_pLoader->m_fHeight = fHeight;
-  if (fContentAreaHeight < 0)
+  if (fCalcHeight < 0)
     return fCalcHeight;
 
   m_bHasBlock = true;
-  if (iBlockCount == 0 && fHeight > 0) {
-    fHeight = fTextHeight - GetLayoutHeight();
+  if (m_Blocks.empty() && m_pLoader->fHeight > 0) {
+    float fHeight = fTextHeight - GetLayoutHeight();
     if (fHeight > 0) {
-      XFA_AttributeEnum iAlign = m_textParser.GetVAlign(m_pTextProvider);
-      if (iAlign == XFA_AttributeEnum::Middle)
+      XFA_AttributeValue iAlign = m_textParser.GetVAlign(m_pTextProvider);
+      if (iAlign == XFA_AttributeValue::Middle)
         fHeight /= 2.0f;
-      else if (iAlign != XFA_AttributeEnum::Bottom)
+      else if (iAlign != XFA_AttributeValue::Bottom)
         fHeight = 0;
-      m_pLoader->m_fStartLineOffset = fHeight;
+      m_pLoader->fStartLineOffset = fHeight;
     }
   }
 
-  float fLinePos = m_pLoader->m_fStartLineOffset;
-  int32_t iLineIndex = 0;
-  if (iBlockCount > 1) {
-    if (iBlockCount >= (iBlockIndex + 1) * 2) {
-      iLineIndex = m_Blocks[iBlockIndex * 2];
-    } else {
-      iLineIndex = m_Blocks[iBlockCount - 1] + m_Blocks[iBlockCount - 2];
-    }
-    if (!m_pLoader->m_BlocksHeight.empty()) {
-      for (int32_t i = 0; i < iBlockIndex; i++)
-        fLinePos -= m_pLoader->m_BlocksHeight[i * 2 + 1];
+  float fLinePos = m_pLoader->fStartLineOffset;
+  size_t szLineIndex = 0;
+  if (!m_Blocks.empty()) {
+    if (szBlockIndex < m_Blocks.size())
+      szLineIndex = m_Blocks[szBlockIndex].szIndex;
+    else
+      szLineIndex = GetNextIndexFromLastBlockData();
+    for (size_t i = 0;
+         i < std::min(szBlockIndex, m_pLoader->blockHeights.size()); ++i) {
+      fLinePos -= m_pLoader->blockHeights[i].fHeight;
     }
   }
 
-  int32_t iCount = pdfium::CollectionSize<int32_t>(m_pLoader->m_lineHeights);
-  int32_t i = 0;
-  for (i = iLineIndex; i < iCount; i++) {
-    float fLineHeight = m_pLoader->m_lineHeights[i];
-    if (i == iLineIndex && fLineHeight - fContentAreaHeight > 0.001)
-      return 0;
+  if (szLineIndex >= m_pLoader->lineHeights.size())
+    return fCalcHeight;
 
-    if (fLinePos + fLineHeight - fContentAreaHeight > 0.001) {
-      if (iBlockCount >= (iBlockIndex + 1) * 2) {
-        m_Blocks[iBlockIndex * 2] = iLineIndex;
-        m_Blocks[iBlockIndex * 2 + 1] = i - iLineIndex;
-      } else {
-        m_Blocks.push_back(iLineIndex);
-        m_Blocks.push_back(i - iLineIndex);
-      }
-      if (i == iLineIndex) {
-        if (fCalcHeight <= fLinePos) {
-          if (pdfium::CollectionSize<int32_t>(m_pLoader->m_BlocksHeight) >
-                  iBlockIndex * 2 &&
-              (m_pLoader->m_BlocksHeight[iBlockIndex * 2] == iBlockIndex)) {
-            m_pLoader->m_BlocksHeight[iBlockIndex * 2 + 1] = fCalcHeight;
-          } else {
-            m_pLoader->m_BlocksHeight.push_back((float)iBlockIndex);
-            m_pLoader->m_BlocksHeight.push_back(fCalcHeight);
-          }
-        }
-        return fCalcHeight;
-      }
+  if (m_pLoader->lineHeights[szLineIndex] - fCalcHeight > kHeightTolerance)
+    return 0;
+
+  for (size_t i = szLineIndex; i < m_pLoader->lineHeights.size(); ++i) {
+    float fLineHeight = m_pLoader->lineHeights[i];
+    if (fLinePos + fLineHeight - fCalcHeight <= kHeightTolerance) {
+      fLinePos += fLineHeight;
+      continue;
+    }
+
+    if (szBlockIndex < m_Blocks.size())
+      m_Blocks[szBlockIndex] = {szLineIndex, i - szLineIndex};
+    else
+      m_Blocks.push_back({szLineIndex, i - szLineIndex});
+
+    if (i != szLineIndex)
       return fLinePos;
+
+    if (fCalcHeight > fLinePos)
+      return fCalcHeight;
+
+    if (szBlockIndex < m_pLoader->blockHeights.size() &&
+        m_pLoader->blockHeights[szBlockIndex].szBlockIndex == szBlockIndex) {
+      m_pLoader->blockHeights[szBlockIndex].fHeight = fCalcHeight;
+    } else {
+      m_pLoader->blockHeights.push_back({szBlockIndex, fCalcHeight});
     }
-    fLinePos += fLineHeight;
+    return fCalcHeight;
   }
   return fCalcHeight;
 }
 
-int32_t CXFA_TextLayout::CountBlocks() const {
-  int32_t iCount = pdfium::CollectionSize<int32_t>(m_Blocks) / 2;
-  return iCount > 0 ? iCount : 1;
+size_t CXFA_TextLayout::CountBlocks() const {
+  size_t szCount = m_Blocks.size();
+  return szCount > 0 ? szCount : 1;
+}
+
+size_t CXFA_TextLayout::GetNextIndexFromLastBlockData() const {
+  return m_Blocks.back().szIndex + m_Blocks.back().szLength;
+}
+
+void CXFA_TextLayout::UpdateLoaderHeight(float fTextHeight) {
+  m_pLoader->fHeight = fTextHeight;
+  if (m_pLoader->fHeight < 0)
+    m_pLoader->fHeight = GetLayoutHeight();
 }
 
 CFX_SizeF CXFA_TextLayout::CalcSize(const CFX_SizeF& minSize,
@@ -389,7 +420,7 @@
   float fLinePos = 0;
   m_iLines = 0;
   m_fMaxWidth = 0;
-  Loader(width, fLinePos, false);
+  Loader(width, &fLinePos, false);
   if (fLinePos < 0.1f)
     fLinePos = m_textParser.GetFontSize(m_pTextProvider, nullptr);
 
@@ -404,53 +435,48 @@
   Unload();
   m_pBreak = CreateBreak(true);
   if (m_pLoader) {
-    m_pLoader->m_iTotalLines = -1;
-    m_pLoader->m_iChar = 0;
+    m_pLoader->iTotalLines = -1;
+    m_pLoader->iChar = 0;
   }
 
   m_iLines = 0;
   float fLinePos = 0;
-  Loader(size.width, fLinePos, true);
+  Loader(size.width, &fLinePos, true);
   UpdateAlign(size.height, fLinePos);
   m_pTabstopContext.reset();
   return fLinePos;
 }
 
-bool CXFA_TextLayout::Layout(int32_t iBlock) {
-  if (!m_pLoader || iBlock < 0 || iBlock >= CountBlocks())
-    return false;
-  if (m_pLoader->m_fWidth < 1)
+bool CXFA_TextLayout::LayoutInternal(size_t szBlockIndex) {
+  ASSERT(szBlockIndex < CountBlocks());
+
+  if (!m_pLoader || m_pLoader->fWidth < 1)
     return false;
 
-  m_pLoader->m_iTotalLines = -1;
+  m_pLoader->iTotalLines = -1;
   m_iLines = 0;
   float fLinePos = 0;
   CXFA_Node* pNode = nullptr;
-  CFX_SizeF szText(m_pLoader->m_fWidth, m_pLoader->m_fHeight);
-  int32_t iCount = pdfium::CollectionSize<int32_t>(m_Blocks);
-  int32_t iBlocksHeightCount =
-      pdfium::CollectionSize<int32_t>(m_pLoader->m_BlocksHeight);
-  iBlocksHeightCount /= 2;
-  if (iBlock < iBlocksHeightCount)
+  CFX_SizeF szText(m_pLoader->fWidth, m_pLoader->fHeight);
+  if (szBlockIndex < m_pLoader->blockHeights.size())
     return true;
-  if (iBlock == iBlocksHeightCount) {
+  if (szBlockIndex == m_pLoader->blockHeights.size()) {
     Unload();
     m_pBreak = CreateBreak(true);
-    fLinePos = m_pLoader->m_fStartLineOffset;
-    for (int32_t i = 0; i < iBlocksHeightCount; i++)
-      fLinePos -= m_pLoader->m_BlocksHeight[i * 2 + 1];
+    fLinePos = m_pLoader->fStartLineOffset;
+    for (size_t i = 0; i < m_pLoader->blockHeights.size(); ++i)
+      fLinePos -= m_pLoader->blockHeights[i].fHeight;
 
-    m_pLoader->m_iChar = 0;
-    if (iCount > 1)
-      m_pLoader->m_iTotalLines = m_Blocks[iBlock * 2 + 1];
+    m_pLoader->iChar = 0;
+    if (!m_Blocks.empty())
+      m_pLoader->iTotalLines = m_Blocks[szBlockIndex].szLength;
 
-    Loader(szText.width, fLinePos, true);
-    if (iCount == 0 && m_pLoader->m_fStartLineOffset < 0.1f)
+    Loader(szText.width, &fLinePos, true);
+    if (m_Blocks.empty() && m_pLoader->fStartLineOffset < 0.1f)
       UpdateAlign(szText.height, fLinePos);
   } else if (m_pTextDataNode) {
-    iBlock *= 2;
-    if (iBlock < iCount - 2)
-      m_pLoader->m_iTotalLines = m_Blocks[iBlock + 1];
+    if (!m_Blocks.empty() && szBlockIndex < m_Blocks.size() - 1)
+      m_pLoader->iTotalLines = m_Blocks[szBlockIndex].szLength;
 
     m_pBreak->Reset();
     if (m_bRichText) {
@@ -458,150 +484,130 @@
       if (!pContainerNode)
         return true;
 
-      CFX_XMLNode* pXMLNode = m_pLoader->m_pXMLNode;
+      const CFX_XMLNode* pXMLNode = m_pLoader->pXMLNode.Get();
       if (!pXMLNode)
         return true;
 
-      CFX_XMLNode* pSaveXMLNode = m_pLoader->m_pXMLNode;
-      for (; pXMLNode;
-           pXMLNode = pXMLNode->GetNodeItem(CFX_XMLNode::NextSibling)) {
-        if (!LoadRichText(pXMLNode, szText.width, fLinePos,
-                          m_pLoader->m_pParentStyle, true, nullptr)) {
+      const CFX_XMLNode* pSaveXMLNode = pXMLNode;
+      for (; pXMLNode; pXMLNode = pXMLNode->GetNextSibling()) {
+        if (!LoadRichText(pXMLNode, szText.width, &fLinePos,
+                          m_pLoader->pParentStyle, true, nullptr, true, false,
+                          0)) {
           break;
         }
       }
       while (!pXMLNode) {
-        pXMLNode = pSaveXMLNode->GetNodeItem(CFX_XMLNode::Parent);
+        pXMLNode = pSaveXMLNode->GetParent();
         if (pXMLNode == pContainerNode)
           break;
-        if (!LoadRichText(pXMLNode, szText.width, fLinePos,
-                          m_pLoader->m_pParentStyle, true, nullptr, false)) {
+        if (!LoadRichText(pXMLNode, szText.width, &fLinePos,
+                          m_pLoader->pParentStyle, true, nullptr, false, false,
+                          0)) {
           break;
         }
         pSaveXMLNode = pXMLNode;
-        pXMLNode = pXMLNode->GetNodeItem(CFX_XMLNode::NextSibling);
+        pXMLNode = pXMLNode->GetNextSibling();
         if (!pXMLNode)
           continue;
-        for (; pXMLNode;
-             pXMLNode = pXMLNode->GetNodeItem(CFX_XMLNode::NextSibling)) {
-          if (!LoadRichText(pXMLNode, szText.width, fLinePos,
-                            m_pLoader->m_pParentStyle, true, nullptr)) {
+        for (; pXMLNode; pXMLNode = pXMLNode->GetNextSibling()) {
+          if (!LoadRichText(pXMLNode, szText.width, &fLinePos,
+                            m_pLoader->pParentStyle, true, nullptr, true, false,
+                            0)) {
             break;
           }
         }
       }
     } else {
-      pNode = m_pLoader->m_pNode;
+      pNode = m_pLoader->pNode.Get();
       if (!pNode)
         return true;
-      LoadText(pNode, szText.width, fLinePos, true);
+      LoadText(pNode, szText.width, &fLinePos, true);
     }
   }
-  if (iBlock == iCount) {
+  if (szBlockIndex == m_Blocks.size()) {
     m_pTabstopContext.reset();
     m_pLoader.reset();
   }
   return true;
 }
 
-void CXFA_TextLayout::ItemBlocks(const CFX_RectF& rtText, int32_t iBlockIndex) {
+void CXFA_TextLayout::ItemBlocks(const CFX_RectF& rtText, size_t szBlockIndex) {
   if (!m_pLoader)
     return;
 
-  int32_t iCountHeight =
-      pdfium::CollectionSize<int32_t>(m_pLoader->m_lineHeights);
-  if (iCountHeight == 0)
+  if (m_pLoader->lineHeights.empty())
     return;
 
-  bool bEndItem = true;
-  int32_t iBlockCount = pdfium::CollectionSize<int32_t>(m_Blocks);
-  float fLinePos = m_pLoader->m_fStartLineOffset;
-  int32_t iLineIndex = 0;
-  if (iBlockIndex > 0) {
-    int32_t iBlockHeightCount =
-        pdfium::CollectionSize<int32_t>(m_pLoader->m_BlocksHeight);
-    iBlockHeightCount /= 2;
-    if (iBlockHeightCount >= iBlockIndex) {
-      for (int32_t i = 0; i < iBlockIndex; i++)
-        fLinePos -= m_pLoader->m_BlocksHeight[i * 2 + 1];
+  float fLinePos = m_pLoader->fStartLineOffset;
+  size_t szLineIndex = 0;
+  if (szBlockIndex > 0) {
+    if (szBlockIndex <= m_pLoader->blockHeights.size()) {
+      for (size_t i = 0; i < szBlockIndex; ++i)
+        fLinePos -= m_pLoader->blockHeights[i].fHeight;
     } else {
       fLinePos = 0;
     }
-    iLineIndex = m_Blocks[iBlockCount - 1] + m_Blocks[iBlockCount - 2];
+    szLineIndex = GetNextIndexFromLastBlockData();
   }
 
-  int32_t i = 0;
-  for (i = iLineIndex; i < iCountHeight; i++) {
-    float fLineHeight = m_pLoader->m_lineHeights[i];
-    if (fLinePos + fLineHeight - rtText.height > 0.001) {
-      m_Blocks.push_back(iLineIndex);
-      m_Blocks.push_back(i - iLineIndex);
-      bEndItem = false;
-      break;
+  size_t i;
+  for (i = szLineIndex; i < m_pLoader->lineHeights.size(); ++i) {
+    float fLineHeight = m_pLoader->lineHeights[i];
+    if (fLinePos + fLineHeight - rtText.height > kHeightTolerance) {
+      m_Blocks.push_back({szLineIndex, i - szLineIndex});
+      return;
     }
     fLinePos += fLineHeight;
   }
-  if (iCountHeight > 0 && (i - iLineIndex) > 0 && bEndItem) {
-    m_Blocks.push_back(iLineIndex);
-    m_Blocks.push_back(i - iLineIndex);
-  }
+  if (i > szLineIndex)
+    m_Blocks.push_back({szLineIndex, i - szLineIndex});
 }
 
 bool CXFA_TextLayout::DrawString(CFX_RenderDevice* pFxDevice,
-                                 const CFX_Matrix& tmDoc2Device,
+                                 const CFX_Matrix& mtDoc2Device,
                                  const CFX_RectF& rtClip,
-                                 int32_t iBlock) {
+                                 size_t szBlockIndex) {
   if (!pFxDevice)
     return false;
 
   pFxDevice->SaveState();
-  pFxDevice->SetClip_Rect(rtClip);
+  pFxDevice->SetClip_Rect(rtClip.GetOuterRect());
 
   if (m_pieceLines.empty()) {
-    int32_t iBlockCount = CountBlocks();
-    for (int32_t i = 0; i < iBlockCount; i++)
-      Layout(i);
+    size_t szBlockCount = CountBlocks();
+    for (size_t i = 0; i < szBlockCount; ++i)
+      LayoutInternal(i);
   }
 
-  FXTEXT_CHARPOS* pCharPos = nullptr;
-  int32_t iCharCount = 0;
-  int32_t iLineStart = 0;
-  int32_t iPieceLines = pdfium::CollectionSize<int32_t>(m_pieceLines);
-  int32_t iCount = pdfium::CollectionSize<int32_t>(m_Blocks);
-  if (iCount > 0) {
-    iBlock *= 2;
-    if (iBlock < iCount) {
-      iLineStart = m_Blocks[iBlock];
-      iPieceLines = m_Blocks[iBlock + 1];
+  std::vector<TextCharPos> char_pos(1);
+  size_t szLineStart = 0;
+  size_t szPieceLines = m_pieceLines.size();
+  if (!m_Blocks.empty()) {
+    if (szBlockIndex < m_Blocks.size()) {
+      szLineStart = m_Blocks[szBlockIndex].szIndex;
+      szPieceLines = m_Blocks[szBlockIndex].szLength;
     } else {
-      iPieceLines = 0;
+      szPieceLines = 0;
     }
   }
 
-  for (int32_t i = 0; i < iPieceLines; i++) {
-    if (i + iLineStart >= pdfium::CollectionSize<int32_t>(m_pieceLines))
+  for (size_t i = 0; i < szPieceLines; ++i) {
+    if (i + szLineStart >= m_pieceLines.size())
       break;
 
-    CXFA_PieceLine* pPieceLine = m_pieceLines[i + iLineStart].get();
-    int32_t iPieces = pdfium::CollectionSize<int32_t>(pPieceLine->m_textPieces);
-    int32_t j = 0;
-    for (j = 0; j < iPieces; j++) {
+    CXFA_PieceLine* pPieceLine = m_pieceLines[i + szLineStart].get();
+    for (size_t j = 0; j < pPieceLine->m_textPieces.size(); ++j) {
       const CXFA_TextPiece* pPiece = pPieceLine->m_textPieces[j].get();
       int32_t iChars = pPiece->iChars;
-      if (iCharCount < iChars) {
-        FX_Free(pCharPos);
-        pCharPos = FX_Alloc(FXTEXT_CHARPOS, iChars);
-        iCharCount = iChars;
-      }
-      memset(pCharPos, 0, iCharCount * sizeof(FXTEXT_CHARPOS));
-      RenderString(pFxDevice, pPieceLine, j, pCharPos, tmDoc2Device);
+      if (pdfium::CollectionSize<int32_t>(char_pos) < iChars)
+        char_pos.resize(iChars);
+      RenderString(pFxDevice, pPieceLine, j, &char_pos, mtDoc2Device);
     }
-    for (j = 0; j < iPieces; j++)
-      RenderPath(pFxDevice, pPieceLine, j, pCharPos, tmDoc2Device);
+    for (size_t j = 0; j < pPieceLine->m_textPieces.size(); ++j)
+      RenderPath(pFxDevice, pPieceLine, j, &char_pos, mtDoc2Device);
   }
   pFxDevice->RestoreState(false);
-  FX_Free(pCharPos);
-  return iPieceLines > 0;
+  return szPieceLines > 0;
 }
 
 void CXFA_TextLayout::UpdateAlign(float fHeight, float fBottom) {
@@ -610,10 +616,10 @@
     return;
 
   switch (m_textParser.GetVAlign(m_pTextProvider)) {
-    case XFA_AttributeEnum::Middle:
+    case XFA_AttributeValue::Middle:
       fHeight /= 2.0f;
       break;
-    case XFA_AttributeEnum::Bottom:
+    case XFA_AttributeValue::Bottom:
       break;
     default:
       return;
@@ -625,32 +631,33 @@
   }
 }
 
-bool CXFA_TextLayout::Loader(float textWidth,
-                             float& fLinePos,
+void CXFA_TextLayout::Loader(float textWidth,
+                             float* pLinePos,
                              bool bSavePieces) {
   GetTextDataNode();
   if (!m_pTextDataNode)
-    return true;
+    return;
 
-  if (m_bRichText) {
-    CFX_XMLNode* pXMLContainer = GetXMLContainerNode();
-    if (pXMLContainer) {
-      if (!m_textParser.IsParsed())
-        m_textParser.DoParse(pXMLContainer, m_pTextProvider);
-
-      auto pRootStyle = m_textParser.CreateRootStyle(m_pTextProvider);
-      LoadRichText(pXMLContainer, textWidth, fLinePos, pRootStyle, bSavePieces,
-                   nullptr);
-    }
-  } else {
-    LoadText(m_pTextDataNode, textWidth, fLinePos, bSavePieces);
+  if (!m_bRichText) {
+    LoadText(m_pTextDataNode, textWidth, pLinePos, bSavePieces);
+    return;
   }
-  return true;
+
+  const CFX_XMLNode* pXMLContainer = GetXMLContainerNode();
+  if (!pXMLContainer)
+    return;
+
+  if (!m_textParser.IsParsed())
+    m_textParser.DoParse(pXMLContainer, m_pTextProvider);
+
+  auto pRootStyle = m_textParser.CreateRootStyle(m_pTextProvider);
+  LoadRichText(pXMLContainer, textWidth, pLinePos, pRootStyle, bSavePieces,
+               nullptr, true, false, 0);
 }
 
 void CXFA_TextLayout::LoadText(CXFA_Node* pNode,
                                float textWidth,
-                               float& fLinePos,
+                               float* pLinePos,
                                bool bSavePieces) {
   InitBreak(textWidth);
 
@@ -662,10 +669,10 @@
       fSpaceAbove = 0;
 
     switch (para->GetVerticalAlign()) {
-      case XFA_AttributeEnum::Top:
-      case XFA_AttributeEnum::Middle:
-      case XFA_AttributeEnum::Bottom: {
-        fLinePos += fSpaceAbove;
+      case XFA_AttributeValue::Top:
+      case XFA_AttributeValue::Middle:
+      case XFA_AttributeValue::Bottom: {
+        *pLinePos += fSpaceAbove;
         break;
       }
       default:
@@ -676,20 +683,20 @@
 
   WideString wsText = pNode->JSObject()->GetContent(false);
   wsText.TrimRight(L" ");
-  bool bRet = AppendChar(wsText, fLinePos, fSpaceAbove, bSavePieces);
+  bool bRet = AppendChar(wsText, pLinePos, fSpaceAbove, bSavePieces);
   if (bRet && m_pLoader)
-    m_pLoader->m_pNode = pNode;
+    m_pLoader->pNode = pNode;
   else
-    EndBreak(CFX_BreakType::Paragraph, fLinePos, bSavePieces);
+    EndBreak(CFX_BreakType::Paragraph, pLinePos, bSavePieces);
 }
 
 bool CXFA_TextLayout::LoadRichText(
-    CFX_XMLNode* pXMLNode,
+    const CFX_XMLNode* pXMLNode,
     float textWidth,
-    float& fLinePos,
+    float* pLinePos,
     const RetainPtr<CFX_CSSComputedStyle>& pParentStyle,
     bool bSavePieces,
-    RetainPtr<CXFA_LinkUserData> pLinkData,
+    RetainPtr<CFX_LinkUserData> pLinkData,
     bool bEndBreak,
     bool bIsOl,
     int32_t iLiCount) {
@@ -706,23 +713,22 @@
   if (bEndBreak) {
     bool bCurOl = false;
     bool bCurLi = false;
-    CFX_XMLElement* pElement = nullptr;
+    const CFX_XMLElement* pElement = nullptr;
     if (pContext) {
-      if (m_bBlockContinue ||
-          (m_pLoader && pXMLNode == m_pLoader->m_pXMLNode)) {
+      if (m_bBlockContinue || (m_pLoader && pXMLNode == m_pLoader->pXMLNode)) {
         m_bBlockContinue = true;
       }
-      if (pXMLNode->GetType() == FX_XMLNODE_Text) {
+      if (pXMLNode->GetType() == CFX_XMLNode::Type::kText) {
         bContentNode = true;
-      } else if (pXMLNode->GetType() == FX_XMLNODE_Element) {
-        pElement = static_cast<CFX_XMLElement*>(pXMLNode);
+      } else if (pXMLNode->GetType() == CFX_XMLNode::Type::kElement) {
+        pElement = static_cast<const CFX_XMLElement*>(pXMLNode);
         wsName = pElement->GetLocalTagName();
       }
-      if (wsName == L"ol") {
+      if (wsName.EqualsASCII("ol")) {
         bIsOl = true;
         bCurOl = true;
       }
-      if (m_bBlockContinue || bContentNode == false) {
+      if (m_bBlockContinue || !bContentNode) {
         eDisplay = pContext->GetDisplay();
         if (eDisplay != CFX_CSSDisplay::Block &&
             eDisplay != CFX_CSSDisplay::Inline &&
@@ -736,23 +742,20 @@
         if ((eDisplay == CFX_CSSDisplay::Block ||
              eDisplay == CFX_CSSDisplay::ListItem) &&
             pStyle &&
-            (wsName.IsEmpty() || (wsName != L"body" && wsName != L"html" &&
-                                  wsName != L"ol" && wsName != L"ul"))) {
+            (wsName.IsEmpty() ||
+             !(wsName.EqualsASCII("body") || wsName.EqualsASCII("html") ||
+               wsName.EqualsASCII("ol") || wsName.EqualsASCII("ul")))) {
           const CFX_CSSRect* pRect = pStyle->GetMarginWidth();
           if (pRect) {
-            fLinePos += pRect->top.GetValue();
+            *pLinePos += pRect->top.GetValue();
             fSpaceBelow = pRect->bottom.GetValue();
           }
         }
 
-        if (wsName == L"a") {
-          ASSERT(pElement);
-          WideString wsLinkContent = pElement->GetString(L"href");
-          if (!wsLinkContent.IsEmpty()) {
-            pLinkData = pdfium::MakeRetain<CXFA_LinkUserData>(
-                wsLinkContent.GetBuffer(wsLinkContent.GetLength()));
-            wsLinkContent.ReleaseBuffer(wsLinkContent.GetLength());
-          }
+        if (wsName.EqualsASCII("a")) {
+          WideString wsLinkContent = pElement->GetAttribute(L"href");
+          if (!wsLinkContent.IsEmpty())
+            pLinkData = pdfium::MakeRetain<CFX_LinkUserData>(wsLinkContent);
         }
 
         int32_t iTabCount = m_textParser.CountTabs(
@@ -761,10 +764,10 @@
             bContentNode ? pParentStyle.Get() : pStyle.Get());
         WideString wsText;
         if (bContentNode && iTabCount == 0) {
-          wsText = static_cast<CFX_XMLText*>(pXMLNode)->GetText();
-        } else if (wsName == L"br") {
+          wsText = ToXMLText(pXMLNode)->GetText();
+        } else if (wsName.EqualsASCII("br")) {
           wsText = L'\n';
-        } else if (wsName == L"li") {
+        } else if (wsName.EqualsASCII("li")) {
           bCurLi = true;
           if (bIsOl)
             wsText = WideString::Format(L"%d.  ", iLiCount);
@@ -775,63 +778,61 @@
             while (iTabCount-- > 0)
               wsText += L'\t';
           } else {
-            m_textParser.GetEmbbedObj(m_pTextProvider, pXMLNode, wsText);
+            Optional<WideString> obj =
+                m_textParser.GetEmbeddedObj(m_pTextProvider, pXMLNode);
+            if (obj)
+              wsText = *obj;
           }
         }
 
         int32_t iLength = wsText.GetLength();
         if (iLength > 0 && bContentNode && !bSpaceRun)
-          ProcessText(wsText);
+          ProcessText(&wsText);
 
         if (m_pLoader) {
-          if (wsText.GetLength() > 0 &&
-              (m_pLoader->m_dwFlags & XFA_LOADERCNTXTFLG_FILTERSPACE)) {
+          if (wsText.GetLength() > 0 && m_pLoader->bFilterSpace) {
             wsText.TrimLeft(L" ");
           }
           if (CFX_CSSDisplay::Block == eDisplay) {
-            m_pLoader->m_dwFlags |= XFA_LOADERCNTXTFLG_FILTERSPACE;
+            m_pLoader->bFilterSpace = true;
           } else if (CFX_CSSDisplay::Inline == eDisplay &&
-                     (m_pLoader->m_dwFlags & XFA_LOADERCNTXTFLG_FILTERSPACE)) {
-            m_pLoader->m_dwFlags &= ~XFA_LOADERCNTXTFLG_FILTERSPACE;
-          } else if (wsText.GetLength() > 0 &&
-                     (0x20 == wsText[wsText.GetLength() - 1])) {
-            m_pLoader->m_dwFlags |= XFA_LOADERCNTXTFLG_FILTERSPACE;
+                     m_pLoader->bFilterSpace) {
+            m_pLoader->bFilterSpace = false;
+          } else if (wsText.GetLength() > 0 && wsText.Back() == 0x20) {
+            m_pLoader->bFilterSpace = true;
           } else if (wsText.GetLength() != 0) {
-            m_pLoader->m_dwFlags &= ~XFA_LOADERCNTXTFLG_FILTERSPACE;
+            m_pLoader->bFilterSpace = false;
           }
         }
 
         if (wsText.GetLength() > 0) {
-          if (!m_pLoader || m_pLoader->m_iChar == 0) {
-            auto pUserData = pdfium::MakeRetain<CXFA_TextUserData>(
+          if (!m_pLoader || m_pLoader->iChar == 0) {
+            auto pUserData = pdfium::MakeRetain<CFX_TextUserData>(
                 bContentNode ? pParentStyle : pStyle, pLinkData);
             m_pBreak->SetUserData(pUserData);
           }
 
-          if (AppendChar(wsText, fLinePos, 0, bSavePieces)) {
+          if (AppendChar(wsText, pLinePos, 0, bSavePieces)) {
             if (m_pLoader)
-              m_pLoader->m_dwFlags &= ~XFA_LOADERCNTXTFLG_FILTERSPACE;
-            if (IsEnd(bSavePieces)) {
-              if (m_pLoader && m_pLoader->m_iTotalLines > -1) {
-                m_pLoader->m_pXMLNode = pXMLNode;
-                m_pLoader->m_pParentStyle = pParentStyle;
-              }
-              return false;
+              m_pLoader->bFilterSpace = false;
+            if (!IsEnd(bSavePieces))
+              return true;
+            if (m_pLoader && m_pLoader->iTotalLines > -1) {
+              m_pLoader->pXMLNode = pXMLNode;
+              m_pLoader->pParentStyle = pParentStyle;
             }
-            return true;
+            return false;
           }
         }
       }
     }
 
-    for (CFX_XMLNode* pChildNode =
-             pXMLNode->GetNodeItem(CFX_XMLNode::FirstChild);
-         pChildNode;
-         pChildNode = pChildNode->GetNodeItem(CFX_XMLNode::NextSibling)) {
+    for (CFX_XMLNode* pChildNode = pXMLNode->GetFirstChild(); pChildNode;
+         pChildNode = pChildNode->GetNextSibling()) {
       if (bCurOl)
         iLiCount++;
 
-      if (!LoadRichText(pChildNode, textWidth, fLinePos,
+      if (!LoadRichText(pChildNode, textWidth, pLinePos,
                         pContext ? pStyle : pParentStyle, bSavePieces,
                         pLinkData, true, bIsOl, iLiCount))
         return false;
@@ -839,10 +840,10 @@
 
     if (m_pLoader) {
       if (CFX_CSSDisplay::Block == eDisplay)
-        m_pLoader->m_dwFlags |= XFA_LOADERCNTXTFLG_FILTERSPACE;
+        m_pLoader->bFilterSpace = true;
     }
     if (bCurLi)
-      EndBreak(CFX_BreakType::Line, fLinePos, bSavePieces);
+      EndBreak(CFX_BreakType::Line, pLinePos, bSavePieces);
   } else {
     if (pContext)
       eDisplay = pContext->GetDisplay();
@@ -853,17 +854,16 @@
       CFX_BreakType dwStatus = (eDisplay == CFX_CSSDisplay::Block)
                                    ? CFX_BreakType::Paragraph
                                    : CFX_BreakType::Piece;
-      EndBreak(dwStatus, fLinePos, bSavePieces);
+      EndBreak(dwStatus, pLinePos, bSavePieces);
       if (eDisplay == CFX_CSSDisplay::Block) {
-        fLinePos += fSpaceBelow;
+        *pLinePos += fSpaceBelow;
         if (m_pTabstopContext)
           m_pTabstopContext->RemoveAll();
       }
       if (IsEnd(bSavePieces)) {
-        if (m_pLoader && m_pLoader->m_iTotalLines > -1) {
-          m_pLoader->m_pXMLNode =
-              pXMLNode->GetNodeItem(CFX_XMLNode::NextSibling);
-          m_pLoader->m_pParentStyle = pParentStyle;
+        if (m_pLoader && m_pLoader->iTotalLines > -1) {
+          m_pLoader->pXMLNode = pXMLNode->GetNextSibling();
+          m_pLoader->pParentStyle = pParentStyle;
         }
         return false;
       }
@@ -873,13 +873,13 @@
 }
 
 bool CXFA_TextLayout::AppendChar(const WideString& wsText,
-                                 float& fLinePos,
+                                 float* pLinePos,
                                  float fSpaceAbove,
                                  bool bSavePieces) {
   CFX_BreakType dwStatus = CFX_BreakType::None;
   int32_t iChar = 0;
   if (m_pLoader)
-    iChar = m_pLoader->m_iChar;
+    iChar = m_pLoader->iChar;
 
   int32_t iLength = wsText.GetLength();
   for (int32_t i = iChar; i < iLength; i++) {
@@ -889,18 +889,18 @@
 
     dwStatus = m_pBreak->AppendChar(wch);
     if (dwStatus != CFX_BreakType::None && dwStatus != CFX_BreakType::Piece) {
-      AppendTextLine(dwStatus, fLinePos, bSavePieces);
+      AppendTextLine(dwStatus, pLinePos, bSavePieces, false);
       if (IsEnd(bSavePieces)) {
         if (m_pLoader)
-          m_pLoader->m_iChar = i;
+          m_pLoader->iChar = i;
         return true;
       }
       if (dwStatus == CFX_BreakType::Paragraph && m_bRichText)
-        fLinePos += fSpaceAbove;
+        *pLinePos += fSpaceAbove;
     }
   }
   if (m_pLoader)
-    m_pLoader->m_iChar = 0;
+    m_pLoader->iChar = 0;
 
   return false;
 }
@@ -908,39 +908,17 @@
 bool CXFA_TextLayout::IsEnd(bool bSavePieces) {
   if (!bSavePieces)
     return false;
-  if (m_pLoader && m_pLoader->m_iTotalLines > 0)
-    return m_iLines >= m_pLoader->m_iTotalLines;
+  if (m_pLoader && m_pLoader->iTotalLines > 0)
+    return m_iLines >= m_pLoader->iTotalLines;
   return false;
 }
 
-void CXFA_TextLayout::ProcessText(WideString& wsText) {
-  int32_t iLen = wsText.GetLength();
-  if (iLen == 0)
-    return;
-
-  wchar_t* psz = wsText.GetBuffer(iLen);
-  int32_t iTrimLeft = 0;
-  wchar_t wch = 0, wPrev = 0;
-  for (int32_t i = 0; i < iLen; i++) {
-    wch = psz[i];
-    if (wch < 0x20)
-      wch = 0x20;
-    if (wch == 0x20 && wPrev == 0x20)
-      continue;
-
-    wPrev = wch;
-    psz[iTrimLeft++] = wch;
-  }
-  wsText.ReleaseBuffer(iLen);
-  wsText = wsText.Left(iTrimLeft);
-}
-
 void CXFA_TextLayout::EndBreak(CFX_BreakType dwStatus,
-                               float& fLinePos,
+                               float* pLinePos,
                                bool bSavePieces) {
   dwStatus = m_pBreak->EndBreak(dwStatus);
   if (dwStatus != CFX_BreakType::None && dwStatus != CFX_BreakType::Piece)
-    AppendTextLine(dwStatus, fLinePos, bSavePieces, true);
+    AppendTextLine(dwStatus, pLinePos, bSavePieces, true);
 }
 
 void CXFA_TextLayout::DoTabstops(CFX_CSSComputedStyle* pStyle,
@@ -999,7 +977,7 @@
 }
 
 void CXFA_TextLayout::AppendTextLine(CFX_BreakType dwStatus,
-                                     float& fLinePos,
+                                     float* pLinePos,
                                      bool bSavePieces,
                                      bool bEndBreak) {
   int32_t iPieces = m_pBreak->CountBreakPieces();
@@ -1018,7 +996,7 @@
     int32_t i = 0;
     for (i = 0; i < iPieces; i++) {
       const CFX_BreakPiece* pPiece = m_pBreak->GetBreakPieceUnstable(i);
-      CXFA_TextUserData* pUserData = pPiece->m_pUserData.Get();
+      CFX_TextUserData* pUserData = pPiece->m_pUserData.Get();
       if (pUserData)
         pStyle = pUserData->m_pStyle;
       float fVerScale = pPiece->m_iVerticalScale / 100.0f;
@@ -1035,11 +1013,13 @@
       m_textParser.GetLinethrough(m_pTextProvider, pStyle.Get(),
                                   pTP->iLineThrough);
       pTP->dwColor = m_textParser.GetColor(m_pTextProvider, pStyle.Get());
-      pTP->pFont = m_textParser.GetFont(m_pDoc, m_pTextProvider, pStyle.Get());
+      pTP->pFont =
+          m_textParser.GetFont(m_pDoc.Get(), m_pTextProvider, pStyle.Get());
       pTP->fFontSize = m_textParser.GetFontSize(m_pTextProvider, pStyle.Get());
       pTP->rtPiece.left = pPiece->m_iStartPos / 20000.0f;
       pTP->rtPiece.width = pPiece->m_iWidth / 20000.0f;
-      pTP->rtPiece.height = (float)pPiece->m_iFontSize * fVerScale / 20.0f;
+      pTP->rtPiece.height =
+          static_cast<float>(pPiece->m_iFontSize) * fVerScale / 20.0f;
       float fBaseLineTemp =
           m_textParser.GetBaseline(m_pTextProvider, pStyle.Get());
       pTP->rtPiece.top = fBaseLineTemp;
@@ -1050,10 +1030,6 @@
         float fLineHeightTmp = fBaseLineTemp + pTP->rtPiece.height;
         if (fLineHeight < fLineHeightTmp)
           fLineHeight = fLineHeightTmp;
-        else
-          fBaseLineTemp = 0;
-      } else if (fBaseLine < -fBaseLineTemp) {
-        fBaseLine = -fBaseLineTemp;
       }
       fLineStep = std::max(fLineStep, fLineHeight);
       pTP->pLinkData = pUserData ? pUserData->m_pLinkData : nullptr;
@@ -1063,16 +1039,16 @@
     for (const auto& pTP : pPieceLine->m_textPieces) {
       float& fTop = pTP->rtPiece.top;
       float fBaseLineTemp = fTop;
-      fTop = fLinePos + fLineStep - pTP->rtPiece.height - fBaseLineTemp;
+      fTop = *pLinePos + fLineStep - pTP->rtPiece.height - fBaseLineTemp;
       fTop = std::max(0.0f, fTop);
     }
-    fLinePos += fLineStep + fBaseLine;
+    *pLinePos += fLineStep + fBaseLine;
   } else {
     float fLineStep = 0;
     float fLineWidth = 0;
     for (int32_t i = 0; i < iPieces; i++) {
       const CFX_BreakPiece* pPiece = m_pBreak->GetBreakPieceUnstable(i);
-      CXFA_TextUserData* pUserData = pPiece->m_pUserData.Get();
+      CFX_TextUserData* pUserData = pPiece->m_pUserData.Get();
       if (pUserData)
         pStyle = pUserData->m_pStyle;
       float fVerScale = pPiece->m_iVerticalScale / 100.0f;
@@ -1081,7 +1057,8 @@
           m_pTextProvider, pStyle.Get(), m_iLines == 0, fVerScale);
       if (fBaseLine > 0) {
         float fLineHeightTmp =
-            fBaseLine + (float)pPiece->m_iFontSize * fVerScale / 20.0f;
+            fBaseLine +
+            static_cast<float>(pPiece->m_iFontSize) * fVerScale / 20.0f;
         if (fLineHeight < fLineHeightTmp) {
           fLineHeight = fLineHeightTmp;
         }
@@ -1089,12 +1066,12 @@
       fLineStep = std::max(fLineStep, fLineHeight);
       fLineWidth += pPiece->m_iWidth / 20000.0f;
     }
-    fLinePos += fLineStep;
+    *pLinePos += fLineStep;
     m_fMaxWidth = std::max(m_fMaxWidth, fLineWidth);
-    if (m_pLoader && m_pLoader->m_bSaveLineHeight) {
-      float fHeight = fLinePos - m_pLoader->m_fLastPos;
-      m_pLoader->m_fLastPos = fLinePos;
-      m_pLoader->m_lineHeights.push_back(fHeight);
+    if (m_pLoader && m_pLoader->bSaveLineHeight) {
+      float fHeight = *pLinePos - m_pLoader->fLastPos;
+      m_pLoader->fLastPos = *pLinePos;
+      m_pLoader->lineHeights.push_back(fHeight);
     }
   }
 
@@ -1114,7 +1091,7 @@
           fSpaceBelow = 0;
 
         m_pBreak->SetLineStartPos(fStartPos);
-        fLinePos += fSpaceBelow;
+        *pLinePos += fSpaceBelow;
       }
     }
   }
@@ -1136,60 +1113,63 @@
 
 void CXFA_TextLayout::RenderString(CFX_RenderDevice* pDevice,
                                    CXFA_PieceLine* pPieceLine,
-                                   int32_t iPiece,
-                                   FXTEXT_CHARPOS* pCharPos,
-                                   const CFX_Matrix& tmDoc2Device) {
-  const CXFA_TextPiece* pPiece = pPieceLine->m_textPieces[iPiece].get();
-  int32_t iCount = GetDisplayPos(pPiece, pCharPos);
-  if (iCount > 0) {
-    CFDE_TextOut::DrawString(pDevice, pPiece->dwColor, pPiece->pFont, pCharPos,
-                             iCount, pPiece->fFontSize, &tmDoc2Device);
+                                   size_t szPiece,
+                                   std::vector<TextCharPos>* pCharPos,
+                                   const CFX_Matrix& mtDoc2Device) {
+  const CXFA_TextPiece* pPiece = pPieceLine->m_textPieces[szPiece].get();
+  size_t szCount = GetDisplayPos(pPiece, pCharPos);
+  if (szCount > 0) {
+    auto span = pdfium::make_span(pCharPos->data(), szCount);
+    CFDE_TextOut::DrawString(pDevice, pPiece->dwColor, pPiece->pFont, span,
+                             pPiece->fFontSize, mtDoc2Device);
   }
-  pPieceLine->m_charCounts.push_back(iCount);
+  pPieceLine->m_charCounts.push_back(szCount);
 }
 
 void CXFA_TextLayout::RenderPath(CFX_RenderDevice* pDevice,
                                  CXFA_PieceLine* pPieceLine,
-                                 int32_t iPiece,
-                                 FXTEXT_CHARPOS* pCharPos,
-                                 const CFX_Matrix& tmDoc2Device) {
-  CXFA_TextPiece* pPiece = pPieceLine->m_textPieces[iPiece].get();
+                                 size_t szPiece,
+                                 std::vector<TextCharPos>* pCharPos,
+                                 const CFX_Matrix& mtDoc2Device) {
+  CXFA_TextPiece* pPiece = pPieceLine->m_textPieces[szPiece].get();
   bool bNoUnderline = pPiece->iUnderline < 1 || pPiece->iUnderline > 2;
   bool bNoLineThrough = pPiece->iLineThrough < 1 || pPiece->iLineThrough > 2;
   if (bNoUnderline && bNoLineThrough)
     return;
 
   CFX_PathData path;
-  int32_t iChars = GetDisplayPos(pPiece, pCharPos);
-  if (iChars > 0) {
-    CFX_PointF pt1, pt2;
-    float fEndY = pCharPos[0].m_Origin.y + 1.05f;
-    if (pPiece->iPeriod == XFA_AttributeEnum::Word) {
+  size_t szChars = GetDisplayPos(pPiece, pCharPos);
+  if (szChars > 0) {
+    CFX_PointF pt1;
+    CFX_PointF pt2;
+    float fEndY = (*pCharPos)[0].m_Origin.y + 1.05f;
+    if (pPiece->iPeriod == XFA_AttributeValue::Word) {
       for (int32_t i = 0; i < pPiece->iUnderline; i++) {
-        for (int32_t j = 0; j < iChars; j++) {
-          pt1.x = pCharPos[j].m_Origin.x;
-          pt2.x =
-              pt1.x + pCharPos[j].m_FontCharWidth * pPiece->fFontSize / 1000.0f;
+        for (size_t j = 0; j < szChars; j++) {
+          pt1.x = (*pCharPos)[j].m_Origin.x;
+          pt2.x = pt1.x +
+                  (*pCharPos)[j].m_FontCharWidth * pPiece->fFontSize / 1000.0f;
           pt1.y = pt2.y = fEndY;
           path.AppendLine(pt1, pt2);
         }
         fEndY += 2.0f;
       }
     } else {
-      pt1.x = pCharPos[0].m_Origin.x;
-      pt2.x =
-          pCharPos[iChars - 1].m_Origin.x +
-          pCharPos[iChars - 1].m_FontCharWidth * pPiece->fFontSize / 1000.0f;
+      pt1.x = (*pCharPos)[0].m_Origin.x;
+      pt2.x = (*pCharPos)[szChars - 1].m_Origin.x +
+              (*pCharPos)[szChars - 1].m_FontCharWidth * pPiece->fFontSize /
+                  1000.0f;
       for (int32_t i = 0; i < pPiece->iUnderline; i++) {
         pt1.y = pt2.y = fEndY;
         path.AppendLine(pt1, pt2);
         fEndY += 2.0f;
       }
     }
-    fEndY = pCharPos[0].m_Origin.y - pPiece->rtPiece.height * 0.25f;
-    pt1.x = pCharPos[0].m_Origin.x;
-    pt2.x = pCharPos[iChars - 1].m_Origin.x +
-            pCharPos[iChars - 1].m_FontCharWidth * pPiece->fFontSize / 1000.0f;
+    fEndY = (*pCharPos)[0].m_Origin.y - pPiece->rtPiece.height * 0.25f;
+    pt1.x = (*pCharPos)[0].m_Origin.x;
+    pt2.x =
+        (*pCharPos)[szChars - 1].m_Origin.x +
+        (*pCharPos)[szChars - 1].m_FontCharWidth * pPiece->fFontSize / 1000.0f;
     for (int32_t i = 0; i < pPiece->iLineThrough; i++) {
       pt1.y = pt2.y = fEndY;
       path.AppendLine(pt1, pt2);
@@ -1197,59 +1177,61 @@
     }
   } else {
     if (bNoLineThrough &&
-        (bNoUnderline || pPiece->iPeriod != XFA_AttributeEnum::All)) {
+        (bNoUnderline || pPiece->iPeriod != XFA_AttributeValue::All)) {
       return;
     }
-    int32_t iCharsTmp = 0;
-    int32_t iPiecePrev = iPiece;
-    int32_t iPieceNext = iPiece;
-    while (iPiecePrev > 0) {
-      iPiecePrev--;
-      iCharsTmp = pPieceLine->m_charCounts[iPiecePrev];
-      if (iCharsTmp > 0)
+    bool bHasCount = false;
+    size_t szPiecePrev = szPiece;
+    size_t szPieceNext = szPiece;
+    while (szPiecePrev > 0) {
+      szPiecePrev--;
+      if (pPieceLine->m_charCounts[szPiecePrev] > 0) {
+        bHasCount = true;
         break;
+      }
     }
-    if (iCharsTmp == 0)
+    if (!bHasCount)
       return;
 
-    iCharsTmp = 0;
-    int32_t iPieces = pdfium::CollectionSize<int32_t>(pPieceLine->m_textPieces);
-    while (iPieceNext < iPieces - 1) {
-      iPieceNext++;
-      iCharsTmp = pPieceLine->m_charCounts[iPieceNext];
-      if (iCharsTmp > 0)
+    bHasCount = false;
+    while (szPieceNext < pPieceLine->m_textPieces.size() - 1) {
+      szPieceNext++;
+      if (pPieceLine->m_charCounts[szPieceNext] > 0) {
+        bHasCount = true;
         break;
+      }
     }
-    if (iCharsTmp == 0)
+    if (!bHasCount)
       return;
 
     float fOrgX = 0.0f;
     float fEndX = 0.0f;
-    pPiece = pPieceLine->m_textPieces[iPiecePrev].get();
-    iChars = GetDisplayPos(pPiece, pCharPos);
-    if (iChars < 1)
+    pPiece = pPieceLine->m_textPieces[szPiecePrev].get();
+    szChars = GetDisplayPos(pPiece, pCharPos);
+    if (szChars < 1)
       return;
 
-    fOrgX = pCharPos[iChars - 1].m_Origin.x +
-            pCharPos[iChars - 1].m_FontCharWidth * pPiece->fFontSize / 1000.0f;
-    pPiece = pPieceLine->m_textPieces[iPieceNext].get();
-    iChars = GetDisplayPos(pPiece, pCharPos);
-    if (iChars < 1)
+    fOrgX =
+        (*pCharPos)[szChars - 1].m_Origin.x +
+        (*pCharPos)[szChars - 1].m_FontCharWidth * pPiece->fFontSize / 1000.0f;
+    pPiece = pPieceLine->m_textPieces[szPieceNext].get();
+    szChars = GetDisplayPos(pPiece, pCharPos);
+    if (szChars < 1)
       return;
 
-    fEndX = pCharPos[0].m_Origin.x;
+    fEndX = (*pCharPos)[0].m_Origin.x;
     CFX_PointF pt1;
     CFX_PointF pt2;
     pt1.x = fOrgX;
     pt2.x = fEndX;
-    float fEndY = pCharPos[0].m_Origin.y + 1.05f;
+    float fEndY = (*pCharPos)[0].m_Origin.y + 1.05f;
     for (int32_t i = 0; i < pPiece->iUnderline; i++) {
       pt1.y = fEndY;
       pt2.y = fEndY;
       path.AppendLine(pt1, pt2);
       fEndY += 2.0f;
     }
-    fEndY = pCharPos[0].m_Origin.y - pPiece->rtPiece.height * 0.25f;
+    fEndY = (*pCharPos)[0].m_Origin.y - pPiece->rtPiece.height * 0.25f;
     for (int32_t i = 0; i < pPiece->iLineThrough; i++) {
       pt1.y = fEndY;
       pt2.y = fEndY;
@@ -1264,35 +1246,12 @@
   graphState.m_LineWidth = 1;
   graphState.m_MiterLimit = 10;
   graphState.m_DashPhase = 0;
-  pDevice->DrawPath(&path, &tmDoc2Device, &graphState, 0, pPiece->dwColor, 0);
+  pDevice->DrawPath(&path, &mtDoc2Device, &graphState, 0, pPiece->dwColor, 0);
 }
 
-int32_t CXFA_TextLayout::GetDisplayPos(const CXFA_TextPiece* pPiece,
-                                       FXTEXT_CHARPOS* pCharPos,
-                                       bool bCharCode) {
-  if (!pPiece)
+size_t CXFA_TextLayout::GetDisplayPos(const CXFA_TextPiece* pPiece,
+                                      std::vector<TextCharPos>* pCharPos) {
+  if (!pPiece || pPiece->iChars < 1)
     return 0;
-
-  FX_RTFTEXTOBJ tr;
-  if (!ToRun(pPiece, &tr))
-    return 0;
-  return m_pBreak->GetDisplayPos(&tr, pCharPos, bCharCode);
-}
-
-bool CXFA_TextLayout::ToRun(const CXFA_TextPiece* pPiece, FX_RTFTEXTOBJ* tr) {
-  int32_t iLength = pPiece->iChars;
-  if (iLength < 1)
-    return false;
-
-  tr->pStr = pPiece->szText;
-  tr->pFont = pPiece->pFont;
-  tr->pRect = &pPiece->rtPiece;
-  tr->pWidths = pPiece->Widths;
-  tr->iLength = iLength;
-  tr->fFontSize = pPiece->fFontSize;
-  tr->iBidiLevel = pPiece->iBidiLevel;
-  tr->wLineBreakChar = L'\n';
-  tr->iVerticalScale = pPiece->iVerScale;
-  tr->iHorizontalScale = pPiece->iHorScale;
-  return true;
+  return m_pBreak->GetDisplayPos(pPiece, pCharPos);
 }
diff --git a/xfa/fxfa/cxfa_textlayout.h b/xfa/fxfa/cxfa_textlayout.h
index 40b64a7..e47475a 100644
--- a/xfa/fxfa/cxfa_textlayout.h
+++ b/xfa/fxfa/cxfa_textlayout.h
@@ -13,51 +13,60 @@
 #include "core/fxcrt/css/cfx_css.h"
 #include "core/fxcrt/fx_coordinates.h"
 #include "core/fxcrt/fx_string.h"
-#include "xfa/fgas/layout/cfx_rtfbreak.h"
+#include "xfa/fgas/layout/cfx_char.h"
 #include "xfa/fxfa/cxfa_textparser.h"
 
 class CFDE_RenderDevice;
 class CFX_CSSComputedStyle;
-class CFX_RenderDevice;
 class CFX_RTFBreak;
+class CFX_RenderDevice;
 class CFX_XMLNode;
-class CXFA_LinkUserData;
-class CXFA_LoaderContext;
+class CFX_LinkUserData;
 class CXFA_Node;
 class CXFA_PieceLine;
 class CXFA_TextPiece;
 class CXFA_TextProvider;
 class CXFA_TextTabstopsContext;
+class TextCharPos;
+struct CXFA_LoaderContext;
+struct FX_RTFTEXTOBJ;
 
 class CXFA_TextLayout {
  public:
-  explicit CXFA_TextLayout(CXFA_FFDoc* doc, CXFA_TextProvider* pTextProvider);
+  CXFA_TextLayout(CXFA_FFDoc* doc, CXFA_TextProvider* pTextProvider);
   ~CXFA_TextLayout();
 
   float GetLayoutHeight();
   float StartLayout(float fWidth);
-  float DoLayout(int32_t iBlockIndex,
-                 float fCalcHeight,
-                 float fContentAreaHeight,
-                 float fTextHeight);
+  float DoLayout(float fTextHeight);
+  float DoSplitLayout(size_t szBlockIndex,
+                      float fCalcHeight,
+                      float fTextHeight);
   float Layout(const CFX_SizeF& size);
 
   CFX_SizeF CalcSize(const CFX_SizeF& minSize, const CFX_SizeF& maxSize);
-  void ItemBlocks(const CFX_RectF& rtText, int32_t iBlockIndex);
+  void ItemBlocks(const CFX_RectF& rtText, size_t szBlockIndex);
   bool DrawString(CFX_RenderDevice* pFxDevice,
-                  const CFX_Matrix& tmDoc2Device,
+                  const CFX_Matrix& mtDoc2Device,
                   const CFX_RectF& rtClip,
-                  int32_t iBlock);
+                  size_t szBlockIndex);
   bool IsLoaded() const { return !m_pieceLines.empty(); }
   void Unload();
+
   const std::vector<std::unique_ptr<CXFA_PieceLine>>* GetPieceLines() const {
     return &m_pieceLines;
   }
 
-  bool m_bHasBlock;
-  std::vector<int32_t> m_Blocks;
+  bool HasBlock() const { return m_bHasBlock; }
+  void ClearBlocks() { m_Blocks.clear(); }
+  void ResetHasBlock() { m_bHasBlock = false; }
 
  private:
+  struct BlockData {
+    size_t szIndex;
+    size_t szLength;
+  };
+
   void GetTextDataNode();
   CFX_XMLNode* GetXMLContainerNode();
   std::unique_ptr<CFX_RTFBreak> CreateBreak(bool bDefault);
@@ -65,64 +74,65 @@
   void InitBreak(CFX_CSSComputedStyle* pStyle,
                  CFX_CSSDisplay eDisplay,
                  float fLineWidth,
-                 CFX_XMLNode* pXMLNode,
+                 const CFX_XMLNode* pXMLNode,
                  CFX_CSSComputedStyle* pParentStyle);
-  bool Loader(float textWidth, float& fLinePos, bool bSavePieces);
+  void Loader(float textWidth, float* pLinePos, bool bSavePieces);
   void LoadText(CXFA_Node* pNode,
                 float textWidth,
-                float& fLinePos,
+                float* pLinePos,
                 bool bSavePieces);
-  bool LoadRichText(CFX_XMLNode* pXMLNode,
+  bool LoadRichText(const CFX_XMLNode* pXMLNode,
                     float textWidth,
-                    float& fLinePos,
+                    float* pLinePos,
                     const RetainPtr<CFX_CSSComputedStyle>& pParentStyle,
                     bool bSavePieces,
-                    RetainPtr<CXFA_LinkUserData> pLinkData,
-                    bool bEndBreak = true,
-                    bool bIsOl = false,
-                    int32_t iLiCount = 0);
+                    RetainPtr<CFX_LinkUserData> pLinkData,
+                    bool bEndBreak,
+                    bool bIsOl,
+                    int32_t iLiCount);
   bool AppendChar(const WideString& wsText,
-                  float& fLinePos,
+                  float* pLinePos,
                   float fSpaceAbove,
                   bool bSavePieces);
   void AppendTextLine(CFX_BreakType dwStatus,
-                      float& fLinePos,
+                      float* pLinePos,
                       bool bSavePieces,
-                      bool bEndBreak = false);
-  void EndBreak(CFX_BreakType dwStatus, float& fLinePos, bool bDefault);
+                      bool bEndBreak);
+  void EndBreak(CFX_BreakType dwStatus, float* pLinePos, bool bDefault);
   bool IsEnd(bool bSavePieces);
-  void ProcessText(WideString& wsText);
   void UpdateAlign(float fHeight, float fBottom);
   void RenderString(CFX_RenderDevice* pDevice,
                     CXFA_PieceLine* pPieceLine,
-                    int32_t iPiece,
-                    FXTEXT_CHARPOS* pCharPos,
-                    const CFX_Matrix& tmDoc2Device);
+                    size_t szPiece,
+                    std::vector<TextCharPos>* pCharPos,
+                    const CFX_Matrix& mtDoc2Device);
   void RenderPath(CFX_RenderDevice* pDevice,
                   CXFA_PieceLine* pPieceLine,
-                  int32_t iPiece,
-                  FXTEXT_CHARPOS* pCharPos,
-                  const CFX_Matrix& tmDoc2Device);
-  int32_t GetDisplayPos(const CXFA_TextPiece* pPiece,
-                        FXTEXT_CHARPOS* pCharPos,
-                        bool bCharCode = false);
-  bool ToRun(const CXFA_TextPiece* pPiece, FX_RTFTEXTOBJ* tr);
+                  size_t szPiece,
+                  std::vector<TextCharPos>* pCharPos,
+                  const CFX_Matrix& mtDoc2Device);
+  size_t GetDisplayPos(const CXFA_TextPiece* pPiece,
+                       std::vector<TextCharPos>* pCharPos);
   void DoTabstops(CFX_CSSComputedStyle* pStyle, CXFA_PieceLine* pPieceLine);
-  bool Layout(int32_t iBlock);
-  int32_t CountBlocks() const;
+  bool LayoutInternal(size_t szBlockIndex);
+  size_t CountBlocks() const;
+  size_t GetNextIndexFromLastBlockData() const;
+  void UpdateLoaderHeight(float fTextHeight);
 
-  CXFA_FFDoc* m_pDoc;
-  CXFA_TextProvider* m_pTextProvider;
-  CXFA_Node* m_pTextDataNode;
-  bool m_bRichText;
+  bool m_bHasBlock = false;
+  bool m_bRichText = false;
+  bool m_bBlockContinue = true;
+  int32_t m_iLines = 0;
+  float m_fMaxWidth = 0;
+  std::vector<BlockData> m_Blocks;
+  UnownedPtr<CXFA_FFDoc> const m_pDoc;
+  CXFA_TextProvider* const m_pTextProvider;  // Raw, owned by tree node.
+  CXFA_Node* m_pTextDataNode = nullptr;      // Raw, owned by tree node.
   std::unique_ptr<CFX_RTFBreak> m_pBreak;
   std::unique_ptr<CXFA_LoaderContext> m_pLoader;
-  int32_t m_iLines;
-  float m_fMaxWidth;
   CXFA_TextParser m_textParser;
   std::vector<std::unique_ptr<CXFA_PieceLine>> m_pieceLines;
   std::unique_ptr<CXFA_TextTabstopsContext> m_pTabstopContext;
-  bool m_bBlockContinue;
 };
 
 #endif  // XFA_FXFA_CXFA_TEXTLAYOUT_H_
diff --git a/xfa/fxfa/cxfa_textparsecontext.h b/xfa/fxfa/cxfa_textparsecontext.h
index 20d914b..a146d40 100644
--- a/xfa/fxfa/cxfa_textparsecontext.h
+++ b/xfa/fxfa/cxfa_textparsecontext.h
@@ -12,7 +12,6 @@
 
 #include "core/fxcrt/css/cfx_css.h"
 #include "core/fxcrt/css/cfx_cssdeclaration.h"
-#include "third_party/base/stl_util.h"
 
 class CFX_CSSComputedStyle;
 
diff --git a/xfa/fxfa/cxfa_textparser.cpp b/xfa/fxfa/cxfa_textparser.cpp
index 07ba896..61b9a28 100644
--- a/xfa/fxfa/cxfa_textparser.cpp
+++ b/xfa/fxfa/cxfa_textparser.cpp
@@ -17,8 +17,10 @@
 #include "core/fxcrt/fx_codepage.h"
 #include "core/fxcrt/xml/cfx_xmlelement.h"
 #include "core/fxcrt/xml/cfx_xmlnode.h"
+#include "core/fxge/fx_font.h"
 #include "third_party/base/ptr_util.h"
 #include "xfa/fgas/font/cfgas_fontmgr.h"
+#include "xfa/fgas/font/cfgas_gefont.h"
 #include "xfa/fxfa/cxfa_ffapp.h"
 #include "xfa/fxfa/cxfa_ffdoc.h"
 #include "xfa/fxfa/cxfa_fontmgr.h"
@@ -41,6 +43,18 @@
   Location,
 };
 
+WideString GetLowerCaseElementAttributeOrDefault(
+    const CFX_XMLElement* pElement,
+    const WideString& wsName,
+    const WideString& wsDefaultValue) {
+  WideString ws = pElement->GetAttribute(wsName);
+  if (ws.IsEmpty())
+    ws = wsDefaultValue;
+  else
+    ws.MakeLower();
+  return ws;
+}
+
 }  // namespace
 
 CXFA_TextParser::CXFA_TextParser()
@@ -74,20 +88,22 @@
 }
 
 std::unique_ptr<CFX_CSSStyleSheet> CXFA_TextParser::LoadDefaultSheetStyle() {
-  static const wchar_t s_pStyle[] =
-      L"html,body,ol,p,ul{display:block}"
-      L"li{display:list-item}"
-      L"ol,ul{padding-left:33px;margin:1.12em 0}"
-      L"ol{list-style-type:decimal}"
-      L"a{color:#0000ff;text-decoration:underline}"
-      L"b{font-weight:bolder}"
-      L"i{font-style:italic}"
-      L"sup{vertical-align:+15em;font-size:.66em}"
-      L"sub{vertical-align:-15em;font-size:.66em}";
-
+  static const char kStyle[] =
+      "html,body,ol,p,ul{display:block}"
+      "li{display:list-item}"
+      "ol,ul{padding-left:33px;margin:1.12em 0}"
+      "ol{list-style-type:decimal}"
+      "a{color:#0000ff;text-decoration:underline}"
+      "b{font-weight:bolder}"
+      "i{font-style:italic}"
+      "sup{vertical-align:+15em;font-size:.66em}"
+      "sub{vertical-align:-15em;font-size:.66em}";
+  WideString ws = WideString::FromASCII(kStyle);
   auto sheet = pdfium::MakeUnique<CFX_CSSStyleSheet>();
-  return sheet->LoadBuffer(s_pStyle, wcslen(s_pStyle)) ? std::move(sheet)
-                                                       : nullptr;
+  if (!sheet->LoadBuffer(ws.c_str(), ws.GetLength()))
+    return nullptr;
+
+  return sheet;
 }
 
 RetainPtr<CFX_CSSComputedStyle> CXFA_TextParser::CreateRootStyle(
@@ -104,20 +120,20 @@
     pStyle->SetTextIndent(indent);
     CFX_CSSTextAlign hAlign = CFX_CSSTextAlign::Left;
     switch (para->GetHorizontalAlign()) {
-      case XFA_AttributeEnum::Center:
+      case XFA_AttributeValue::Center:
         hAlign = CFX_CSSTextAlign::Center;
         break;
-      case XFA_AttributeEnum::Right:
+      case XFA_AttributeValue::Right:
         hAlign = CFX_CSSTextAlign::Right;
         break;
-      case XFA_AttributeEnum::Justify:
+      case XFA_AttributeValue::Justify:
         hAlign = CFX_CSSTextAlign::Justify;
         break;
-      case XFA_AttributeEnum::JustifyAll:
+      case XFA_AttributeValue::JustifyAll:
         hAlign = CFX_CSSTextAlign::JustifyAll;
         break;
-      case XFA_AttributeEnum::Left:
-      case XFA_AttributeEnum::Radix:
+      case XFA_AttributeValue::Left:
+      case XFA_AttributeValue::Radix:
         break;
       default:
         NOTREACHED();
@@ -180,7 +196,7 @@
 }
 
 RetainPtr<CFX_CSSComputedStyle> CXFA_TextParser::ComputeStyle(
-    CFX_XMLNode* pXMLNode,
+    const CFX_XMLNode* pXMLNode,
     CFX_CSSComputedStyle* pParentStyle) {
   auto it = m_mapXMLNodeToParseContext.find(pXMLNode);
   if (it == m_mapXMLNodeToParseContext.end())
@@ -203,7 +219,7 @@
   return pStyle;
 }
 
-void CXFA_TextParser::DoParse(CFX_XMLNode* pXMLContainer,
+void CXFA_TextParser::DoParse(const CFX_XMLNode* pXMLContainer,
                               CXFA_TextProvider* pTextProvider) {
   if (!pXMLContainer || !pTextProvider || m_bParsed)
     return;
@@ -214,7 +230,7 @@
   ParseRichText(pXMLContainer, pRootStyle.Get());
 }
 
-void CXFA_TextParser::ParseRichText(CFX_XMLNode* pXMLNode,
+void CXFA_TextParser::ParseRichText(const CFX_XMLNode* pXMLNode,
                                     CFX_CSSComputedStyle* pParentStyle) {
   if (!pXMLNode)
     return;
@@ -224,8 +240,8 @@
     return;
 
   RetainPtr<CFX_CSSComputedStyle> pNewStyle;
-  if ((tagProvider->GetTagName() != L"body") ||
-      (tagProvider->GetTagName() != L"html")) {
+  if (!(tagProvider->GetTagName().EqualsASCII("body") &&
+        tagProvider->GetTagName().EqualsASCII("html"))) {
     auto pTextContext = pdfium::MakeUnique<CXFA_TextParseContext>();
     CFX_CSSDisplay eDisplay = CFX_CSSDisplay::Inline;
     if (!tagProvider->m_bContent) {
@@ -245,9 +261,8 @@
     m_mapXMLNodeToParseContext[pXMLNode] = std::move(pTextContext);
   }
 
-  for (CFX_XMLNode* pXMLChild = pXMLNode->GetNodeItem(CFX_XMLNode::FirstChild);
-       pXMLChild;
-       pXMLChild = pXMLChild->GetNodeItem(CFX_XMLNode::NextSibling)) {
+  for (CFX_XMLNode* pXMLChild = pXMLNode->GetFirstChild(); pXMLChild;
+       pXMLChild = pXMLChild->GetNextSibling()) {
     ParseRichText(pXMLChild, pNewStyle.Get());
   }
 }
@@ -268,60 +283,56 @@
       0xb182eaae,  // body
       0xdb8ac455,  // html
   };
-  static const int32_t s_iCount = FX_ArraySize(s_XFATagName);
-
-  return std::binary_search(s_XFATagName, s_XFATagName + s_iCount,
+  return std::binary_search(std::begin(s_XFATagName), std::end(s_XFATagName),
                             FX_HashCode_GetW(wsName.AsStringView(), true));
 }
 
+// static
 std::unique_ptr<CXFA_TextParser::TagProvider> CXFA_TextParser::ParseTagInfo(
-    CFX_XMLNode* pXMLNode) {
+    const CFX_XMLNode* pXMLNode) {
   auto tagProvider = pdfium::MakeUnique<TagProvider>();
-
-  WideString wsName;
-  if (pXMLNode->GetType() == FX_XMLNODE_Element) {
-    CFX_XMLElement* pXMLElement = static_cast<CFX_XMLElement*>(pXMLNode);
-    wsName = pXMLElement->GetLocalTagName();
+  const CFX_XMLElement* pXMLElement = ToXMLElement(pXMLNode);
+  if (pXMLElement) {
+    WideString wsName = pXMLElement->GetLocalTagName();
     tagProvider->SetTagName(wsName);
     tagProvider->m_bTagAvailable = TagValidate(wsName);
-
-    WideString wsValue = pXMLElement->GetString(L"style");
+    WideString wsValue = pXMLElement->GetAttribute(L"style");
     if (!wsValue.IsEmpty())
       tagProvider->SetAttribute(L"style", wsValue);
-  } else if (pXMLNode->GetType() == FX_XMLNODE_Text) {
+
+    return tagProvider;
+  }
+  if (pXMLNode->GetType() == CFX_XMLNode::Type::kText) {
     tagProvider->m_bTagAvailable = true;
     tagProvider->m_bContent = true;
   }
   return tagProvider;
 }
 
-XFA_AttributeEnum CXFA_TextParser::GetVAlign(
+XFA_AttributeValue CXFA_TextParser::GetVAlign(
     CXFA_TextProvider* pTextProvider) const {
   CXFA_Para* para = pTextProvider->GetParaIfExists();
-  return para ? para->GetVerticalAlign() : XFA_AttributeEnum::Top;
+  return para ? para->GetVerticalAlign() : XFA_AttributeValue::Top;
 }
 
 float CXFA_TextParser::GetTabInterval(CFX_CSSComputedStyle* pStyle) const {
   WideString wsValue;
-  if (pStyle && pStyle->GetCustomStyle(L"tab-interval", wsValue))
+  if (pStyle && pStyle->GetCustomStyle(L"tab-interval", &wsValue))
     return CXFA_Measurement(wsValue.AsStringView()).ToUnit(XFA_Unit::Pt);
   return 36;
 }
 
 int32_t CXFA_TextParser::CountTabs(CFX_CSSComputedStyle* pStyle) const {
   WideString wsValue;
-  if (pStyle && pStyle->GetCustomStyle(L"xfa-tab-count", wsValue))
+  if (pStyle && pStyle->GetCustomStyle(L"xfa-tab-count", &wsValue))
     return wsValue.GetInteger();
   return 0;
 }
 
 bool CXFA_TextParser::IsSpaceRun(CFX_CSSComputedStyle* pStyle) const {
   WideString wsValue;
-  if (pStyle && pStyle->GetCustomStyle(L"xfa-spacerun", wsValue)) {
-    wsValue.MakeLower();
-    return wsValue == L"yes";
-  }
-  return false;
+  return pStyle && pStyle->GetCustomStyle(L"xfa-spacerun", &wsValue) &&
+         wsValue.EqualsASCIINoCase("yes");
 }
 
 RetainPtr<CFGAS_GEFont> CXFA_TextParser::GetFont(
@@ -334,9 +345,9 @@
   if (font) {
     wsFamily = font->GetTypeface();
     if (font->IsBold())
-      dwStyle |= FXFONT_BOLD;
+      dwStyle |= FXFONT_FORCE_BOLD;
     if (font->IsItalic())
-      dwStyle |= FXFONT_BOLD;
+      dwStyle |= FXFONT_FORCE_BOLD;
   }
 
   if (pStyle) {
@@ -346,7 +357,7 @@
 
     dwStyle = 0;
     if (pStyle->GetFontWeight() > FXFONT_FW_NORMAL)
-      dwStyle |= FXFONT_BOLD;
+      dwStyle |= FXFONT_FORCE_BOLD;
     if (pStyle->GetFontStyle() == CFX_CSSFontStyle::Italic)
       dwStyle |= FXFONT_ITALIC;
   }
@@ -366,10 +377,10 @@
 
 int32_t CXFA_TextParser::GetHorScale(CXFA_TextProvider* pTextProvider,
                                      CFX_CSSComputedStyle* pStyle,
-                                     CFX_XMLNode* pXMLNode) const {
+                                     const CFX_XMLNode* pXMLNode) const {
   if (pStyle) {
     WideString wsValue;
-    if (pStyle->GetCustomStyle(L"xfa-font-horizontal-scale", wsValue))
+    if (pStyle->GetCustomStyle(L"xfa-font-horizontal-scale", &wsValue))
       return wsValue.GetInteger();
 
     while (pXMLNode) {
@@ -378,11 +389,11 @@
         CXFA_TextParseContext* pContext = it->second.get();
         if (pContext && pContext->m_pParentStyle &&
             pContext->m_pParentStyle->GetCustomStyle(
-                L"xfa-font-horizontal-scale", wsValue)) {
+                L"xfa-font-horizontal-scale", &wsValue)) {
           return wsValue.GetInteger();
         }
       }
-      pXMLNode = pXMLNode->GetNodeItem(CFX_XMLNode::Parent);
+      pXMLNode = pXMLNode->GetParent();
     }
   }
 
@@ -394,7 +405,7 @@
                                      CFX_CSSComputedStyle* pStyle) const {
   if (pStyle) {
     WideString wsValue;
-    if (pStyle->GetCustomStyle(L"xfa-font-vertical-scale", wsValue))
+    if (pStyle->GetCustomStyle(L"xfa-font-vertical-scale", &wsValue))
       return wsValue.GetInteger();
   }
 
@@ -405,9 +416,9 @@
 void CXFA_TextParser::GetUnderline(CXFA_TextProvider* pTextProvider,
                                    CFX_CSSComputedStyle* pStyle,
                                    int32_t& iUnderline,
-                                   XFA_AttributeEnum& iPeriod) const {
+                                   XFA_AttributeValue& iPeriod) const {
   iUnderline = 0;
-  iPeriod = XFA_AttributeEnum::All;
+  iPeriod = XFA_AttributeValue::All;
   CXFA_Font* font = pTextProvider->GetFontIfExists();
   if (!pStyle) {
     if (font) {
@@ -424,9 +435,9 @@
     iUnderline = 1;
 
   WideString wsValue;
-  if (pStyle->GetCustomStyle(L"underlinePeriod", wsValue)) {
-    if (wsValue == L"word")
-      iPeriod = XFA_AttributeEnum::Word;
+  if (pStyle->GetCustomStyle(L"underlinePeriod", &wsValue)) {
+    if (wsValue.EqualsASCII("word"))
+      iPeriod = XFA_AttributeValue::Word;
   } else if (font) {
     iPeriod = font->GetUnderlinePeriod();
   }
@@ -435,9 +446,11 @@
 void CXFA_TextParser::GetLinethrough(CXFA_TextProvider* pTextProvider,
                                      CFX_CSSComputedStyle* pStyle,
                                      int32_t& iLinethrough) const {
+  iLinethrough = 0;
   if (pStyle) {
     uint32_t dwDecoration = pStyle->GetTextDecoration();
-    iLinethrough = (dwDecoration & CFX_CSSTEXTDECORATION_LineThrough) ? 1 : 0;
+    if (dwDecoration & CFX_CSSTEXTDECORATION_LineThrough)
+      iLinethrough = 1;
     return;
   }
 
@@ -494,49 +507,38 @@
   return fLineHeight;
 }
 
-bool CXFA_TextParser::GetEmbbedObj(CXFA_TextProvider* pTextProvider,
-                                   CFX_XMLNode* pXMLNode,
-                                   WideString& wsValue) {
-  wsValue.clear();
+Optional<WideString> CXFA_TextParser::GetEmbeddedObj(
+    const CXFA_TextProvider* pTextProvider,
+    const CFX_XMLNode* pXMLNode) {
   if (!pXMLNode)
-    return false;
+    return {};
 
-  bool bRet = false;
-  if (pXMLNode->GetType() == FX_XMLNODE_Element) {
-    CFX_XMLElement* pElement = static_cast<CFX_XMLElement*>(pXMLNode);
-    WideString wsAttr = pElement->GetString(L"xfa:embed");
-    if (wsAttr.IsEmpty())
-      return false;
-    if (wsAttr[0] == L'#')
-      wsAttr.Delete(0);
+  const CFX_XMLElement* pElement = ToXMLElement(pXMLNode);
+  if (!pElement)
+    return {};
 
-    WideString ws = pElement->GetString(L"xfa:embedType");
-    if (ws.IsEmpty())
-      ws = L"som";
-    else
-      ws.MakeLower();
+  WideString wsAttr = pElement->GetAttribute(L"xfa:embed");
+  if (wsAttr.IsEmpty())
+    return {};
 
-    bool bURI = (ws == L"uri");
-    if (!bURI && ws != L"som")
-      return false;
+  if (wsAttr[0] == L'#')
+    wsAttr.Delete(0);
 
-    ws = pElement->GetString(L"xfa:embedMode");
-    if (ws.IsEmpty())
-      ws = L"formatted";
-    else
-      ws.MakeLower();
+  WideString ws =
+      GetLowerCaseElementAttributeOrDefault(pElement, L"xfa:embedType", L"som");
+  if (!ws.EqualsASCII("uri"))
+    return {};
 
-    bool bRaw = (ws == L"raw");
-    if (!bRaw && ws != L"formatted")
-      return false;
+  ws = GetLowerCaseElementAttributeOrDefault(pElement, L"xfa:embedMode",
+                                             L"formatted");
+  if (!(ws.EqualsASCII("raw") || ws.EqualsASCII("formatted")))
+    return {};
 
-    bRet = pTextProvider->GetEmbbedObj(bURI, bRaw, wsAttr, wsValue);
-  }
-  return bRet;
+  return pTextProvider->GetEmbeddedObj(wsAttr);
 }
 
 CXFA_TextParseContext* CXFA_TextParser::GetParseContextFromMap(
-    CFX_XMLNode* pXMLNode) {
+    const CFX_XMLNode* pXMLNode) {
   auto it = m_mapXMLNodeToParseContext.find(pXMLNode);
   return it != m_mapXMLNodeToParseContext.end() ? it->second.get() : nullptr;
 }
@@ -547,20 +549,18 @@
     return false;
 
   WideString wsValue;
-  if (!pStyle->GetCustomStyle(L"xfa-tab-stops", wsValue) &&
-      !pStyle->GetCustomStyle(L"tab-stops", wsValue)) {
+  if (!pStyle->GetCustomStyle(L"xfa-tab-stops", &wsValue) &&
+      !pStyle->GetCustomStyle(L"tab-stops", &wsValue)) {
     return false;
   }
 
-  int32_t iLength = wsValue.GetLength();
-  const wchar_t* pTabStops = wsValue.c_str();
-  int32_t iCur = 0;
-  int32_t iLast = 0;
+  pdfium::span<const wchar_t> spTabStops = wsValue.span();
+  size_t iCur = 0;
+  size_t iLast = 0;
   WideString wsAlign;
   TabStopStatus eStatus = TabStopStatus::None;
-  wchar_t ch;
-  while (iCur < iLength) {
-    ch = pTabStops[iCur];
+  while (iCur < spTabStops.size()) {
+    wchar_t ch = spTabStops[iCur];
     switch (eStatus) {
       case TabStopStatus::None:
         if (ch <= ' ') {
@@ -572,10 +572,10 @@
         break;
       case TabStopStatus::Alignment:
         if (ch == ' ') {
-          wsAlign = WideStringView(pTabStops + iLast, iCur - iLast);
+          wsAlign = WideStringView(spTabStops.subspan(iLast, iCur - iLast));
           eStatus = TabStopStatus::StartLeader;
           iCur++;
-          while (iCur < iLength && pTabStops[iCur] <= ' ')
+          while (iCur < spTabStops.size() && spTabStops[iCur] <= ' ')
             iCur++;
           iLast = iCur;
         } else {
@@ -587,8 +587,8 @@
           eStatus = TabStopStatus::Location;
         } else {
           int32_t iCount = 0;
-          while (iCur < iLength) {
-            ch = pTabStops[iCur];
+          while (iCur < spTabStops.size()) {
+            ch = spTabStops[iCur];
             iCur++;
             if (ch == '(') {
               iCount++;
@@ -598,7 +598,7 @@
                 break;
             }
           }
-          while (iCur < iLength && pTabStops[iCur] <= ' ')
+          while (iCur < spTabStops.size() && spTabStops[iCur] <= ' ')
             iCur++;
 
           iLast = iCur;
@@ -608,7 +608,8 @@
       case TabStopStatus::Location:
         if (ch == ' ') {
           uint32_t dwHashCode = FX_HashCode_GetW(wsAlign.AsStringView(), true);
-          CXFA_Measurement ms(WideStringView(pTabStops + iLast, iCur - iLast));
+          CXFA_Measurement ms(
+              WideStringView(spTabStops.subspan(iLast, iCur - iLast)));
           float fPos = ms.ToUnit(XFA_Unit::Pt);
           pTabstopContext->Append(dwHashCode, fPos);
           wsAlign.clear();
@@ -623,7 +624,8 @@
 
   if (!wsAlign.IsEmpty()) {
     uint32_t dwHashCode = FX_HashCode_GetW(wsAlign.AsStringView(), true);
-    CXFA_Measurement ms(WideStringView(pTabStops + iLast, iCur - iLast));
+    CXFA_Measurement ms(
+        WideStringView(spTabStops.subspan(iLast, iCur - iLast)));
     float fPos = ms.ToUnit(XFA_Unit::Pt);
     pTabstopContext->Append(dwHashCode, fPos);
   }
diff --git a/xfa/fxfa/cxfa_textparser.h b/xfa/fxfa/cxfa_textparser.h
index cd2856e..b1e5878 100644
--- a/xfa/fxfa/cxfa_textparser.h
+++ b/xfa/fxfa/cxfa_textparser.h
@@ -14,6 +14,7 @@
 #include "core/fxcrt/fx_system.h"
 #include "core/fxcrt/retain_ptr.h"
 #include "core/fxge/fx_dib.h"
+#include "third_party/base/optional.h"
 #include "xfa/fxfa/fxfa_basic.h"
 
 class CFGAS_GEFont;
@@ -32,17 +33,18 @@
   virtual ~CXFA_TextParser();
 
   void Reset();
-  void DoParse(CFX_XMLNode* pXMLContainer, CXFA_TextProvider* pTextProvider);
+  void DoParse(const CFX_XMLNode* pXMLContainer,
+               CXFA_TextProvider* pTextProvider);
 
   RetainPtr<CFX_CSSComputedStyle> CreateRootStyle(
       CXFA_TextProvider* pTextProvider);
   RetainPtr<CFX_CSSComputedStyle> ComputeStyle(
-      CFX_XMLNode* pXMLNode,
+      const CFX_XMLNode* pXMLNode,
       CFX_CSSComputedStyle* pParentStyle);
 
   bool IsParsed() const { return m_bParsed; }
 
-  XFA_AttributeEnum GetVAlign(CXFA_TextProvider* pTextProvider) const;
+  XFA_AttributeValue GetVAlign(CXFA_TextProvider* pTextProvider) const;
 
   float GetTabInterval(CFX_CSSComputedStyle* pStyle) const;
   int32_t CountTabs(CFX_CSSComputedStyle* pStyle) const;
@@ -59,14 +61,14 @@
 
   int32_t GetHorScale(CXFA_TextProvider* pTextProvider,
                       CFX_CSSComputedStyle* pStyle,
-                      CFX_XMLNode* pXMLNode) const;
+                      const CFX_XMLNode* pXMLNode) const;
   int32_t GetVerScale(CXFA_TextProvider* pTextProvider,
                       CFX_CSSComputedStyle* pStyle) const;
 
   void GetUnderline(CXFA_TextProvider* pTextProvider,
                     CFX_CSSComputedStyle* pStyle,
                     int32_t& iUnderline,
-                    XFA_AttributeEnum& iPeriod) const;
+                    XFA_AttributeValue& iPeriod) const;
   void GetLinethrough(CXFA_TextProvider* pTextProvider,
                       CFX_CSSComputedStyle* pStyle,
                       int32_t& iLinethrough) const;
@@ -79,10 +81,9 @@
                       bool bFirst,
                       float fVerScale) const;
 
-  bool GetEmbbedObj(CXFA_TextProvider* pTextProvider,
-                    CFX_XMLNode* pXMLNode,
-                    WideString& wsValue);
-  CXFA_TextParseContext* GetParseContextFromMap(CFX_XMLNode* pXMLNode);
+  Optional<WideString> GetEmbeddedObj(const CXFA_TextProvider* pTextProvider,
+                                      const CFX_XMLNode* pXMLNode);
+  CXFA_TextParseContext* GetParseContextFromMap(const CFX_XMLNode* pXMLNode);
 
  protected:
   bool TagValidate(const WideString& str) const;
@@ -112,9 +113,12 @@
     std::map<WideString, WideString> m_Attributes;
   };
 
+  // static
+  std::unique_ptr<TagProvider> ParseTagInfo(const CFX_XMLNode* pXMLNode);
+
   void InitCSSData(CXFA_TextProvider* pTextProvider);
-  void ParseRichText(CFX_XMLNode* pXMLNode, CFX_CSSComputedStyle* pParentStyle);
-  std::unique_ptr<TagProvider> ParseTagInfo(CFX_XMLNode* pXMLNode);
+  void ParseRichText(const CFX_XMLNode* pXMLNode,
+                     CFX_CSSComputedStyle* pParentStyle);
   std::unique_ptr<CFX_CSSStyleSheet> LoadDefaultSheetStyle();
   RetainPtr<CFX_CSSComputedStyle> CreateStyle(
       CFX_CSSComputedStyle* pParentStyle);
@@ -122,7 +126,7 @@
   bool m_bParsed;
   bool m_cssInitialized;
   std::unique_ptr<CFX_CSSStyleSelector> m_pSelector;
-  std::map<CFX_XMLNode*, std::unique_ptr<CXFA_TextParseContext>>
+  std::map<const CFX_XMLNode*, std::unique_ptr<CXFA_TextParseContext>>
       m_mapXMLNodeToParseContext;
 };
 
diff --git a/xfa/fxfa/cxfa_textparser_unittest.cpp b/xfa/fxfa/cxfa_textparser_unittest.cpp
index bd748cd..5198638 100644
--- a/xfa/fxfa/cxfa_textparser_unittest.cpp
+++ b/xfa/fxfa/cxfa_textparser_unittest.cpp
@@ -6,7 +6,7 @@
 
 #include "testing/gtest/include/gtest/gtest.h"
 
-class CXFA_TestTextParser : public CXFA_TextParser {
+class CXFA_TestTextParser final : public CXFA_TextParser {
  public:
   CXFA_TestTextParser() : CXFA_TextParser() {}
 
diff --git a/xfa/fxfa/cxfa_textpiece.cpp b/xfa/fxfa/cxfa_textpiece.cpp
index d6a8d3a..363361a 100644
--- a/xfa/fxfa/cxfa_textpiece.cpp
+++ b/xfa/fxfa/cxfa_textpiece.cpp
@@ -6,9 +6,8 @@
 
 #include "xfa/fxfa/cxfa_textpiece.h"
 
-#include "xfa/fgas/font/cfgas_gefont.h"
-#include "xfa/fxfa/cxfa_linkuserdata.h"
+#include "xfa/fgas/layout/cfx_linkuserdata.h"
 
-CXFA_TextPiece::CXFA_TextPiece() {}
+CXFA_TextPiece::CXFA_TextPiece() = default;
 
-CXFA_TextPiece::~CXFA_TextPiece() {}
+CXFA_TextPiece::~CXFA_TextPiece() = default;
diff --git a/xfa/fxfa/cxfa_textpiece.h b/xfa/fxfa/cxfa_textpiece.h
index f3812f8..c9d524d 100644
--- a/xfa/fxfa/cxfa_textpiece.h
+++ b/xfa/fxfa/cxfa_textpiece.h
@@ -7,35 +7,23 @@
 #ifndef XFA_FXFA_CXFA_TEXTPIECE_H_
 #define XFA_FXFA_CXFA_TEXTPIECE_H_
 
-#include <vector>
-
-#include "core/fxcrt/fx_coordinates.h"
-#include "core/fxcrt/fx_string.h"
+#include "core/fxcrt/retain_ptr.h"
 #include "core/fxge/fx_dib.h"
+#include "xfa/fgas/layout/cfx_textpiece.h"
 #include "xfa/fxfa/fxfa_basic.h"
 
-class CFGAS_GEFont;
-class CXFA_LinkUserData;
+class CFX_LinkUserData;
 
-class CXFA_TextPiece {
+class CXFA_TextPiece : public CFX_TextPiece {
  public:
   CXFA_TextPiece();
   ~CXFA_TextPiece();
 
-  WideString szText;
-  std::vector<int32_t> Widths;
-  int32_t iChars;
-  int32_t iHorScale;
-  int32_t iVerScale;
-  int32_t iBidiLevel;
   int32_t iUnderline;
-  XFA_AttributeEnum iPeriod;
   int32_t iLineThrough;
+  XFA_AttributeValue iPeriod;
   FX_ARGB dwColor;
-  float fFontSize;
-  CFX_RectF rtPiece;
-  RetainPtr<CFGAS_GEFont> pFont;
-  RetainPtr<CXFA_LinkUserData> pLinkData;
+  RetainPtr<CFX_LinkUserData> pLinkData;
 };
 
 #endif  // XFA_FXFA_CXFA_TEXTPIECE_H_
diff --git a/xfa/fxfa/cxfa_textprovider.cpp b/xfa/fxfa/cxfa_textprovider.cpp
index 55da281..7a17037 100644
--- a/xfa/fxfa/cxfa_textprovider.cpp
+++ b/xfa/fxfa/cxfa_textprovider.cpp
@@ -12,11 +12,9 @@
 
 #include "core/fxcrt/xml/cfx_xmlelement.h"
 #include "core/fxcrt/xml/cfx_xmlnode.h"
-#include "fxjs/cfxjse_engine.h"
-#include "fxjs/cfxjse_value.h"
+#include "fxjs/xfa/cfxjse_engine.h"
+#include "fxjs/xfa/cfxjse_value.h"
 #include "fxjs/xfa/cjx_object.h"
-#include "third_party/base/ptr_util.h"
-#include "third_party/base/stl_util.h"
 #include "xfa/fde/cfde_textout.h"
 #include "xfa/fxfa/cxfa_eventparam.h"
 #include "xfa/fxfa/cxfa_ffapp.h"
@@ -31,7 +29,6 @@
 #include "xfa/fxfa/parser/cxfa_caption.h"
 #include "xfa/fxfa/parser/cxfa_font.h"
 #include "xfa/fxfa/parser/cxfa_items.h"
-#include "xfa/fxfa/parser/cxfa_layoutprocessor.h"
 #include "xfa/fxfa/parser/cxfa_localevalue.h"
 #include "xfa/fxfa/parser/cxfa_node.h"
 #include "xfa/fxfa/parser/cxfa_para.h"
@@ -39,13 +36,11 @@
 #include "xfa/fxfa/parser/xfa_resolvenode_rs.h"
 #include "xfa/fxfa/parser/xfa_utils.h"
 
-CXFA_Node* CXFA_TextProvider::GetTextNode(bool& bRichText) {
-  bRichText = false;
-
+CXFA_Node* CXFA_TextProvider::GetTextNode(bool* bRichText) {
+  *bRichText = false;
   if (m_eType == XFA_TEXTPROVIDERTYPE_Text) {
-    CXFA_Node* pElementNode = m_pWidgetAcc->GetNode();
     CXFA_Value* pValueNode =
-        pElementNode->GetChild<CXFA_Value>(0, XFA_Element::Value, false);
+        m_pNode->GetChild<CXFA_Value>(0, XFA_Element::Value, false);
     if (!pValueNode)
       return nullptr;
 
@@ -53,24 +48,23 @@
     if (pChildNode && pChildNode->GetElementType() == XFA_Element::ExData) {
       Optional<WideString> contentType = pChildNode->JSObject()->TryAttribute(
           XFA_Attribute::ContentType, false);
-      if (contentType && *contentType == L"text/html")
-        bRichText = true;
+      if (contentType.has_value() &&
+          contentType.value().EqualsASCII("text/html")) {
+        *bRichText = true;
+      }
     }
     return pChildNode;
   }
 
   if (m_eType == XFA_TEXTPROVIDERTYPE_Datasets) {
-    CXFA_Node* pBind = m_pWidgetAcc->GetNode()->GetBindData();
+    CXFA_Node* pBind = m_pNode->GetBindData();
     CFX_XMLNode* pXMLNode = pBind->GetXMLMappingNode();
-    ASSERT(pXMLNode);
-    for (CFX_XMLNode* pXMLChild =
-             pXMLNode->GetNodeItem(CFX_XMLNode::FirstChild);
-         pXMLChild;
-         pXMLChild = pXMLChild->GetNodeItem(CFX_XMLNode::NextSibling)) {
-      if (pXMLChild->GetType() == FX_XMLNODE_Element) {
-        CFX_XMLElement* pElement = static_cast<CFX_XMLElement*>(pXMLChild);
-        if (XFA_RecognizeRichText(pElement))
-          bRichText = true;
+    for (CFX_XMLNode* pXMLChild = pXMLNode->GetFirstChild(); pXMLChild;
+         pXMLChild = pXMLChild->GetNextSibling()) {
+      CFX_XMLElement* pElement = ToXMLElement(pXMLChild);
+      if (pElement && XFA_RecognizeRichText(pElement)) {
+        *bRichText = true;
+        break;
       }
     }
     return pBind;
@@ -78,8 +72,7 @@
 
   if (m_eType == XFA_TEXTPROVIDERTYPE_Caption) {
     CXFA_Caption* pCaptionNode =
-        m_pWidgetAcc->GetNode()->GetChild<CXFA_Caption>(0, XFA_Element::Caption,
-                                                        false);
+        m_pNode->GetChild<CXFA_Caption>(0, XFA_Element::Caption, false);
     if (!pCaptionNode)
       return nullptr;
 
@@ -92,23 +85,27 @@
     if (pChildNode && pChildNode->GetElementType() == XFA_Element::ExData) {
       Optional<WideString> contentType = pChildNode->JSObject()->TryAttribute(
           XFA_Attribute::ContentType, false);
-      if (contentType && *contentType == L"text/html")
-        bRichText = true;
+      if (contentType.has_value() &&
+          contentType.value().EqualsASCII("text/html")) {
+        *bRichText = true;
+      }
     }
     return pChildNode;
   }
 
-  CXFA_Items* pItemNode = m_pWidgetAcc->GetNode()->GetChild<CXFA_Items>(
-      0, XFA_Element::Items, false);
+  CXFA_Items* pItemNode =
+      m_pNode->GetChild<CXFA_Items>(0, XFA_Element::Items, false);
   if (!pItemNode)
     return nullptr;
 
   CXFA_Node* pNode = pItemNode->GetFirstChild();
   while (pNode) {
     WideString wsName = pNode->JSObject()->GetCData(XFA_Attribute::Name);
-    if (m_eType == XFA_TEXTPROVIDERTYPE_Rollover && wsName == L"rollover")
+    if (m_eType == XFA_TEXTPROVIDERTYPE_Rollover &&
+        wsName.EqualsASCII("rollover")) {
       return pNode;
-    if (m_eType == XFA_TEXTPROVIDERTYPE_Down && wsName == L"down")
+    }
+    if (m_eType == XFA_TEXTPROVIDERTYPE_Down && wsName.EqualsASCII("down"))
       return pNode;
 
     pNode = pNode->GetNextSibling();
@@ -118,45 +115,37 @@
 
 CXFA_Para* CXFA_TextProvider::GetParaIfExists() {
   if (m_eType == XFA_TEXTPROVIDERTYPE_Text)
-    return m_pWidgetAcc->GetNode()->GetParaIfExists();
+    return m_pNode->GetParaIfExists();
 
-  CXFA_Caption* pNode = m_pWidgetAcc->GetNode()->GetChild<CXFA_Caption>(
-      0, XFA_Element::Caption, false);
+  CXFA_Caption* pNode =
+      m_pNode->GetChild<CXFA_Caption>(0, XFA_Element::Caption, false);
   return pNode->GetChild<CXFA_Para>(0, XFA_Element::Para, false);
 }
 
 CXFA_Font* CXFA_TextProvider::GetFontIfExists() {
   if (m_eType == XFA_TEXTPROVIDERTYPE_Text)
-    return m_pWidgetAcc->GetNode()->GetFontIfExists();
+    return m_pNode->GetFontIfExists();
 
-  CXFA_Caption* pNode = m_pWidgetAcc->GetNode()->GetChild<CXFA_Caption>(
-      0, XFA_Element::Caption, false);
+  CXFA_Caption* pNode =
+      m_pNode->GetChild<CXFA_Caption>(0, XFA_Element::Caption, false);
   CXFA_Font* font = pNode->GetChild<CXFA_Font>(0, XFA_Element::Font, false);
-  return font ? font : m_pWidgetAcc->GetNode()->GetFontIfExists();
+  return font ? font : m_pNode->GetFontIfExists();
 }
 
-bool CXFA_TextProvider::IsCheckButtonAndAutoWidth() {
-  XFA_Element eType = m_pWidgetAcc->GetUIType();
-  if (eType != XFA_Element::CheckButton)
+bool CXFA_TextProvider::IsCheckButtonAndAutoWidth() const {
+  if (m_pNode->GetFFWidgetType() != XFA_FFWidgetType::kCheckButton)
     return false;
-  return !m_pWidgetAcc->GetNode()->TryWidth();
+  return !m_pNode->TryWidth();
 }
 
-bool CXFA_TextProvider::GetEmbbedObj(bool bURI,
-                                     bool bRaw,
-                                     const WideString& wsAttr,
-                                     WideString& wsValue) {
+Optional<WideString> CXFA_TextProvider::GetEmbeddedObj(
+    const WideString& wsAttr) const {
   if (m_eType != XFA_TEXTPROVIDERTYPE_Text)
-    return false;
+    return {};
 
-  if (!bURI)
-    return false;
-
-  CXFA_Node* pWidgetNode = m_pWidgetAcc->GetNode();
-  CXFA_Node* pParent = pWidgetNode->GetParent();
-  CXFA_Document* pDocument = pWidgetNode->GetDocument();
+  CXFA_Node* pParent = m_pNode->GetParent();
+  CXFA_Document* pDocument = m_pNode->GetDocument();
   CXFA_Node* pIDNode = nullptr;
-  CXFA_WidgetAcc* pEmbAcc = nullptr;
   if (pParent)
     pIDNode = pDocument->GetNodeByID(pParent, wsAttr.AsStringView());
 
@@ -165,12 +154,8 @@
         ToNode(pDocument->GetXFAObject(XFA_HASHCODE_Form)),
         wsAttr.AsStringView());
   }
-  if (pIDNode)
-    pEmbAcc = pIDNode->GetWidgetAcc();
+  if (!pIDNode || !pIDNode->IsWidgetReady())
+    return {};
 
-  if (!pEmbAcc)
-    return false;
-
-  wsValue = pEmbAcc->GetValue(XFA_VALUEPICTURE_Display);
-  return true;
+  return pIDNode->GetValue(XFA_VALUEPICTURE_Display);
 }
diff --git a/xfa/fxfa/cxfa_textprovider.h b/xfa/fxfa/cxfa_textprovider.h
index 3431c9a..b4a9664 100644
--- a/xfa/fxfa/cxfa_textprovider.h
+++ b/xfa/fxfa/cxfa_textprovider.h
@@ -8,11 +8,12 @@
 #define XFA_FXFA_CXFA_TEXTPROVIDER_H_
 
 #include "core/fxcrt/fx_string.h"
+#include "third_party/base/optional.h"
 #include "xfa/fxfa/cxfa_textlayout.h"
-#include "xfa/fxfa/cxfa_widgetacc.h"
 
 class CXFA_Font;
 class CXFA_Node;
+class CXFA_Para;
 
 enum XFA_TEXTPROVIDERTYPE {
   XFA_TEXTPROVIDERTYPE_Text,
@@ -24,23 +25,20 @@
 
 class CXFA_TextProvider {
  public:
-  CXFA_TextProvider(CXFA_WidgetAcc* pWidgetAcc, XFA_TEXTPROVIDERTYPE eType)
-      : m_pWidgetAcc(pWidgetAcc), m_eType(eType) {
-    ASSERT(m_pWidgetAcc);
+  CXFA_TextProvider(CXFA_Node* pNode, XFA_TEXTPROVIDERTYPE eType)
+      : m_pNode(pNode), m_eType(eType) {
+    ASSERT(m_pNode);
   }
   ~CXFA_TextProvider() {}
 
-  CXFA_Node* GetTextNode(bool& bRichText);
+  CXFA_Node* GetTextNode(bool* bRichText);
   CXFA_Para* GetParaIfExists();
   CXFA_Font* GetFontIfExists();
-  bool IsCheckButtonAndAutoWidth();
-  bool GetEmbbedObj(bool bURI,
-                    bool bRaw,
-                    const WideString& wsAttr,
-                    WideString& wsValue);
+  bool IsCheckButtonAndAutoWidth() const;
+  Optional<WideString> GetEmbeddedObj(const WideString& wsAttr) const;
 
  private:
-  CXFA_WidgetAcc* m_pWidgetAcc;
+  CXFA_Node* m_pNode;  // Raw, this class owned by tree node.
   XFA_TEXTPROVIDERTYPE m_eType;
 };
 
diff --git a/xfa/fxfa/cxfa_textuserdata.h b/xfa/fxfa/cxfa_textuserdata.h
deleted file mode 100644
index c1af217..0000000
--- a/xfa/fxfa/cxfa_textuserdata.h
+++ /dev/null
@@ -1,30 +0,0 @@
-// 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_CXFA_TEXTUSERDATA_H_
-#define XFA_FXFA_CXFA_TEXTUSERDATA_H_
-
-#include "core/fxcrt/retain_ptr.h"
-
-class CFX_CSSComputedStyle;
-class CXFA_LinkUserData;
-
-class CXFA_TextUserData : public Retainable {
- public:
-  template <typename T, typename... Args>
-  friend RetainPtr<T> pdfium::MakeRetain(Args&&... args);
-
-  RetainPtr<CFX_CSSComputedStyle> m_pStyle;
-  RetainPtr<CXFA_LinkUserData> m_pLinkData;
-
- private:
-  explicit CXFA_TextUserData(const RetainPtr<CFX_CSSComputedStyle>& pStyle);
-  CXFA_TextUserData(const RetainPtr<CFX_CSSComputedStyle>& pStyle,
-                    const RetainPtr<CXFA_LinkUserData>& pLinkData);
-  ~CXFA_TextUserData() override;
-};
-
-#endif  // XFA_FXFA_CXFA_TEXTUSERDATA_H_
diff --git a/xfa/fxfa/cxfa_widgetacc.cpp b/xfa/fxfa/cxfa_widgetacc.cpp
deleted file mode 100644
index ad4e08e..0000000
--- a/xfa/fxfa/cxfa_widgetacc.cpp
+++ /dev/null
@@ -1,2757 +0,0 @@
-// 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
-
-#include "xfa/fxfa/cxfa_widgetacc.h"
-
-#include <algorithm>
-#include <tuple>
-#include <vector>
-
-#include "core/fxcrt/cfx_decimal.h"
-#include "core/fxcrt/cfx_memorystream.h"
-#include "core/fxcrt/fx_extension.h"
-#include "core/fxcrt/xml/cfx_xmlelement.h"
-#include "core/fxcrt/xml/cfx_xmlnode.h"
-#include "fxjs/cfxjse_engine.h"
-#include "fxjs/xfa/cjx_object.h"
-#include "third_party/base/stl_util.h"
-#include "xfa/fde/cfde_textout.h"
-#include "xfa/fxfa/cxfa_ffapp.h"
-#include "xfa/fxfa/cxfa_ffdoc.h"
-#include "xfa/fxfa/cxfa_ffdocview.h"
-#include "xfa/fxfa/cxfa_ffnotify.h"
-#include "xfa/fxfa/cxfa_ffwidget.h"
-#include "xfa/fxfa/cxfa_fontmgr.h"
-#include "xfa/fxfa/cxfa_textlayout.h"
-#include "xfa/fxfa/cxfa_textprovider.h"
-#include "xfa/fxfa/parser/cxfa_bind.h"
-#include "xfa/fxfa/parser/cxfa_border.h"
-#include "xfa/fxfa/parser/cxfa_calculate.h"
-#include "xfa/fxfa/parser/cxfa_caption.h"
-#include "xfa/fxfa/parser/cxfa_comb.h"
-#include "xfa/fxfa/parser/cxfa_decimal.h"
-#include "xfa/fxfa/parser/cxfa_document.h"
-#include "xfa/fxfa/parser/cxfa_event.h"
-#include "xfa/fxfa/parser/cxfa_font.h"
-#include "xfa/fxfa/parser/cxfa_format.h"
-#include "xfa/fxfa/parser/cxfa_image.h"
-#include "xfa/fxfa/parser/cxfa_items.h"
-#include "xfa/fxfa/parser/cxfa_layoutprocessor.h"
-#include "xfa/fxfa/parser/cxfa_localevalue.h"
-#include "xfa/fxfa/parser/cxfa_margin.h"
-#include "xfa/fxfa/parser/cxfa_measurement.h"
-#include "xfa/fxfa/parser/cxfa_node.h"
-#include "xfa/fxfa/parser/cxfa_para.h"
-#include "xfa/fxfa/parser/cxfa_picture.h"
-#include "xfa/fxfa/parser/cxfa_script.h"
-#include "xfa/fxfa/parser/cxfa_stroke.h"
-#include "xfa/fxfa/parser/cxfa_ui.h"
-#include "xfa/fxfa/parser/cxfa_validate.h"
-#include "xfa/fxfa/parser/cxfa_value.h"
-#include "xfa/fxfa/parser/xfa_utils.h"
-
-class CXFA_WidgetLayoutData {
- public:
-  CXFA_WidgetLayoutData() : m_fWidgetHeight(-1) {}
-  virtual ~CXFA_WidgetLayoutData() {}
-
-  float m_fWidgetHeight;
-};
-
-namespace {
-
-constexpr uint8_t g_inv_base64[128] = {
-    255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
-    255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
-    255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 62,  255,
-    255, 255, 63,  52,  53,  54,  55,  56,  57,  58,  59,  60,  61,  255, 255,
-    255, 255, 255, 255, 255, 0,   1,   2,   3,   4,   5,   6,   7,   8,   9,
-    10,  11,  12,  13,  14,  15,  16,  17,  18,  19,  20,  21,  22,  23,  24,
-    25,  255, 255, 255, 255, 255, 255, 26,  27,  28,  29,  30,  31,  32,  33,
-    34,  35,  36,  37,  38,  39,  40,  41,  42,  43,  44,  45,  46,  47,  48,
-    49,  50,  51,  255, 255, 255, 255, 255,
-};
-
-uint8_t* XFA_RemoveBase64Whitespace(const uint8_t* pStr, int32_t iLen) {
-  uint8_t* pCP;
-  int32_t i = 0, j = 0;
-  if (iLen == 0) {
-    iLen = strlen((char*)pStr);
-  }
-  pCP = FX_Alloc(uint8_t, iLen + 1);
-  for (; i < iLen; i++) {
-    if ((pStr[i] & 128) == 0) {
-      if (g_inv_base64[pStr[i]] != 0xFF || pStr[i] == '=') {
-        pCP[j++] = pStr[i];
-      }
-    }
-  }
-  pCP[j] = '\0';
-  return pCP;
-}
-
-int32_t XFA_Base64Decode(const char* pStr, uint8_t* pOutBuffer) {
-  if (!pStr) {
-    return 0;
-  }
-  uint8_t* pBuffer =
-      XFA_RemoveBase64Whitespace((uint8_t*)pStr, strlen((char*)pStr));
-  if (!pBuffer) {
-    return 0;
-  }
-  int32_t iLen = strlen((char*)pBuffer);
-  int32_t i = 0, j = 0;
-  uint32_t dwLimb = 0;
-  for (; i + 3 < iLen; i += 4) {
-    if (pBuffer[i] == '=' || pBuffer[i + 1] == '=' || pBuffer[i + 2] == '=' ||
-        pBuffer[i + 3] == '=') {
-      if (pBuffer[i] == '=' || pBuffer[i + 1] == '=') {
-        break;
-      }
-      if (pBuffer[i + 2] == '=') {
-        dwLimb = ((uint32_t)g_inv_base64[pBuffer[i]] << 6) |
-                 ((uint32_t)g_inv_base64[pBuffer[i + 1]]);
-        pOutBuffer[j] = (uint8_t)(dwLimb >> 4) & 0xFF;
-        j++;
-      } else {
-        dwLimb = ((uint32_t)g_inv_base64[pBuffer[i]] << 12) |
-                 ((uint32_t)g_inv_base64[pBuffer[i + 1]] << 6) |
-                 ((uint32_t)g_inv_base64[pBuffer[i + 2]]);
-        pOutBuffer[j] = (uint8_t)(dwLimb >> 10) & 0xFF;
-        pOutBuffer[j + 1] = (uint8_t)(dwLimb >> 2) & 0xFF;
-        j += 2;
-      }
-    } else {
-      dwLimb = ((uint32_t)g_inv_base64[pBuffer[i]] << 18) |
-               ((uint32_t)g_inv_base64[pBuffer[i + 1]] << 12) |
-               ((uint32_t)g_inv_base64[pBuffer[i + 2]] << 6) |
-               ((uint32_t)g_inv_base64[pBuffer[i + 3]]);
-      pOutBuffer[j] = (uint8_t)(dwLimb >> 16) & 0xff;
-      pOutBuffer[j + 1] = (uint8_t)(dwLimb >> 8) & 0xff;
-      pOutBuffer[j + 2] = (uint8_t)(dwLimb)&0xff;
-      j += 3;
-    }
-  }
-  FX_Free(pBuffer);
-  return j;
-}
-
-FXCODEC_IMAGE_TYPE XFA_GetImageType(const WideString& wsType) {
-  WideString wsContentType(wsType);
-  wsContentType.MakeLower();
-  if (wsContentType == L"image/jpg")
-    return FXCODEC_IMAGE_JPG;
-  if (wsContentType == L"image/png")
-    return FXCODEC_IMAGE_PNG;
-  if (wsContentType == L"image/gif")
-    return FXCODEC_IMAGE_GIF;
-  if (wsContentType == L"image/bmp")
-    return FXCODEC_IMAGE_BMP;
-  if (wsContentType == L"image/tif")
-    return FXCODEC_IMAGE_TIF;
-  return FXCODEC_IMAGE_UNKNOWN;
-}
-
-RetainPtr<CFX_DIBitmap> XFA_LoadImageData(CXFA_FFDoc* pDoc,
-                                          CXFA_Image* pImage,
-                                          bool& bNameImage,
-                                          int32_t& iImageXDpi,
-                                          int32_t& iImageYDpi) {
-  WideString wsHref = pImage->GetHref();
-  WideString wsImage = pImage->GetContent();
-  if (wsHref.IsEmpty() && wsImage.IsEmpty())
-    return nullptr;
-
-  FXCODEC_IMAGE_TYPE type = XFA_GetImageType(pImage->GetContentType());
-  ByteString bsContent;
-  uint8_t* pImageBuffer = nullptr;
-  RetainPtr<IFX_SeekableReadStream> pImageFileRead;
-  if (wsImage.GetLength() > 0) {
-    XFA_AttributeEnum iEncoding = pImage->GetTransferEncoding();
-    if (iEncoding == XFA_AttributeEnum::Base64) {
-      ByteString bsData = wsImage.UTF8Encode();
-      int32_t iLength = bsData.GetLength();
-      pImageBuffer = FX_Alloc(uint8_t, iLength);
-      int32_t iRead = XFA_Base64Decode(bsData.c_str(), pImageBuffer);
-      if (iRead > 0) {
-        pImageFileRead =
-            pdfium::MakeRetain<CFX_MemoryStream>(pImageBuffer, iRead, false);
-      }
-    } else {
-      bsContent = ByteString::FromUnicode(wsImage);
-      pImageFileRead = pdfium::MakeRetain<CFX_MemoryStream>(
-          const_cast<uint8_t*>(bsContent.raw_str()), bsContent.GetLength(),
-          false);
-    }
-  } else {
-    WideString wsURL = wsHref;
-    if (wsURL.Left(7) != L"http://" && wsURL.Left(6) != L"ftp://") {
-      RetainPtr<CFX_DIBitmap> pBitmap =
-          pDoc->GetPDFNamedImage(wsURL.AsStringView(), iImageXDpi, iImageYDpi);
-      if (pBitmap) {
-        bNameImage = true;
-        return pBitmap;
-      }
-    }
-    pImageFileRead = pDoc->GetDocEnvironment()->OpenLinkedFile(pDoc, wsURL);
-  }
-  if (!pImageFileRead) {
-    FX_Free(pImageBuffer);
-    return nullptr;
-  }
-  bNameImage = false;
-  RetainPtr<CFX_DIBitmap> pBitmap =
-      XFA_LoadImageFromBuffer(pImageFileRead, type, iImageXDpi, iImageYDpi);
-  FX_Free(pImageBuffer);
-  return pBitmap;
-}
-
-class CXFA_TextLayoutData : public CXFA_WidgetLayoutData {
- public:
-  CXFA_TextLayoutData() {}
-  ~CXFA_TextLayoutData() override {}
-
-  CXFA_TextLayout* GetTextLayout() const { return m_pTextLayout.get(); }
-  CXFA_TextProvider* GetTextProvider() const { return m_pTextProvider.get(); }
-
-  void LoadText(CXFA_FFDoc* doc, CXFA_WidgetAcc* pAcc) {
-    if (m_pTextLayout)
-      return;
-
-    m_pTextProvider =
-        pdfium::MakeUnique<CXFA_TextProvider>(pAcc, XFA_TEXTPROVIDERTYPE_Text);
-    m_pTextLayout =
-        pdfium::MakeUnique<CXFA_TextLayout>(doc, m_pTextProvider.get());
-  }
-
- private:
-  std::unique_ptr<CXFA_TextLayout> m_pTextLayout;
-  std::unique_ptr<CXFA_TextProvider> m_pTextProvider;
-};
-
-class CXFA_ImageLayoutData : public CXFA_WidgetLayoutData {
- public:
-  CXFA_ImageLayoutData()
-      : m_bNamedImage(false), m_iImageXDpi(0), m_iImageYDpi(0) {}
-
-  ~CXFA_ImageLayoutData() override {}
-
-  bool LoadImageData(CXFA_FFDoc* doc, CXFA_WidgetAcc* pAcc) {
-    if (m_pDIBitmap)
-      return true;
-
-    CXFA_Value* value = pAcc->GetNode()->GetFormValueIfExists();
-    if (!value)
-      return false;
-
-    CXFA_Image* image = value->GetImageIfExists();
-    if (!image)
-      return false;
-
-    pAcc->SetImageImage(XFA_LoadImageData(doc, image, m_bNamedImage,
-                                          m_iImageXDpi, m_iImageYDpi));
-    return !!m_pDIBitmap;
-  }
-
-  RetainPtr<CFX_DIBitmap> m_pDIBitmap;
-  bool m_bNamedImage;
-  int32_t m_iImageXDpi;
-  int32_t m_iImageYDpi;
-};
-
-class CXFA_FieldLayoutData : public CXFA_WidgetLayoutData {
- public:
-  CXFA_FieldLayoutData() {}
-  ~CXFA_FieldLayoutData() override {}
-
-  bool LoadCaption(CXFA_FFDoc* doc, CXFA_WidgetAcc* pAcc) {
-    if (m_pCapTextLayout)
-      return true;
-    CXFA_Caption* caption = pAcc->GetNode()->GetCaptionIfExists();
-    if (!caption || caption->IsHidden())
-      return false;
-
-    m_pCapTextProvider = pdfium::MakeUnique<CXFA_TextProvider>(
-        pAcc, XFA_TEXTPROVIDERTYPE_Caption);
-    m_pCapTextLayout =
-        pdfium::MakeUnique<CXFA_TextLayout>(doc, m_pCapTextProvider.get());
-    return true;
-  }
-
-  std::unique_ptr<CXFA_TextLayout> m_pCapTextLayout;
-  std::unique_ptr<CXFA_TextProvider> m_pCapTextProvider;
-  std::unique_ptr<CFDE_TextOut> m_pTextOut;
-  std::vector<float> m_FieldSplitArray;
-};
-
-class CXFA_TextEditData : public CXFA_FieldLayoutData {};
-
-class CXFA_ImageEditData : public CXFA_FieldLayoutData {
- public:
-  CXFA_ImageEditData()
-      : m_bNamedImage(false), m_iImageXDpi(0), m_iImageYDpi(0) {}
-
-  ~CXFA_ImageEditData() override {}
-
-  bool LoadImageData(CXFA_FFDoc* doc, CXFA_WidgetAcc* pAcc) {
-    if (m_pDIBitmap)
-      return true;
-
-    CXFA_Value* value = pAcc->GetNode()->GetFormValueIfExists();
-    if (!value)
-      return false;
-
-    CXFA_Image* image = value->GetImageIfExists();
-    if (!image)
-      return false;
-
-    pAcc->SetImageEditImage(XFA_LoadImageData(doc, image, m_bNamedImage,
-                                              m_iImageXDpi, m_iImageYDpi));
-    return !!m_pDIBitmap;
-  }
-
-  RetainPtr<CFX_DIBitmap> m_pDIBitmap;
-  bool m_bNamedImage;
-  int32_t m_iImageXDpi;
-  int32_t m_iImageYDpi;
-};
-
-float GetEdgeThickness(const std::vector<CXFA_Stroke*>& strokes,
-                       bool b3DStyle,
-                       int32_t nIndex) {
-  float fThickness = 0;
-
-  CXFA_Stroke* stroke = strokes[nIndex * 2 + 1];
-  if (stroke->IsVisible()) {
-    if (nIndex == 0)
-      fThickness += 2.5f;
-
-    fThickness += stroke->GetThickness() * (b3DStyle ? 4 : 2);
-  }
-  return fThickness;
-}
-
-bool SplitDateTime(const WideString& wsDateTime,
-                   WideString& wsDate,
-                   WideString& wsTime) {
-  wsDate = L"";
-  wsTime = L"";
-  if (wsDateTime.IsEmpty())
-    return false;
-
-  auto nSplitIndex = wsDateTime.Find('T');
-  if (!nSplitIndex.has_value())
-    nSplitIndex = wsDateTime.Find(' ');
-  if (!nSplitIndex.has_value())
-    return false;
-
-  wsDate = wsDateTime.Left(nSplitIndex.value());
-  if (!wsDate.IsEmpty()) {
-    if (!std::any_of(wsDate.begin(), wsDate.end(), std::iswdigit))
-      return false;
-  }
-  wsTime = wsDateTime.Right(wsDateTime.GetLength() - nSplitIndex.value() - 1);
-  if (!wsTime.IsEmpty()) {
-    if (!std::any_of(wsTime.begin(), wsTime.end(), std::iswdigit))
-      return false;
-  }
-  return true;
-}
-
-std::pair<XFA_Element, CXFA_Node*> CreateUIChild(CXFA_Node* pNode) {
-  XFA_Element eType = pNode->GetElementType();
-  XFA_Element eWidgetType = eType;
-  if (eType != XFA_Element::Field && eType != XFA_Element::Draw)
-    return {eWidgetType, nullptr};
-
-  eWidgetType = XFA_Element::Unknown;
-  XFA_Element eUIType = XFA_Element::Unknown;
-  auto* defValue =
-      pNode->JSObject()->GetOrCreateProperty<CXFA_Value>(0, XFA_Element::Value);
-  XFA_Element eValueType =
-      defValue ? defValue->GetChildValueClassID() : XFA_Element::Unknown;
-  switch (eValueType) {
-    case XFA_Element::Boolean:
-      eUIType = XFA_Element::CheckButton;
-      break;
-    case XFA_Element::Integer:
-    case XFA_Element::Decimal:
-    case XFA_Element::Float:
-      eUIType = XFA_Element::NumericEdit;
-      break;
-    case XFA_Element::ExData:
-    case XFA_Element::Text:
-      eUIType = XFA_Element::TextEdit;
-      eWidgetType = XFA_Element::Text;
-      break;
-    case XFA_Element::Date:
-    case XFA_Element::Time:
-    case XFA_Element::DateTime:
-      eUIType = XFA_Element::DateTimeEdit;
-      break;
-    case XFA_Element::Image:
-      eUIType = XFA_Element::ImageEdit;
-      eWidgetType = XFA_Element::Image;
-      break;
-    case XFA_Element::Arc:
-    case XFA_Element::Line:
-    case XFA_Element::Rectangle:
-      eUIType = XFA_Element::DefaultUi;
-      eWidgetType = eValueType;
-      break;
-    default:
-      break;
-  }
-
-  CXFA_Node* pUIChild = nullptr;
-  CXFA_Ui* pUI =
-      pNode->JSObject()->GetOrCreateProperty<CXFA_Ui>(0, XFA_Element::Ui);
-  CXFA_Node* pChild = pUI ? pUI->GetFirstChild() : nullptr;
-  for (; pChild; pChild = pChild->GetNextSibling()) {
-    XFA_Element eChildType = pChild->GetElementType();
-    if (eChildType == XFA_Element::Extras ||
-        eChildType == XFA_Element::Picture) {
-      continue;
-    }
-
-    auto node = CXFA_Node::Create(pChild->GetDocument(), XFA_Element::Ui,
-                                  XFA_PacketType::Form);
-    if (node && node->HasPropertyFlags(eChildType, XFA_PROPERTYFLAG_OneOf)) {
-      pUIChild = pChild;
-      break;
-    }
-  }
-
-  if (eType == XFA_Element::Draw) {
-    XFA_Element eDraw =
-        pUIChild ? pUIChild->GetElementType() : XFA_Element::Unknown;
-    switch (eDraw) {
-      case XFA_Element::TextEdit:
-        eWidgetType = XFA_Element::Text;
-        break;
-      case XFA_Element::ImageEdit:
-        eWidgetType = XFA_Element::Image;
-        break;
-      default:
-        eWidgetType = eWidgetType == XFA_Element::Unknown ? XFA_Element::Text
-                                                          : eWidgetType;
-        break;
-    }
-  } else {
-    if (pUIChild && pUIChild->GetElementType() == XFA_Element::DefaultUi) {
-      eWidgetType = XFA_Element::TextEdit;
-    } else {
-      eWidgetType =
-          pUIChild ? pUIChild->GetElementType()
-                   : (eUIType == XFA_Element::Unknown ? XFA_Element::TextEdit
-                                                      : eUIType);
-    }
-  }
-
-  if (!pUIChild) {
-    if (eUIType == XFA_Element::Unknown) {
-      eUIType = XFA_Element::TextEdit;
-      if (defValue) {
-        defValue->JSObject()->GetOrCreateProperty<CXFA_Text>(0,
-                                                             XFA_Element::Text);
-      }
-    }
-    return {eWidgetType,
-            pUI ? pUI->JSObject()->GetOrCreateProperty<CXFA_Node>(0, eUIType)
-                : nullptr};
-  }
-
-  if (eUIType != XFA_Element::Unknown)
-    return {eWidgetType, pUIChild};
-
-  switch (pUIChild->GetElementType()) {
-    case XFA_Element::CheckButton: {
-      eValueType = XFA_Element::Text;
-      if (CXFA_Items* pItems =
-              pNode->GetChild<CXFA_Items>(0, XFA_Element::Items, false)) {
-        if (CXFA_Node* pItem =
-                pItems->GetChild<CXFA_Node>(0, XFA_Element::Unknown, false)) {
-          eValueType = pItem->GetElementType();
-        }
-      }
-      break;
-    }
-    case XFA_Element::DateTimeEdit:
-      eValueType = XFA_Element::DateTime;
-      break;
-    case XFA_Element::ImageEdit:
-      eValueType = XFA_Element::Image;
-      break;
-    case XFA_Element::NumericEdit:
-      eValueType = XFA_Element::Float;
-      break;
-    case XFA_Element::ChoiceList: {
-      eValueType = (pUIChild->JSObject()->GetEnum(XFA_Attribute::Open) ==
-                    XFA_AttributeEnum::MultiSelect)
-                       ? XFA_Element::ExData
-                       : XFA_Element::Text;
-      break;
-    }
-    case XFA_Element::Barcode:
-    case XFA_Element::Button:
-    case XFA_Element::PasswordEdit:
-    case XFA_Element::Signature:
-    case XFA_Element::TextEdit:
-    default:
-      eValueType = XFA_Element::Text;
-      break;
-  }
-  if (defValue)
-    defValue->JSObject()->GetOrCreateProperty<CXFA_Node>(0, eValueType);
-
-  return {eWidgetType, pUIChild};
-}
-
-}  // namespace
-
-CXFA_WidgetAcc::CXFA_WidgetAcc(CXFA_Node* pNode)
-    : m_bIsNull(true),
-      m_bPreNull(true),
-      m_pUiChildNode(nullptr),
-      m_eUIType(XFA_Element::Unknown),
-      m_pNode(pNode) {}
-
-CXFA_WidgetAcc::~CXFA_WidgetAcc() = default;
-
-void CXFA_WidgetAcc::ResetData() {
-  WideString wsValue;
-  XFA_Element eUIType = GetUIType();
-  switch (eUIType) {
-    case XFA_Element::ImageEdit: {
-      CXFA_Value* imageValue = m_pNode->GetDefaultValueIfExists();
-      CXFA_Image* image = imageValue ? imageValue->GetImageIfExists() : nullptr;
-      WideString wsContentType, wsHref;
-      if (image) {
-        wsValue = image->GetContent();
-        wsContentType = image->GetContentType();
-        wsHref = image->GetHref();
-      }
-      SetImageEdit(wsContentType, wsHref, wsValue);
-      break;
-    }
-    case XFA_Element::ExclGroup: {
-      CXFA_Node* pNextChild = m_pNode->GetFirstContainerChild();
-      while (pNextChild) {
-        CXFA_Node* pChild = pNextChild;
-        CXFA_WidgetAcc* pAcc = pChild->GetWidgetAcc();
-        if (!pAcc)
-          continue;
-
-        bool done = false;
-        if (wsValue.IsEmpty()) {
-          CXFA_Value* defValue = pAcc->GetNode()->GetDefaultValueIfExists();
-          if (defValue) {
-            wsValue = defValue->GetChildValueContent();
-            SetValue(XFA_VALUEPICTURE_Raw, wsValue);
-            pAcc->SetValue(XFA_VALUEPICTURE_Raw, wsValue);
-            done = true;
-          }
-        }
-        if (!done) {
-          CXFA_Items* pItems =
-              pChild->GetChild<CXFA_Items>(0, XFA_Element::Items, false);
-          if (!pItems)
-            continue;
-
-          WideString itemText;
-          if (pItems->CountChildren(XFA_Element::Unknown, false) > 1) {
-            itemText =
-                pItems->GetChild<CXFA_Node>(1, XFA_Element::Unknown, false)
-                    ->JSObject()
-                    ->GetContent(false);
-          }
-          pAcc->SetValue(XFA_VALUEPICTURE_Raw, itemText);
-        }
-        pNextChild = pChild->GetNextContainerSibling();
-      }
-      break;
-    }
-    case XFA_Element::ChoiceList:
-      ClearAllSelections();
-    default: {
-      CXFA_Value* defValue = m_pNode->GetDefaultValueIfExists();
-      if (defValue)
-        wsValue = defValue->GetChildValueContent();
-
-      SetValue(XFA_VALUEPICTURE_Raw, wsValue);
-      break;
-    }
-  }
-}
-
-void CXFA_WidgetAcc::SetImageEdit(const WideString& wsContentType,
-                                  const WideString& wsHref,
-                                  const WideString& wsData) {
-  CXFA_Value* formValue = m_pNode->GetFormValueIfExists();
-  CXFA_Image* image = formValue ? formValue->GetImageIfExists() : nullptr;
-  if (image) {
-    image->SetContentType(WideString(wsContentType));
-    image->SetHref(wsHref);
-  }
-
-  m_pNode->JSObject()->SetContent(wsData, GetFormatDataValue(wsData), true,
-                                  false, true);
-
-  CXFA_Node* pBind = m_pNode->GetBindData();
-  if (!pBind) {
-    if (image)
-      image->SetTransferEncoding(XFA_AttributeEnum::Base64);
-    return;
-  }
-  pBind->JSObject()->SetCData(XFA_Attribute::ContentType, wsContentType, false,
-                              false);
-  CXFA_Node* pHrefNode = pBind->GetFirstChild();
-  if (pHrefNode) {
-    pHrefNode->JSObject()->SetCData(XFA_Attribute::Value, wsHref, false, false);
-  } else {
-    CFX_XMLNode* pXMLNode = pBind->GetXMLMappingNode();
-    ASSERT(pXMLNode && pXMLNode->GetType() == FX_XMLNODE_Element);
-    static_cast<CFX_XMLElement*>(pXMLNode)->SetString(L"href", wsHref);
-  }
-}
-
-CXFA_FFWidget* CXFA_WidgetAcc::GetNextWidget(CXFA_FFWidget* pWidget) {
-  return static_cast<CXFA_FFWidget*>(pWidget->GetNext());
-}
-
-void CXFA_WidgetAcc::UpdateUIDisplay(CXFA_FFDocView* docView,
-                                     CXFA_FFWidget* pExcept) {
-  CXFA_FFWidget* pWidget = docView->GetWidgetForNode(m_pNode);
-  for (; pWidget; pWidget = GetNextWidget(pWidget)) {
-    if (pWidget == pExcept || !pWidget->IsLoaded() ||
-        (GetUIType() != XFA_Element::CheckButton && pWidget->IsFocused())) {
-      continue;
-    }
-    pWidget->UpdateFWLData();
-    pWidget->AddInvalidateRect();
-  }
-}
-
-void CXFA_WidgetAcc::CalcCaptionSize(CXFA_FFDoc* doc, CFX_SizeF& szCap) {
-  CXFA_Caption* caption = m_pNode->GetCaptionIfExists();
-  if (!caption || !caption->IsVisible())
-    return;
-
-  LoadCaption(doc);
-
-  XFA_Element eUIType = GetUIType();
-  XFA_AttributeEnum iCapPlacement = caption->GetPlacementType();
-  float fCapReserve = caption->GetReserve();
-  const bool bVert = iCapPlacement == XFA_AttributeEnum::Top ||
-                     iCapPlacement == XFA_AttributeEnum::Bottom;
-  const bool bReserveExit = fCapReserve > 0.01;
-  CXFA_TextLayout* pCapTextLayout =
-      static_cast<CXFA_FieldLayoutData*>(m_pLayoutData.get())
-          ->m_pCapTextLayout.get();
-  if (pCapTextLayout) {
-    if (!bVert && eUIType != XFA_Element::Button)
-      szCap.width = fCapReserve;
-
-    CFX_SizeF minSize;
-    szCap = pCapTextLayout->CalcSize(minSize, szCap);
-    if (bReserveExit)
-      bVert ? szCap.height = fCapReserve : szCap.width = fCapReserve;
-  } else {
-    float fFontSize = 10.0f;
-    CXFA_Font* font = caption->GetFontIfExists();
-    if (font) {
-      fFontSize = font->GetFontSize();
-    } else {
-      CXFA_Font* widgetfont = m_pNode->GetFontIfExists();
-      if (widgetfont)
-        fFontSize = widgetfont->GetFontSize();
-    }
-
-    if (bVert) {
-      szCap.height = fCapReserve > 0 ? fCapReserve : fFontSize;
-    } else {
-      szCap.width = fCapReserve > 0 ? fCapReserve : 0;
-      szCap.height = fFontSize;
-    }
-  }
-
-  CXFA_Margin* captionMargin = caption->GetMarginIfExists();
-  if (!captionMargin)
-    return;
-
-  float fLeftInset = captionMargin->GetLeftInset();
-  float fTopInset = captionMargin->GetTopInset();
-  float fRightInset = captionMargin->GetRightInset();
-  float fBottomInset = captionMargin->GetBottomInset();
-  if (bReserveExit) {
-    bVert ? (szCap.width += fLeftInset + fRightInset)
-          : (szCap.height += fTopInset + fBottomInset);
-  } else {
-    szCap.width += fLeftInset + fRightInset;
-    szCap.height += fTopInset + fBottomInset;
-  }
-}
-
-bool CXFA_WidgetAcc::CalculateFieldAutoSize(CXFA_FFDoc* doc, CFX_SizeF& size) {
-  CFX_SizeF szCap;
-  CalcCaptionSize(doc, szCap);
-
-  CFX_RectF rtUIMargin = GetUIMargin();
-  size.width += rtUIMargin.left + rtUIMargin.width;
-  size.height += rtUIMargin.top + rtUIMargin.height;
-  if (szCap.width > 0 && szCap.height > 0) {
-    CXFA_Caption* caption = m_pNode->GetCaptionIfExists();
-    XFA_AttributeEnum placement = caption ? caption->GetPlacementType()
-                                          : CXFA_Caption::kDefaultPlacementType;
-    switch (placement) {
-      case XFA_AttributeEnum::Left:
-      case XFA_AttributeEnum::Right:
-      case XFA_AttributeEnum::Inline: {
-        size.width += szCap.width;
-        size.height = std::max(size.height, szCap.height);
-      } break;
-      case XFA_AttributeEnum::Top:
-      case XFA_AttributeEnum::Bottom: {
-        size.height += szCap.height;
-        size.width = std::max(size.width, szCap.width);
-      }
-      default:
-        break;
-    }
-  }
-  return CalculateWidgetAutoSize(size);
-}
-
-bool CXFA_WidgetAcc::CalculateWidgetAutoSize(CFX_SizeF& size) {
-  CXFA_Margin* margin = m_pNode->GetMarginIfExists();
-  if (margin) {
-    size.width += margin->GetLeftInset() + margin->GetRightInset();
-    size.height += margin->GetTopInset() + margin->GetBottomInset();
-  }
-
-  CXFA_Para* para = m_pNode->GetParaIfExists();
-  if (para)
-    size.width += para->GetMarginLeft() + para->GetTextIndent();
-
-  Optional<float> width = m_pNode->TryWidth();
-  if (width) {
-    size.width = *width;
-  } else {
-    Optional<float> min = m_pNode->TryMinWidth();
-    if (min)
-      size.width = std::max(size.width, *min);
-
-    Optional<float> max = m_pNode->TryMaxWidth();
-    if (max && *max > 0)
-      size.width = std::min(size.width, *max);
-  }
-
-  Optional<float> height = m_pNode->TryHeight();
-  if (height) {
-    size.height = *height;
-  } else {
-    Optional<float> min = m_pNode->TryMinHeight();
-    if (min)
-      size.height = std::max(size.height, *min);
-
-    Optional<float> max = m_pNode->TryMaxHeight();
-    if (max && *max > 0)
-      size.height = std::min(size.height, *max);
-  }
-  return true;
-}
-
-void CXFA_WidgetAcc::CalculateTextContentSize(CXFA_FFDoc* doc,
-                                              CFX_SizeF& size) {
-  float fFontSize = m_pNode->GetFontSize();
-  WideString wsText = GetValue(XFA_VALUEPICTURE_Display);
-  if (wsText.IsEmpty()) {
-    size.height += fFontSize;
-    return;
-  }
-
-  wchar_t wcEnter = '\n';
-  wchar_t wsLast = wsText[wsText.GetLength() - 1];
-  if (wsLast == wcEnter)
-    wsText = wsText + wcEnter;
-
-  CXFA_FieldLayoutData* layoutData =
-      static_cast<CXFA_FieldLayoutData*>(m_pLayoutData.get());
-  if (!layoutData->m_pTextOut) {
-    layoutData->m_pTextOut = pdfium::MakeUnique<CFDE_TextOut>();
-    CFDE_TextOut* pTextOut = layoutData->m_pTextOut.get();
-    pTextOut->SetFont(GetFDEFont(doc));
-    pTextOut->SetFontSize(fFontSize);
-    pTextOut->SetLineBreakTolerance(fFontSize * 0.2f);
-    pTextOut->SetLineSpace(m_pNode->GetLineHeight());
-
-    FDE_TextStyle dwStyles;
-    dwStyles.last_line_height_ = true;
-    if (GetUIType() == XFA_Element::TextEdit && IsMultiLine())
-      dwStyles.line_wrap_ = true;
-
-    pTextOut->SetStyles(dwStyles);
-  }
-  layoutData->m_pTextOut->CalcLogicSize(wsText, size);
-}
-
-bool CXFA_WidgetAcc::CalculateTextEditAutoSize(CXFA_FFDoc* doc,
-                                               CFX_SizeF& size) {
-  if (size.width > 0) {
-    CFX_SizeF szOrz = size;
-    CFX_SizeF szCap;
-    CalcCaptionSize(doc, szCap);
-    bool bCapExit = szCap.width > 0.01 && szCap.height > 0.01;
-    XFA_AttributeEnum iCapPlacement = XFA_AttributeEnum::Unknown;
-    if (bCapExit) {
-      CXFA_Caption* caption = m_pNode->GetCaptionIfExists();
-      iCapPlacement = caption ? caption->GetPlacementType()
-                              : CXFA_Caption::kDefaultPlacementType;
-      switch (iCapPlacement) {
-        case XFA_AttributeEnum::Left:
-        case XFA_AttributeEnum::Right:
-        case XFA_AttributeEnum::Inline: {
-          size.width -= szCap.width;
-        }
-        default:
-          break;
-      }
-    }
-    CFX_RectF rtUIMargin = GetUIMargin();
-    size.width -= rtUIMargin.left + rtUIMargin.width;
-    CXFA_Margin* margin = m_pNode->GetMarginIfExists();
-    if (margin)
-      size.width -= margin->GetLeftInset() + margin->GetRightInset();
-
-    CalculateTextContentSize(doc, size);
-    size.height += rtUIMargin.top + rtUIMargin.height;
-    if (bCapExit) {
-      switch (iCapPlacement) {
-        case XFA_AttributeEnum::Left:
-        case XFA_AttributeEnum::Right:
-        case XFA_AttributeEnum::Inline: {
-          size.height = std::max(size.height, szCap.height);
-        } break;
-        case XFA_AttributeEnum::Top:
-        case XFA_AttributeEnum::Bottom: {
-          size.height += szCap.height;
-        }
-        default:
-          break;
-      }
-    }
-    size.width = szOrz.width;
-    return CalculateWidgetAutoSize(size);
-  }
-  CalculateTextContentSize(doc, size);
-  return CalculateFieldAutoSize(doc, size);
-}
-
-bool CXFA_WidgetAcc::CalculateCheckButtonAutoSize(CXFA_FFDoc* doc,
-                                                  CFX_SizeF& size) {
-  float fCheckSize = GetCheckButtonSize();
-  size = CFX_SizeF(fCheckSize, fCheckSize);
-  return CalculateFieldAutoSize(doc, size);
-}
-
-bool CXFA_WidgetAcc::CalculatePushButtonAutoSize(CXFA_FFDoc* doc,
-                                                 CFX_SizeF& size) {
-  CalcCaptionSize(doc, size);
-  return CalculateWidgetAutoSize(size);
-}
-
-CFX_SizeF CXFA_WidgetAcc::CalculateImageSize(float img_width,
-                                             float img_height,
-                                             float dpi_x,
-                                             float dpi_y) {
-  CFX_RectF rtImage(0, 0, XFA_UnitPx2Pt(img_width, dpi_x),
-                    XFA_UnitPx2Pt(img_height, dpi_y));
-
-  CFX_RectF rtFit;
-  Optional<float> width = m_pNode->TryWidth();
-  if (width) {
-    rtFit.width = *width;
-    GetWidthWithoutMargin(rtFit.width);
-  } else {
-    rtFit.width = rtImage.width;
-  }
-
-  Optional<float> height = m_pNode->TryHeight();
-  if (height) {
-    rtFit.height = *height;
-    GetHeightWithoutMargin(rtFit.height);
-  } else {
-    rtFit.height = rtImage.height;
-  }
-
-  return rtFit.Size();
-}
-
-bool CXFA_WidgetAcc::CalculateImageAutoSize(CXFA_FFDoc* doc, CFX_SizeF& size) {
-  if (!GetImageImage())
-    LoadImageImage(doc);
-
-  size.clear();
-  RetainPtr<CFX_DIBitmap> pBitmap = GetImageImage();
-  if (!pBitmap)
-    return CalculateWidgetAutoSize(size);
-
-  int32_t iImageXDpi = 0;
-  int32_t iImageYDpi = 0;
-  GetImageDpi(iImageXDpi, iImageYDpi);
-
-  size = CalculateImageSize(pBitmap->GetWidth(), pBitmap->GetHeight(),
-                            iImageXDpi, iImageYDpi);
-  return CalculateWidgetAutoSize(size);
-}
-
-bool CXFA_WidgetAcc::CalculateImageEditAutoSize(CXFA_FFDoc* doc,
-                                                CFX_SizeF& size) {
-  if (!GetImageEditImage())
-    LoadImageEditImage(doc);
-
-  size.clear();
-  RetainPtr<CFX_DIBitmap> pBitmap = GetImageEditImage();
-  if (!pBitmap)
-    return CalculateFieldAutoSize(doc, size);
-
-  int32_t iImageXDpi = 0;
-  int32_t iImageYDpi = 0;
-  GetImageEditDpi(iImageXDpi, iImageYDpi);
-
-  size = CalculateImageSize(pBitmap->GetWidth(), pBitmap->GetHeight(),
-                            iImageXDpi, iImageYDpi);
-  return CalculateFieldAutoSize(doc, size);
-}
-
-bool CXFA_WidgetAcc::LoadImageImage(CXFA_FFDoc* doc) {
-  InitLayoutData();
-  return static_cast<CXFA_ImageLayoutData*>(m_pLayoutData.get())
-      ->LoadImageData(doc, this);
-}
-
-bool CXFA_WidgetAcc::LoadImageEditImage(CXFA_FFDoc* doc) {
-  InitLayoutData();
-  return static_cast<CXFA_ImageEditData*>(m_pLayoutData.get())
-      ->LoadImageData(doc, this);
-}
-
-void CXFA_WidgetAcc::GetImageDpi(int32_t& iImageXDpi, int32_t& iImageYDpi) {
-  CXFA_ImageLayoutData* pData =
-      static_cast<CXFA_ImageLayoutData*>(m_pLayoutData.get());
-  iImageXDpi = pData->m_iImageXDpi;
-  iImageYDpi = pData->m_iImageYDpi;
-}
-
-void CXFA_WidgetAcc::GetImageEditDpi(int32_t& iImageXDpi, int32_t& iImageYDpi) {
-  CXFA_ImageEditData* pData =
-      static_cast<CXFA_ImageEditData*>(m_pLayoutData.get());
-  iImageXDpi = pData->m_iImageXDpi;
-  iImageYDpi = pData->m_iImageYDpi;
-}
-
-void CXFA_WidgetAcc::LoadText(CXFA_FFDoc* doc) {
-  InitLayoutData();
-  static_cast<CXFA_TextLayoutData*>(m_pLayoutData.get())->LoadText(doc, this);
-}
-
-float CXFA_WidgetAcc::CalculateWidgetAutoWidth(float fWidthCalc) {
-  CXFA_Margin* margin = m_pNode->GetMarginIfExists();
-  if (margin)
-    fWidthCalc += margin->GetLeftInset() + margin->GetRightInset();
-
-  Optional<float> min = m_pNode->TryMinWidth();
-  if (min)
-    fWidthCalc = std::max(fWidthCalc, *min);
-
-  Optional<float> max = m_pNode->TryMaxWidth();
-  if (max && *max > 0)
-    fWidthCalc = std::min(fWidthCalc, *max);
-
-  return fWidthCalc;
-}
-
-float CXFA_WidgetAcc::GetWidthWithoutMargin(float fWidthCalc) {
-  CXFA_Margin* margin = m_pNode->GetMarginIfExists();
-  if (margin)
-    fWidthCalc -= margin->GetLeftInset() + margin->GetRightInset();
-  return fWidthCalc;
-}
-
-float CXFA_WidgetAcc::CalculateWidgetAutoHeight(float fHeightCalc) {
-  CXFA_Margin* margin = m_pNode->GetMarginIfExists();
-  if (margin)
-    fHeightCalc += margin->GetTopInset() + margin->GetBottomInset();
-
-  Optional<float> min = m_pNode->TryMinHeight();
-  if (min)
-    fHeightCalc = std::max(fHeightCalc, *min);
-
-  Optional<float> max = m_pNode->TryMaxHeight();
-  if (max && *max > 0)
-    fHeightCalc = std::min(fHeightCalc, *max);
-
-  return fHeightCalc;
-}
-
-float CXFA_WidgetAcc::GetHeightWithoutMargin(float fHeightCalc) {
-  CXFA_Margin* margin = m_pNode->GetMarginIfExists();
-  if (margin)
-    fHeightCalc -= margin->GetTopInset() + margin->GetBottomInset();
-  return fHeightCalc;
-}
-
-void CXFA_WidgetAcc::StartWidgetLayout(CXFA_FFDoc* doc,
-                                       float& fCalcWidth,
-                                       float& fCalcHeight) {
-  InitLayoutData();
-
-  XFA_Element eUIType = GetUIType();
-  if (eUIType == XFA_Element::Text) {
-    m_pLayoutData->m_fWidgetHeight = m_pNode->TryHeight().value_or(-1);
-    StartTextLayout(doc, fCalcWidth, fCalcHeight);
-    return;
-  }
-  if (fCalcWidth > 0 && fCalcHeight > 0)
-    return;
-
-  m_pLayoutData->m_fWidgetHeight = -1;
-  float fWidth = 0;
-  if (fCalcWidth > 0 && fCalcHeight < 0) {
-    Optional<float> height = m_pNode->TryHeight();
-    if (height)
-      fCalcHeight = *height;
-    else
-      CalculateAccWidthAndHeight(doc, eUIType, fCalcWidth, fCalcHeight);
-
-    m_pLayoutData->m_fWidgetHeight = fCalcHeight;
-    return;
-  }
-  if (fCalcWidth < 0 && fCalcHeight < 0) {
-    Optional<float> height;
-    Optional<float> width = m_pNode->TryWidth();
-    if (width) {
-      fWidth = *width;
-
-      height = m_pNode->TryHeight();
-      if (height)
-        fCalcHeight = *height;
-    }
-    if (!width || !height)
-      CalculateAccWidthAndHeight(doc, eUIType, fWidth, fCalcHeight);
-
-    fCalcWidth = fWidth;
-  }
-  m_pLayoutData->m_fWidgetHeight = fCalcHeight;
-}
-
-void CXFA_WidgetAcc::CalculateAccWidthAndHeight(CXFA_FFDoc* doc,
-                                                XFA_Element eUIType,
-                                                float& fWidth,
-                                                float& fCalcHeight) {
-  CFX_SizeF sz(fWidth, m_pLayoutData->m_fWidgetHeight);
-  switch (eUIType) {
-    case XFA_Element::Barcode:
-    case XFA_Element::ChoiceList:
-    case XFA_Element::Signature:
-      CalculateFieldAutoSize(doc, sz);
-      break;
-    case XFA_Element::ImageEdit:
-      CalculateImageEditAutoSize(doc, sz);
-      break;
-    case XFA_Element::Button:
-      CalculatePushButtonAutoSize(doc, sz);
-      break;
-    case XFA_Element::CheckButton:
-      CalculateCheckButtonAutoSize(doc, sz);
-      break;
-    case XFA_Element::DateTimeEdit:
-    case XFA_Element::NumericEdit:
-    case XFA_Element::PasswordEdit:
-    case XFA_Element::TextEdit:
-      CalculateTextEditAutoSize(doc, sz);
-      break;
-    case XFA_Element::Image:
-      CalculateImageAutoSize(doc, sz);
-      break;
-    case XFA_Element::Arc:
-    case XFA_Element::Line:
-    case XFA_Element::Rectangle:
-    case XFA_Element::Subform:
-    case XFA_Element::ExclGroup:
-      CalculateWidgetAutoSize(sz);
-      break;
-    default:
-      break;
-  }
-  fWidth = sz.width;
-  m_pLayoutData->m_fWidgetHeight = sz.height;
-  fCalcHeight = sz.height;
-}
-
-bool CXFA_WidgetAcc::FindSplitPos(CXFA_FFDocView* docView,
-                                  int32_t iBlockIndex,
-                                  float& fCalcHeight) {
-  XFA_Element eUIType = GetUIType();
-  if (eUIType == XFA_Element::Subform)
-    return false;
-
-  if (eUIType != XFA_Element::Text && eUIType != XFA_Element::TextEdit &&
-      eUIType != XFA_Element::NumericEdit &&
-      eUIType != XFA_Element::PasswordEdit) {
-    fCalcHeight = 0;
-    return true;
-  }
-
-  float fTopInset = 0;
-  float fBottomInset = 0;
-  if (iBlockIndex == 0) {
-    CXFA_Margin* margin = m_pNode->GetMarginIfExists();
-    if (margin) {
-      fTopInset = margin->GetTopInset();
-      fBottomInset = margin->GetBottomInset();
-    }
-
-    CFX_RectF rtUIMargin = GetUIMargin();
-    fTopInset += rtUIMargin.top;
-    fBottomInset += rtUIMargin.width;
-  }
-  if (eUIType == XFA_Element::Text) {
-    float fHeight = fCalcHeight;
-    if (iBlockIndex == 0) {
-      fCalcHeight = fCalcHeight - fTopInset;
-      if (fCalcHeight < 0)
-        fCalcHeight = 0;
-    }
-
-    CXFA_TextLayout* pTextLayout =
-        static_cast<CXFA_TextLayoutData*>(m_pLayoutData.get())->GetTextLayout();
-    fCalcHeight =
-        pTextLayout->DoLayout(iBlockIndex, fCalcHeight, fCalcHeight,
-                              m_pLayoutData->m_fWidgetHeight - fTopInset);
-    if (fCalcHeight != 0) {
-      if (iBlockIndex == 0)
-        fCalcHeight = fCalcHeight + fTopInset;
-      if (fabs(fHeight - fCalcHeight) < XFA_FLOAT_PERCISION)
-        return false;
-    }
-    return true;
-  }
-  XFA_AttributeEnum iCapPlacement = XFA_AttributeEnum::Unknown;
-  float fCapReserve = 0;
-  if (iBlockIndex == 0) {
-    CXFA_Caption* caption = m_pNode->GetCaptionIfExists();
-    if (caption && !caption->IsHidden()) {
-      iCapPlacement = caption->GetPlacementType();
-      fCapReserve = caption->GetReserve();
-    }
-    if (iCapPlacement == XFA_AttributeEnum::Top &&
-        fCalcHeight < fCapReserve + fTopInset) {
-      fCalcHeight = 0;
-      return true;
-    }
-    if (iCapPlacement == XFA_AttributeEnum::Bottom &&
-        m_pLayoutData->m_fWidgetHeight - fCapReserve - fBottomInset) {
-      fCalcHeight = 0;
-      return true;
-    }
-    if (iCapPlacement != XFA_AttributeEnum::Top)
-      fCapReserve = 0;
-  }
-  CXFA_FieldLayoutData* pFieldData =
-      static_cast<CXFA_FieldLayoutData*>(m_pLayoutData.get());
-  int32_t iLinesCount = 0;
-  float fHeight = m_pLayoutData->m_fWidgetHeight;
-  if (GetValue(XFA_VALUEPICTURE_Display).IsEmpty()) {
-    iLinesCount = 1;
-  } else {
-    if (!pFieldData->m_pTextOut) {
-      // TODO(dsinclair): Inline fWidth when the 2nd param of
-      // CalculateAccWidthAndHeight isn't a ref-param.
-      float fWidth = m_pNode->TryWidth().value_or(0);
-      CalculateAccWidthAndHeight(docView->GetDoc(), eUIType, fWidth, fHeight);
-    }
-    iLinesCount = pFieldData->m_pTextOut->GetTotalLines();
-  }
-  std::vector<float>* pFieldArray = &pFieldData->m_FieldSplitArray;
-  int32_t iFieldSplitCount = pdfium::CollectionSize<int32_t>(*pFieldArray);
-  for (int32_t i = 0; i < iBlockIndex * 3; i += 3) {
-    iLinesCount -= (int32_t)(*pFieldArray)[i + 1];
-    fHeight -= (*pFieldArray)[i + 2];
-  }
-  if (iLinesCount == 0)
-    return false;
-
-  float fLineHeight = m_pNode->GetLineHeight();
-  float fFontSize = m_pNode->GetFontSize();
-  float fTextHeight = iLinesCount * fLineHeight - fLineHeight + fFontSize;
-  float fSpaceAbove = 0;
-  float fStartOffset = 0;
-  if (fHeight > 0.1f && iBlockIndex == 0) {
-    fStartOffset = fTopInset;
-    fHeight -= (fTopInset + fBottomInset);
-    CXFA_Para* para = m_pNode->GetParaIfExists();
-    if (para) {
-      fSpaceAbove = para->GetSpaceAbove();
-      float fSpaceBelow = para->GetSpaceBelow();
-      fHeight -= (fSpaceAbove + fSpaceBelow);
-      switch (para->GetVerticalAlign()) {
-        case XFA_AttributeEnum::Top:
-          fStartOffset += fSpaceAbove;
-          break;
-        case XFA_AttributeEnum::Middle:
-          fStartOffset += ((fHeight - fTextHeight) / 2 + fSpaceAbove);
-          break;
-        case XFA_AttributeEnum::Bottom:
-          fStartOffset += (fHeight - fTextHeight + fSpaceAbove);
-          break;
-        default:
-          NOTREACHED();
-          break;
-      }
-    }
-    if (fStartOffset < 0.1f)
-      fStartOffset = 0;
-  }
-  for (int32_t i = iBlockIndex - 1; iBlockIndex > 0 && i < iBlockIndex; i++) {
-    fStartOffset = (*pFieldArray)[i * 3] - (*pFieldArray)[i * 3 + 2];
-    if (fStartOffset < 0.1f)
-      fStartOffset = 0;
-  }
-  if (iFieldSplitCount / 3 == (iBlockIndex + 1))
-    (*pFieldArray)[0] = fStartOffset;
-  else
-    pFieldArray->push_back(fStartOffset);
-
-  XFA_VERSION version = docView->GetDoc()->GetXFADoc()->GetCurVersionMode();
-  bool bCanSplitNoContent = false;
-  XFA_AttributeEnum eLayoutMode = GetNode()
-                                      ->GetParent()
-                                      ->JSObject()
-                                      ->TryEnum(XFA_Attribute::Layout, true)
-                                      .value_or(XFA_AttributeEnum::Position);
-  if ((eLayoutMode == XFA_AttributeEnum::Position ||
-       eLayoutMode == XFA_AttributeEnum::Tb ||
-       eLayoutMode == XFA_AttributeEnum::Row ||
-       eLayoutMode == XFA_AttributeEnum::Table) &&
-      version > XFA_VERSION_208) {
-    bCanSplitNoContent = true;
-  }
-  if ((eLayoutMode == XFA_AttributeEnum::Tb ||
-       eLayoutMode == XFA_AttributeEnum::Row ||
-       eLayoutMode == XFA_AttributeEnum::Table) &&
-      version <= XFA_VERSION_208) {
-    if (fStartOffset < fCalcHeight) {
-      bCanSplitNoContent = true;
-    } else {
-      fCalcHeight = 0;
-      return true;
-    }
-  }
-  if (bCanSplitNoContent) {
-    if ((fCalcHeight - fTopInset - fSpaceAbove < fLineHeight)) {
-      fCalcHeight = 0;
-      return true;
-    }
-    if (fStartOffset + XFA_FLOAT_PERCISION >= fCalcHeight) {
-      if (iFieldSplitCount / 3 == (iBlockIndex + 1)) {
-        (*pFieldArray)[iBlockIndex * 3 + 1] = 0;
-        (*pFieldArray)[iBlockIndex * 3 + 2] = fCalcHeight;
-      } else {
-        pFieldArray->push_back(0);
-        pFieldArray->push_back(fCalcHeight);
-      }
-      return false;
-    }
-    if (fCalcHeight - fStartOffset < fLineHeight) {
-      fCalcHeight = fStartOffset;
-      if (iFieldSplitCount / 3 == (iBlockIndex + 1)) {
-        (*pFieldArray)[iBlockIndex * 3 + 1] = 0;
-        (*pFieldArray)[iBlockIndex * 3 + 2] = fCalcHeight;
-      } else {
-        pFieldArray->push_back(0);
-        pFieldArray->push_back(fCalcHeight);
-      }
-      return true;
-    }
-    float fTextNum =
-        fCalcHeight + XFA_FLOAT_PERCISION - fCapReserve - fStartOffset;
-    int32_t iLineNum =
-        (int32_t)((fTextNum + (fLineHeight - fFontSize)) / fLineHeight);
-    if (iLineNum >= iLinesCount) {
-      if (fCalcHeight - fStartOffset - fTextHeight >= fFontSize) {
-        if (iFieldSplitCount / 3 == (iBlockIndex + 1)) {
-          (*pFieldArray)[iBlockIndex * 3 + 1] = (float)iLinesCount;
-          (*pFieldArray)[iBlockIndex * 3 + 2] = fCalcHeight;
-        } else {
-          pFieldArray->push_back((float)iLinesCount);
-          pFieldArray->push_back(fCalcHeight);
-        }
-        return false;
-      }
-      if (fHeight - fStartOffset - fTextHeight < fFontSize) {
-        iLineNum -= 1;
-        if (iLineNum == 0) {
-          fCalcHeight = 0;
-          return true;
-        }
-      } else {
-        iLineNum = (int32_t)(fTextNum / fLineHeight);
-      }
-    }
-    if (iLineNum > 0) {
-      float fSplitHeight = iLineNum * fLineHeight + fCapReserve + fStartOffset;
-      if (iFieldSplitCount / 3 == (iBlockIndex + 1)) {
-        (*pFieldArray)[iBlockIndex * 3 + 1] = (float)iLineNum;
-        (*pFieldArray)[iBlockIndex * 3 + 2] = fSplitHeight;
-      } else {
-        pFieldArray->push_back((float)iLineNum);
-        pFieldArray->push_back(fSplitHeight);
-      }
-      if (fabs(fSplitHeight - fCalcHeight) < XFA_FLOAT_PERCISION)
-        return false;
-
-      fCalcHeight = fSplitHeight;
-      return true;
-    }
-  }
-  fCalcHeight = 0;
-  return true;
-}
-
-void CXFA_WidgetAcc::InitLayoutData() {
-  if (m_pLayoutData)
-    return;
-
-  switch (GetUIType()) {
-    case XFA_Element::Text:
-      m_pLayoutData = pdfium::MakeUnique<CXFA_TextLayoutData>();
-      return;
-    case XFA_Element::TextEdit:
-      m_pLayoutData = pdfium::MakeUnique<CXFA_TextEditData>();
-      return;
-    case XFA_Element::Image:
-      m_pLayoutData = pdfium::MakeUnique<CXFA_ImageLayoutData>();
-      return;
-    case XFA_Element::ImageEdit:
-      m_pLayoutData = pdfium::MakeUnique<CXFA_ImageEditData>();
-      return;
-    default:
-      break;
-  }
-  if (m_pNode && m_pNode->GetElementType() == XFA_Element::Field) {
-    m_pLayoutData = pdfium::MakeUnique<CXFA_FieldLayoutData>();
-    return;
-  }
-  m_pLayoutData = pdfium::MakeUnique<CXFA_WidgetLayoutData>();
-}
-
-void CXFA_WidgetAcc::StartTextLayout(CXFA_FFDoc* doc,
-                                     float& fCalcWidth,
-                                     float& fCalcHeight) {
-  LoadText(doc);
-
-  CXFA_TextLayout* pTextLayout =
-      static_cast<CXFA_TextLayoutData*>(m_pLayoutData.get())->GetTextLayout();
-  float fTextHeight = 0;
-  if (fCalcWidth > 0 && fCalcHeight > 0) {
-    float fWidth = GetWidthWithoutMargin(fCalcWidth);
-    pTextLayout->StartLayout(fWidth);
-    fTextHeight = fCalcHeight;
-    fTextHeight = GetHeightWithoutMargin(fTextHeight);
-    pTextLayout->DoLayout(0, fTextHeight, -1, fTextHeight);
-    return;
-  }
-  if (fCalcWidth > 0 && fCalcHeight < 0) {
-    float fWidth = GetWidthWithoutMargin(fCalcWidth);
-    pTextLayout->StartLayout(fWidth);
-  }
-
-  if (fCalcWidth < 0 && fCalcHeight < 0) {
-    Optional<float> width = m_pNode->TryWidth();
-    if (width) {
-      pTextLayout->StartLayout(GetWidthWithoutMargin(*width));
-      fCalcWidth = *width;
-    } else {
-      float fMaxWidth = CalculateWidgetAutoWidth(pTextLayout->StartLayout(-1));
-      pTextLayout->StartLayout(GetWidthWithoutMargin(fMaxWidth));
-      fCalcWidth = fMaxWidth;
-    }
-  }
-
-  if (m_pLayoutData->m_fWidgetHeight < 0) {
-    m_pLayoutData->m_fWidgetHeight = pTextLayout->GetLayoutHeight();
-    m_pLayoutData->m_fWidgetHeight =
-        CalculateWidgetAutoHeight(m_pLayoutData->m_fWidgetHeight);
-  }
-  fTextHeight = m_pLayoutData->m_fWidgetHeight;
-  fTextHeight = GetHeightWithoutMargin(fTextHeight);
-  pTextLayout->DoLayout(0, fTextHeight, -1, fTextHeight);
-  fCalcHeight = m_pLayoutData->m_fWidgetHeight;
-}
-
-bool CXFA_WidgetAcc::LoadCaption(CXFA_FFDoc* doc) {
-  InitLayoutData();
-  return static_cast<CXFA_FieldLayoutData*>(m_pLayoutData.get())
-      ->LoadCaption(doc, this);
-}
-
-CXFA_TextLayout* CXFA_WidgetAcc::GetCaptionTextLayout() {
-  return m_pLayoutData
-             ? static_cast<CXFA_FieldLayoutData*>(m_pLayoutData.get())
-                   ->m_pCapTextLayout.get()
-             : nullptr;
-}
-
-CXFA_TextLayout* CXFA_WidgetAcc::GetTextLayout() {
-  return m_pLayoutData
-             ? static_cast<CXFA_TextLayoutData*>(m_pLayoutData.get())
-                   ->GetTextLayout()
-             : nullptr;
-}
-
-RetainPtr<CFX_DIBitmap> CXFA_WidgetAcc::GetImageImage() {
-  return m_pLayoutData
-             ? static_cast<CXFA_ImageLayoutData*>(m_pLayoutData.get())
-                   ->m_pDIBitmap
-             : nullptr;
-}
-
-RetainPtr<CFX_DIBitmap> CXFA_WidgetAcc::GetImageEditImage() {
-  return m_pLayoutData
-             ? static_cast<CXFA_ImageEditData*>(m_pLayoutData.get())
-                   ->m_pDIBitmap
-             : nullptr;
-}
-
-void CXFA_WidgetAcc::SetImageImage(const RetainPtr<CFX_DIBitmap>& newImage) {
-  CXFA_ImageLayoutData* pData =
-      static_cast<CXFA_ImageLayoutData*>(m_pLayoutData.get());
-  if (pData->m_pDIBitmap != newImage)
-    pData->m_pDIBitmap = newImage;
-}
-
-void CXFA_WidgetAcc::SetImageEditImage(
-    const RetainPtr<CFX_DIBitmap>& newImage) {
-  CXFA_ImageEditData* pData =
-      static_cast<CXFA_ImageEditData*>(m_pLayoutData.get());
-  if (pData->m_pDIBitmap != newImage)
-    pData->m_pDIBitmap = newImage;
-}
-
-RetainPtr<CFGAS_GEFont> CXFA_WidgetAcc::GetFDEFont(CXFA_FFDoc* doc) {
-  WideString wsFontName = L"Courier";
-  uint32_t dwFontStyle = 0;
-  CXFA_Font* font = m_pNode->GetFontIfExists();
-  if (font) {
-    if (font->IsBold())
-      dwFontStyle |= FXFONT_BOLD;
-    if (font->IsItalic())
-      dwFontStyle |= FXFONT_ITALIC;
-
-    wsFontName = font->GetTypeface();
-  }
-  return doc->GetApp()->GetXFAFontMgr()->GetFont(doc, wsFontName.AsStringView(),
-                                                 dwFontStyle);
-}
-
-CXFA_Node* CXFA_WidgetAcc::GetUIChild() {
-  if (m_eUIType == XFA_Element::Unknown)
-    std::tie(m_eUIType, m_pUiChildNode) = CreateUIChild(m_pNode);
-  return m_pUiChildNode;
-}
-
-XFA_Element CXFA_WidgetAcc::GetUIType() {
-  GetUIChild();
-  return m_eUIType;
-}
-
-bool CXFA_WidgetAcc::IsOpenAccess() const {
-  return m_pNode && m_pNode->IsOpenAccess();
-}
-
-std::vector<CXFA_Event*> CXFA_WidgetAcc::GetEventByActivity(
-    XFA_AttributeEnum iActivity,
-    bool bIsFormReady) {
-  std::vector<CXFA_Event*> events;
-  for (CXFA_Node* node : m_pNode->GetNodeList(0, XFA_Element::Event)) {
-    auto* event = static_cast<CXFA_Event*>(node);
-    if (event->GetActivity() == iActivity) {
-      if (iActivity == XFA_AttributeEnum::Ready) {
-        WideString wsRef = event->GetRef();
-        if (bIsFormReady) {
-          if (wsRef == WideStringView(L"$form"))
-            events.push_back(event);
-        } else {
-          if (wsRef == WideStringView(L"$layout"))
-            events.push_back(event);
-        }
-      } else {
-        events.push_back(event);
-      }
-    }
-  }
-  return events;
-}
-
-CXFA_Border* CXFA_WidgetAcc::GetUIBorder() {
-  CXFA_Node* pUIChild = GetUIChild();
-  return pUIChild ? pUIChild->JSObject()->GetProperty<CXFA_Border>(
-                        0, XFA_Element::Border)
-                  : nullptr;
-}
-
-CFX_RectF CXFA_WidgetAcc::GetUIMargin() {
-  CXFA_Node* pUIChild = GetUIChild();
-  CXFA_Margin* mgUI = nullptr;
-  if (pUIChild) {
-    mgUI =
-        pUIChild->JSObject()->GetProperty<CXFA_Margin>(0, XFA_Element::Margin);
-  }
-
-  if (!mgUI)
-    return CFX_RectF();
-
-  CXFA_Border* border = GetUIBorder();
-  if (border && border->GetPresence() != XFA_AttributeEnum::Visible)
-    return CFX_RectF();
-
-  Optional<float> left = mgUI->TryLeftInset();
-  Optional<float> top = mgUI->TryTopInset();
-  Optional<float> right = mgUI->TryRightInset();
-  Optional<float> bottom = mgUI->TryBottomInset();
-  if (border) {
-    bool bVisible = false;
-    float fThickness = 0;
-    XFA_AttributeEnum iType = XFA_AttributeEnum::Unknown;
-    std::tie(iType, bVisible, fThickness) = border->Get3DStyle();
-    if (!left || !top || !right || !bottom) {
-      std::vector<CXFA_Stroke*> strokes = border->GetStrokes();
-      if (!top)
-        top = GetEdgeThickness(strokes, bVisible, 0);
-      if (!right)
-        right = GetEdgeThickness(strokes, bVisible, 1);
-      if (!bottom)
-        bottom = GetEdgeThickness(strokes, bVisible, 2);
-      if (!left)
-        left = GetEdgeThickness(strokes, bVisible, 3);
-    }
-  }
-  return CFX_RectF(left.value_or(0.0), top.value_or(0.0), right.value_or(0.0),
-                   bottom.value_or(0.0));
-}
-
-XFA_AttributeEnum CXFA_WidgetAcc::GetButtonHighlight() {
-  CXFA_Node* pUIChild = GetUIChild();
-  if (pUIChild)
-    return pUIChild->JSObject()->GetEnum(XFA_Attribute::Highlight);
-  return XFA_AttributeEnum::Inverted;
-}
-
-bool CXFA_WidgetAcc::HasButtonRollover() const {
-  CXFA_Items* pItems =
-      m_pNode->GetChild<CXFA_Items>(0, XFA_Element::Items, false);
-  if (!pItems)
-    return false;
-
-  for (CXFA_Node* pText = pItems->GetFirstChild(); pText;
-       pText = pText->GetNextSibling()) {
-    if (pText->JSObject()->GetCData(XFA_Attribute::Name) == L"rollover")
-      return !pText->JSObject()->GetContent(false).IsEmpty();
-  }
-  return false;
-}
-
-bool CXFA_WidgetAcc::HasButtonDown() const {
-  CXFA_Items* pItems =
-      m_pNode->GetChild<CXFA_Items>(0, XFA_Element::Items, false);
-  if (!pItems)
-    return false;
-
-  for (CXFA_Node* pText = pItems->GetFirstChild(); pText;
-       pText = pText->GetNextSibling()) {
-    if (pText->JSObject()->GetCData(XFA_Attribute::Name) == L"down")
-      return !pText->JSObject()->GetContent(false).IsEmpty();
-  }
-  return false;
-}
-
-bool CXFA_WidgetAcc::IsCheckButtonRound() {
-  CXFA_Node* pUIChild = GetUIChild();
-  if (pUIChild)
-    return pUIChild->JSObject()->GetEnum(XFA_Attribute::Shape) ==
-           XFA_AttributeEnum::Round;
-  return false;
-}
-
-XFA_AttributeEnum CXFA_WidgetAcc::GetCheckButtonMark() {
-  CXFA_Node* pUIChild = GetUIChild();
-  if (pUIChild)
-    return pUIChild->JSObject()->GetEnum(XFA_Attribute::Mark);
-  return XFA_AttributeEnum::Default;
-}
-
-bool CXFA_WidgetAcc::IsRadioButton() {
-  CXFA_Node* pParent = m_pNode->GetParent();
-  return pParent && pParent->GetElementType() == XFA_Element::ExclGroup;
-}
-
-float CXFA_WidgetAcc::GetCheckButtonSize() {
-  CXFA_Node* pUIChild = GetUIChild();
-  if (pUIChild) {
-    return pUIChild->JSObject()
-        ->GetMeasure(XFA_Attribute::Size)
-        .ToUnit(XFA_Unit::Pt);
-  }
-  return CXFA_Measurement(10, XFA_Unit::Pt).ToUnit(XFA_Unit::Pt);
-}
-
-bool CXFA_WidgetAcc::IsAllowNeutral() {
-  CXFA_Node* pUIChild = GetUIChild();
-  return pUIChild &&
-         pUIChild->JSObject()->GetBoolean(XFA_Attribute::AllowNeutral);
-}
-
-XFA_CHECKSTATE CXFA_WidgetAcc::GetCheckState() {
-  WideString wsValue = m_pNode->GetRawValue();
-  if (wsValue.IsEmpty())
-    return XFA_CHECKSTATE_Off;
-
-  auto* pItems = m_pNode->GetChild<CXFA_Items>(0, XFA_Element::Items, false);
-  if (!pItems)
-    return XFA_CHECKSTATE_Off;
-
-  CXFA_Node* pText = pItems->GetFirstChild();
-  int32_t i = 0;
-  while (pText) {
-    Optional<WideString> wsContent = pText->JSObject()->TryContent(false, true);
-    if (wsContent && *wsContent == wsValue)
-      return static_cast<XFA_CHECKSTATE>(i);
-
-    i++;
-    pText = pText->GetNextSibling();
-  }
-  return XFA_CHECKSTATE_Off;
-}
-
-void CXFA_WidgetAcc::SetCheckState(XFA_CHECKSTATE eCheckState, bool bNotify) {
-  CXFA_Node* node = m_pNode->GetExclGroupIfExists();
-  if (!node) {
-    CXFA_Items* pItems =
-        m_pNode->GetChild<CXFA_Items>(0, XFA_Element::Items, false);
-    if (!pItems)
-      return;
-
-    int32_t i = -1;
-    CXFA_Node* pText = pItems->GetFirstChild();
-    WideString wsContent;
-    while (pText) {
-      i++;
-      if (i == eCheckState) {
-        wsContent = pText->JSObject()->GetContent(false);
-        break;
-      }
-      pText = pText->GetNextSibling();
-    }
-    if (m_pNode)
-      m_pNode->SyncValue(wsContent, bNotify);
-
-    return;
-  }
-
-  WideString wsValue;
-  if (eCheckState != XFA_CHECKSTATE_Off) {
-    if (CXFA_Items* pItems =
-            m_pNode->GetChild<CXFA_Items>(0, XFA_Element::Items, false)) {
-      CXFA_Node* pText = pItems->GetFirstChild();
-      if (pText)
-        wsValue = pText->JSObject()->GetContent(false);
-    }
-  }
-  CXFA_Node* pChild = node->GetFirstChild();
-  for (; pChild; pChild = pChild->GetNextSibling()) {
-    if (pChild->GetElementType() != XFA_Element::Field)
-      continue;
-
-    CXFA_Items* pItem =
-        pChild->GetChild<CXFA_Items>(0, XFA_Element::Items, false);
-    if (!pItem)
-      continue;
-
-    CXFA_Node* pItemchild = pItem->GetFirstChild();
-    if (!pItemchild)
-      continue;
-
-    WideString text = pItemchild->JSObject()->GetContent(false);
-    WideString wsChildValue = text;
-    if (wsValue != text) {
-      pItemchild = pItemchild->GetNextSibling();
-      if (pItemchild)
-        wsChildValue = pItemchild->JSObject()->GetContent(false);
-      else
-        wsChildValue.clear();
-    }
-    pChild->SyncValue(wsChildValue, bNotify);
-  }
-  node->SyncValue(wsValue, bNotify);
-}
-
-CXFA_Node* CXFA_WidgetAcc::GetSelectedMember() {
-  CXFA_Node* pSelectedMember = nullptr;
-  WideString wsState = m_pNode->GetRawValue();
-  if (wsState.IsEmpty())
-    return pSelectedMember;
-
-  for (CXFA_Node* pNode = ToNode(m_pNode->GetFirstChild()); pNode;
-       pNode = pNode->GetNextSibling()) {
-    CXFA_WidgetAcc widgetData(pNode);
-    if (widgetData.GetCheckState() == XFA_CHECKSTATE_On) {
-      pSelectedMember = pNode;
-      break;
-    }
-  }
-  return pSelectedMember;
-}
-
-CXFA_Node* CXFA_WidgetAcc::SetSelectedMember(const WideStringView& wsName,
-                                             bool bNotify) {
-  uint32_t nameHash = FX_HashCode_GetW(wsName, false);
-  for (CXFA_Node* pNode = ToNode(m_pNode->GetFirstChild()); pNode;
-       pNode = pNode->GetNextSibling()) {
-    if (pNode->GetNameHash() == nameHash) {
-      CXFA_WidgetAcc widgetData(pNode);
-      widgetData.SetCheckState(XFA_CHECKSTATE_On, bNotify);
-      return pNode;
-    }
-  }
-  return nullptr;
-}
-
-void CXFA_WidgetAcc::SetSelectedMemberByValue(const WideStringView& wsValue,
-                                              bool bNotify,
-                                              bool bScriptModify,
-                                              bool bSyncData) {
-  WideString wsExclGroup;
-  for (CXFA_Node* pNode = m_pNode->GetFirstChild(); pNode;
-       pNode = pNode->GetNextSibling()) {
-    if (pNode->GetElementType() != XFA_Element::Field)
-      continue;
-
-    CXFA_Items* pItem =
-        pNode->GetChild<CXFA_Items>(0, XFA_Element::Items, false);
-    if (!pItem)
-      continue;
-
-    CXFA_Node* pItemchild = pItem->GetFirstChild();
-    if (!pItemchild)
-      continue;
-
-    WideString wsChildValue = pItemchild->JSObject()->GetContent(false);
-    if (wsValue != wsChildValue) {
-      pItemchild = pItemchild->GetNextSibling();
-      if (pItemchild)
-        wsChildValue = pItemchild->JSObject()->GetContent(false);
-      else
-        wsChildValue.clear();
-    } else {
-      wsExclGroup = wsValue;
-    }
-    pNode->JSObject()->SetContent(wsChildValue, wsChildValue, bNotify,
-                                  bScriptModify, false);
-  }
-  if (m_pNode) {
-    m_pNode->JSObject()->SetContent(wsExclGroup, wsExclGroup, bNotify,
-                                    bScriptModify, bSyncData);
-  }
-}
-
-CXFA_Node* CXFA_WidgetAcc::GetExclGroupFirstMember() {
-  CXFA_Node* pExcl = GetNode();
-  if (!pExcl)
-    return nullptr;
-
-  CXFA_Node* pNode = pExcl->GetFirstChild();
-  while (pNode) {
-    if (pNode->GetElementType() == XFA_Element::Field)
-      return pNode;
-
-    pNode = pNode->GetNextSibling();
-  }
-  return nullptr;
-}
-CXFA_Node* CXFA_WidgetAcc::GetExclGroupNextMember(CXFA_Node* pNode) {
-  if (!pNode)
-    return nullptr;
-
-  CXFA_Node* pNodeField = pNode->GetNextSibling();
-  while (pNodeField) {
-    if (pNodeField->GetElementType() == XFA_Element::Field)
-      return pNodeField;
-
-    pNodeField = pNodeField->GetNextSibling();
-  }
-  return nullptr;
-}
-
-bool CXFA_WidgetAcc::IsChoiceListCommitOnSelect() {
-  CXFA_Node* pUIChild = GetUIChild();
-  if (pUIChild) {
-    return pUIChild->JSObject()->GetEnum(XFA_Attribute::CommitOn) ==
-           XFA_AttributeEnum::Select;
-  }
-  return true;
-}
-
-bool CXFA_WidgetAcc::IsChoiceListAllowTextEntry() {
-  CXFA_Node* pUIChild = GetUIChild();
-  return pUIChild && pUIChild->JSObject()->GetBoolean(XFA_Attribute::TextEntry);
-}
-
-bool CXFA_WidgetAcc::IsChoiceListMultiSelect() {
-  CXFA_Node* pUIChild = GetUIChild();
-  if (pUIChild) {
-    return pUIChild->JSObject()->GetEnum(XFA_Attribute::Open) ==
-           XFA_AttributeEnum::MultiSelect;
-  }
-  return false;
-}
-
-bool CXFA_WidgetAcc::IsListBox() {
-  CXFA_Node* pUIChild = GetUIChild();
-  if (!pUIChild)
-    return false;
-
-  XFA_AttributeEnum attr = pUIChild->JSObject()->GetEnum(XFA_Attribute::Open);
-  return attr == XFA_AttributeEnum::Always ||
-         attr == XFA_AttributeEnum::MultiSelect;
-}
-
-int32_t CXFA_WidgetAcc::CountChoiceListItems(bool bSaveValue) {
-  std::vector<CXFA_Node*> pItems;
-  int32_t iCount = 0;
-  for (CXFA_Node* pNode = m_pNode->GetFirstChild(); pNode;
-       pNode = pNode->GetNextSibling()) {
-    if (pNode->GetElementType() != XFA_Element::Items)
-      continue;
-    iCount++;
-    pItems.push_back(pNode);
-    if (iCount == 2)
-      break;
-  }
-  if (iCount == 0)
-    return 0;
-
-  CXFA_Node* pItem = pItems[0];
-  if (iCount > 1) {
-    bool bItemOneHasSave =
-        pItems[0]->JSObject()->GetBoolean(XFA_Attribute::Save);
-    bool bItemTwoHasSave =
-        pItems[1]->JSObject()->GetBoolean(XFA_Attribute::Save);
-    if (bItemOneHasSave != bItemTwoHasSave && bSaveValue == bItemTwoHasSave)
-      pItem = pItems[1];
-  }
-  return pItem->CountChildren(XFA_Element::Unknown, false);
-}
-
-Optional<WideString> CXFA_WidgetAcc::GetChoiceListItem(int32_t nIndex,
-                                                       bool bSaveValue) {
-  std::vector<CXFA_Node*> pItemsArray;
-  int32_t iCount = 0;
-  for (CXFA_Node* pNode = m_pNode->GetFirstChild(); pNode;
-       pNode = pNode->GetNextSibling()) {
-    if (pNode->GetElementType() != XFA_Element::Items)
-      continue;
-
-    ++iCount;
-    pItemsArray.push_back(pNode);
-    if (iCount == 2)
-      break;
-  }
-  if (iCount == 0)
-    return {};
-
-  CXFA_Node* pItems = pItemsArray[0];
-  if (iCount > 1) {
-    bool bItemOneHasSave =
-        pItemsArray[0]->JSObject()->GetBoolean(XFA_Attribute::Save);
-    bool bItemTwoHasSave =
-        pItemsArray[1]->JSObject()->GetBoolean(XFA_Attribute::Save);
-    if (bItemOneHasSave != bItemTwoHasSave && bSaveValue == bItemTwoHasSave)
-      pItems = pItemsArray[1];
-  }
-  if (!pItems)
-    return {};
-
-  CXFA_Node* pItem =
-      pItems->GetChild<CXFA_Node>(nIndex, XFA_Element::Unknown, false);
-  if (pItem)
-    return {pItem->JSObject()->GetContent(false)};
-  return {};
-}
-
-std::vector<WideString> CXFA_WidgetAcc::GetChoiceListItems(bool bSaveValue) {
-  std::vector<CXFA_Node*> items;
-  for (CXFA_Node* pNode = m_pNode->GetFirstChild(); pNode && items.size() < 2;
-       pNode = pNode->GetNextSibling()) {
-    if (pNode->GetElementType() == XFA_Element::Items)
-      items.push_back(pNode);
-  }
-  if (items.empty())
-    return std::vector<WideString>();
-
-  CXFA_Node* pItem = items.front();
-  if (items.size() > 1) {
-    bool bItemOneHasSave =
-        items[0]->JSObject()->GetBoolean(XFA_Attribute::Save);
-    bool bItemTwoHasSave =
-        items[1]->JSObject()->GetBoolean(XFA_Attribute::Save);
-    if (bItemOneHasSave != bItemTwoHasSave && bSaveValue == bItemTwoHasSave)
-      pItem = items[1];
-  }
-
-  std::vector<WideString> wsTextArray;
-  for (CXFA_Node* pNode = pItem->GetFirstChild(); pNode;
-       pNode = pNode->GetNextSibling()) {
-    wsTextArray.emplace_back(pNode->JSObject()->GetContent(false));
-  }
-  return wsTextArray;
-}
-
-int32_t CXFA_WidgetAcc::CountSelectedItems() {
-  std::vector<WideString> wsValueArray = GetSelectedItemsValue();
-  if (IsListBox() || !IsChoiceListAllowTextEntry())
-    return pdfium::CollectionSize<int32_t>(wsValueArray);
-
-  int32_t iSelected = 0;
-  std::vector<WideString> wsSaveTextArray = GetChoiceListItems(true);
-  for (const auto& value : wsValueArray) {
-    if (pdfium::ContainsValue(wsSaveTextArray, value))
-      iSelected++;
-  }
-  return iSelected;
-}
-
-int32_t CXFA_WidgetAcc::GetSelectedItem(int32_t nIndex) {
-  std::vector<WideString> wsValueArray = GetSelectedItemsValue();
-  if (!pdfium::IndexInBounds(wsValueArray, nIndex))
-    return -1;
-
-  std::vector<WideString> wsSaveTextArray = GetChoiceListItems(true);
-  auto it = std::find(wsSaveTextArray.begin(), wsSaveTextArray.end(),
-                      wsValueArray[nIndex]);
-  return it != wsSaveTextArray.end() ? it - wsSaveTextArray.begin() : -1;
-}
-
-std::vector<int32_t> CXFA_WidgetAcc::GetSelectedItems() {
-  std::vector<int32_t> iSelArray;
-  std::vector<WideString> wsValueArray = GetSelectedItemsValue();
-  std::vector<WideString> wsSaveTextArray = GetChoiceListItems(true);
-  for (const auto& value : wsValueArray) {
-    auto it = std::find(wsSaveTextArray.begin(), wsSaveTextArray.end(), value);
-    if (it != wsSaveTextArray.end())
-      iSelArray.push_back(it - wsSaveTextArray.begin());
-  }
-  return iSelArray;
-}
-
-std::vector<WideString> CXFA_WidgetAcc::GetSelectedItemsValue() {
-  std::vector<WideString> wsSelTextArray;
-  WideString wsValue = m_pNode->GetRawValue();
-  if (IsChoiceListMultiSelect()) {
-    if (!wsValue.IsEmpty()) {
-      size_t iStart = 0;
-      size_t iLength = wsValue.GetLength();
-      auto iEnd = wsValue.Find(L'\n', iStart);
-      iEnd = (!iEnd.has_value()) ? iLength : iEnd;
-      while (iEnd >= iStart) {
-        wsSelTextArray.push_back(wsValue.Mid(iStart, iEnd.value() - iStart));
-        iStart = iEnd.value() + 1;
-        if (iStart >= iLength)
-          break;
-        iEnd = wsValue.Find(L'\n', iStart);
-        if (!iEnd.has_value())
-          wsSelTextArray.push_back(wsValue.Mid(iStart, iLength - iStart));
-      }
-    }
-  } else {
-    wsSelTextArray.push_back(wsValue);
-  }
-  return wsSelTextArray;
-}
-
-bool CXFA_WidgetAcc::GetItemState(int32_t nIndex) {
-  std::vector<WideString> wsSaveTextArray = GetChoiceListItems(true);
-  return pdfium::IndexInBounds(wsSaveTextArray, nIndex) &&
-         pdfium::ContainsValue(GetSelectedItemsValue(),
-                               wsSaveTextArray[nIndex]);
-}
-
-void CXFA_WidgetAcc::SetItemState(int32_t nIndex,
-                                  bool bSelected,
-                                  bool bNotify,
-                                  bool bScriptModify,
-                                  bool bSyncData) {
-  std::vector<WideString> wsSaveTextArray = GetChoiceListItems(true);
-  if (!pdfium::IndexInBounds(wsSaveTextArray, nIndex))
-    return;
-
-  int32_t iSel = -1;
-  std::vector<WideString> wsValueArray = GetSelectedItemsValue();
-  auto it = std::find(wsValueArray.begin(), wsValueArray.end(),
-                      wsSaveTextArray[nIndex]);
-  if (it != wsValueArray.end())
-    iSel = it - wsValueArray.begin();
-
-  if (IsChoiceListMultiSelect()) {
-    if (bSelected) {
-      if (iSel < 0) {
-        WideString wsValue = m_pNode->GetRawValue();
-        if (!wsValue.IsEmpty()) {
-          wsValue += L"\n";
-        }
-        wsValue += wsSaveTextArray[nIndex];
-        m_pNode->JSObject()->SetContent(wsValue, wsValue, bNotify,
-                                        bScriptModify, bSyncData);
-      }
-    } else if (iSel >= 0) {
-      std::vector<int32_t> iSelArray = GetSelectedItems();
-      auto it = std::find(iSelArray.begin(), iSelArray.end(), nIndex);
-      if (it != iSelArray.end())
-        iSelArray.erase(it);
-      SetSelectedItems(iSelArray, bNotify, bScriptModify, bSyncData);
-    }
-  } else {
-    if (bSelected) {
-      if (iSel < 0) {
-        WideString wsSaveText = wsSaveTextArray[nIndex];
-        m_pNode->JSObject()->SetContent(wsSaveText,
-                                        GetFormatDataValue(wsSaveText), bNotify,
-                                        bScriptModify, bSyncData);
-      }
-    } else if (iSel >= 0) {
-      m_pNode->JSObject()->SetContent(WideString(), WideString(), bNotify,
-                                      bScriptModify, bSyncData);
-    }
-  }
-}
-
-void CXFA_WidgetAcc::SetSelectedItems(const std::vector<int32_t>& iSelArray,
-                                      bool bNotify,
-                                      bool bScriptModify,
-                                      bool bSyncData) {
-  WideString wsValue;
-  int32_t iSize = pdfium::CollectionSize<int32_t>(iSelArray);
-  if (iSize >= 1) {
-    std::vector<WideString> wsSaveTextArray = GetChoiceListItems(true);
-    WideString wsItemValue;
-    for (int32_t i = 0; i < iSize; i++) {
-      wsItemValue = (iSize == 1) ? wsSaveTextArray[iSelArray[i]]
-                                 : wsSaveTextArray[iSelArray[i]] + L"\n";
-      wsValue += wsItemValue;
-    }
-  }
-  WideString wsFormat(wsValue);
-  if (!IsChoiceListMultiSelect())
-    wsFormat = GetFormatDataValue(wsValue);
-
-  m_pNode->JSObject()->SetContent(wsValue, wsFormat, bNotify, bScriptModify,
-                                  bSyncData);
-}
-
-void CXFA_WidgetAcc::ClearAllSelections() {
-  CXFA_Node* pBind = m_pNode->GetBindData();
-  if (!pBind || !IsChoiceListMultiSelect()) {
-    m_pNode->SyncValue(WideString(), false);
-    return;
-  }
-
-  while (CXFA_Node* pChildNode = pBind->GetFirstChild())
-    pBind->RemoveChild(pChildNode, true);
-}
-
-void CXFA_WidgetAcc::InsertItem(const WideString& wsLabel,
-                                const WideString& wsValue,
-                                bool bNotify) {
-  int32_t nIndex = -1;
-  WideString wsNewValue(wsValue);
-  if (wsNewValue.IsEmpty())
-    wsNewValue = wsLabel;
-
-  std::vector<CXFA_Node*> listitems;
-  for (CXFA_Node* pItem = m_pNode->GetFirstChild(); pItem;
-       pItem = pItem->GetNextSibling()) {
-    if (pItem->GetElementType() == XFA_Element::Items)
-      listitems.push_back(pItem);
-  }
-  if (listitems.empty()) {
-    CXFA_Node* pItems = m_pNode->CreateSamePacketNode(XFA_Element::Items);
-    m_pNode->InsertChild(-1, pItems);
-    InsertListTextItem(pItems, wsLabel, nIndex);
-    CXFA_Node* pSaveItems = m_pNode->CreateSamePacketNode(XFA_Element::Items);
-    m_pNode->InsertChild(-1, pSaveItems);
-    pSaveItems->JSObject()->SetBoolean(XFA_Attribute::Save, true, false);
-    InsertListTextItem(pSaveItems, wsNewValue, nIndex);
-  } else if (listitems.size() > 1) {
-    for (int32_t i = 0; i < 2; i++) {
-      CXFA_Node* pNode = listitems[i];
-      bool bHasSave = pNode->JSObject()->GetBoolean(XFA_Attribute::Save);
-      if (bHasSave)
-        InsertListTextItem(pNode, wsNewValue, nIndex);
-      else
-        InsertListTextItem(pNode, wsLabel, nIndex);
-    }
-  } else {
-    CXFA_Node* pNode = listitems[0];
-    pNode->JSObject()->SetBoolean(XFA_Attribute::Save, false, false);
-    pNode->JSObject()->SetEnum(XFA_Attribute::Presence,
-                               XFA_AttributeEnum::Visible, false);
-    CXFA_Node* pSaveItems = m_pNode->CreateSamePacketNode(XFA_Element::Items);
-    m_pNode->InsertChild(-1, pSaveItems);
-    pSaveItems->JSObject()->SetBoolean(XFA_Attribute::Save, true, false);
-    pSaveItems->JSObject()->SetEnum(XFA_Attribute::Presence,
-                                    XFA_AttributeEnum::Hidden, false);
-    CXFA_Node* pListNode = pNode->GetFirstChild();
-    int32_t i = 0;
-    while (pListNode) {
-      InsertListTextItem(pSaveItems, pListNode->JSObject()->GetContent(false),
-                         i);
-      ++i;
-
-      pListNode = pListNode->GetNextSibling();
-    }
-    InsertListTextItem(pNode, wsLabel, nIndex);
-    InsertListTextItem(pSaveItems, wsNewValue, nIndex);
-  }
-  if (!bNotify)
-    return;
-
-  m_pNode->GetDocument()->GetNotify()->OnWidgetListItemAdded(
-      this, wsLabel.c_str(), wsValue.c_str(), nIndex);
-}
-
-void CXFA_WidgetAcc::GetItemLabel(const WideStringView& wsValue,
-                                  WideString& wsLabel) {
-  int32_t iCount = 0;
-  std::vector<CXFA_Node*> listitems;
-  CXFA_Node* pItems = m_pNode->GetFirstChild();
-  for (; pItems; pItems = pItems->GetNextSibling()) {
-    if (pItems->GetElementType() != XFA_Element::Items)
-      continue;
-    iCount++;
-    listitems.push_back(pItems);
-  }
-
-  if (iCount <= 1) {
-    wsLabel = wsValue;
-    return;
-  }
-
-  CXFA_Node* pLabelItems = listitems[0];
-  bool bSave = pLabelItems->JSObject()->GetBoolean(XFA_Attribute::Save);
-  CXFA_Node* pSaveItems = nullptr;
-  if (bSave) {
-    pSaveItems = pLabelItems;
-    pLabelItems = listitems[1];
-  } else {
-    pSaveItems = listitems[1];
-  }
-  iCount = 0;
-
-  int32_t iSearch = -1;
-  for (CXFA_Node* pChildItem = pSaveItems->GetFirstChild(); pChildItem;
-       pChildItem = pChildItem->GetNextSibling()) {
-    if (pChildItem->JSObject()->GetContent(false) == wsValue) {
-      iSearch = iCount;
-      break;
-    }
-    iCount++;
-  }
-  if (iSearch < 0)
-    return;
-
-  CXFA_Node* pText =
-      pLabelItems->GetChild<CXFA_Node>(iSearch, XFA_Element::Unknown, false);
-  if (pText)
-    wsLabel = pText->JSObject()->GetContent(false);
-}
-
-WideString CXFA_WidgetAcc::GetItemValue(const WideStringView& wsLabel) {
-  int32_t iCount = 0;
-  std::vector<CXFA_Node*> listitems;
-  for (CXFA_Node* pItems = m_pNode->GetFirstChild(); pItems;
-       pItems = pItems->GetNextSibling()) {
-    if (pItems->GetElementType() != XFA_Element::Items)
-      continue;
-    iCount++;
-    listitems.push_back(pItems);
-  }
-  if (iCount <= 1)
-    return WideString(wsLabel);
-
-  CXFA_Node* pLabelItems = listitems[0];
-  bool bSave = pLabelItems->JSObject()->GetBoolean(XFA_Attribute::Save);
-  CXFA_Node* pSaveItems = nullptr;
-  if (bSave) {
-    pSaveItems = pLabelItems;
-    pLabelItems = listitems[1];
-  } else {
-    pSaveItems = listitems[1];
-  }
-  iCount = 0;
-
-  int32_t iSearch = -1;
-  WideString wsContent;
-  CXFA_Node* pChildItem = pLabelItems->GetFirstChild();
-  for (; pChildItem; pChildItem = pChildItem->GetNextSibling()) {
-    if (pChildItem->JSObject()->GetContent(false) == wsLabel) {
-      iSearch = iCount;
-      break;
-    }
-    iCount++;
-  }
-  if (iSearch < 0)
-    return L"";
-
-  CXFA_Node* pText =
-      pSaveItems->GetChild<CXFA_Node>(iSearch, XFA_Element::Unknown, false);
-  return pText ? pText->JSObject()->GetContent(false) : L"";
-}
-
-bool CXFA_WidgetAcc::DeleteItem(int32_t nIndex,
-                                bool bNotify,
-                                bool bScriptModify) {
-  bool bSetValue = false;
-  CXFA_Node* pItems = m_pNode->GetFirstChild();
-  for (; pItems; pItems = pItems->GetNextSibling()) {
-    if (pItems->GetElementType() != XFA_Element::Items)
-      continue;
-
-    if (nIndex < 0) {
-      while (CXFA_Node* pNode = pItems->GetFirstChild()) {
-        pItems->RemoveChild(pNode, true);
-      }
-    } else {
-      if (!bSetValue && pItems->JSObject()->GetBoolean(XFA_Attribute::Save)) {
-        SetItemState(nIndex, false, true, bScriptModify, true);
-        bSetValue = true;
-      }
-      int32_t i = 0;
-      CXFA_Node* pNode = pItems->GetFirstChild();
-      while (pNode) {
-        if (i == nIndex) {
-          pItems->RemoveChild(pNode, true);
-          break;
-        }
-        i++;
-        pNode = pNode->GetNextSibling();
-      }
-    }
-  }
-  if (bNotify)
-    m_pNode->GetDocument()->GetNotify()->OnWidgetListItemRemoved(this, nIndex);
-  return true;
-}
-
-bool CXFA_WidgetAcc::IsHorizontalScrollPolicyOff() {
-  CXFA_Node* pUIChild = GetUIChild();
-  if (pUIChild) {
-    return pUIChild->JSObject()->GetEnum(XFA_Attribute::HScrollPolicy) ==
-           XFA_AttributeEnum::Off;
-  }
-  return false;
-}
-
-bool CXFA_WidgetAcc::IsVerticalScrollPolicyOff() {
-  CXFA_Node* pUIChild = GetUIChild();
-  if (pUIChild) {
-    return pUIChild->JSObject()->GetEnum(XFA_Attribute::VScrollPolicy) ==
-           XFA_AttributeEnum::Off;
-  }
-  return false;
-}
-
-Optional<int32_t> CXFA_WidgetAcc::GetNumberOfCells() {
-  CXFA_Node* pUIChild = GetUIChild();
-  if (!pUIChild)
-    return {};
-  if (CXFA_Comb* pNode =
-          pUIChild->GetChild<CXFA_Comb>(0, XFA_Element::Comb, false))
-    return {pNode->JSObject()->GetInteger(XFA_Attribute::NumberOfCells)};
-  return {};
-}
-
-WideString CXFA_WidgetAcc::GetPasswordChar() {
-  CXFA_Node* pUIChild = GetUIChild();
-  return pUIChild ? pUIChild->JSObject()->GetCData(XFA_Attribute::PasswordChar)
-                  : L"*";
-}
-
-bool CXFA_WidgetAcc::IsMultiLine() {
-  CXFA_Node* pUIChild = GetUIChild();
-  return pUIChild && pUIChild->JSObject()->GetBoolean(XFA_Attribute::MultiLine);
-}
-
-std::pair<XFA_Element, int32_t> CXFA_WidgetAcc::GetMaxChars() {
-  if (CXFA_Value* pNode =
-          m_pNode->GetChild<CXFA_Value>(0, XFA_Element::Value, false)) {
-    if (CXFA_Node* pChild = pNode->GetFirstChild()) {
-      switch (pChild->GetElementType()) {
-        case XFA_Element::Text:
-          return {XFA_Element::Text,
-                  pChild->JSObject()->GetInteger(XFA_Attribute::MaxChars)};
-        case XFA_Element::ExData: {
-          int32_t iMax =
-              pChild->JSObject()->GetInteger(XFA_Attribute::MaxLength);
-          return {XFA_Element::ExData, iMax < 0 ? 0 : iMax};
-        }
-        default:
-          break;
-      }
-    }
-  }
-  return {XFA_Element::Unknown, 0};
-}
-
-int32_t CXFA_WidgetAcc::GetFracDigits() {
-  CXFA_Value* pNode =
-      m_pNode->GetChild<CXFA_Value>(0, XFA_Element::Value, false);
-  if (!pNode)
-    return -1;
-
-  CXFA_Decimal* pChild =
-      pNode->GetChild<CXFA_Decimal>(0, XFA_Element::Decimal, false);
-  if (!pChild)
-    return -1;
-
-  return pChild->JSObject()
-      ->TryInteger(XFA_Attribute::FracDigits, true)
-      .value_or(-1);
-}
-
-int32_t CXFA_WidgetAcc::GetLeadDigits() {
-  CXFA_Value* pNode =
-      m_pNode->GetChild<CXFA_Value>(0, XFA_Element::Value, false);
-  if (!pNode)
-    return -1;
-
-  CXFA_Decimal* pChild =
-      pNode->GetChild<CXFA_Decimal>(0, XFA_Element::Decimal, false);
-  if (!pChild)
-    return -1;
-
-  return pChild->JSObject()
-      ->TryInteger(XFA_Attribute::LeadDigits, true)
-      .value_or(-1);
-}
-
-bool CXFA_WidgetAcc::SetValue(XFA_VALUEPICTURE eValueType,
-                              const WideString& wsValue) {
-  if (wsValue.IsEmpty()) {
-    if (m_pNode)
-      m_pNode->SyncValue(wsValue, true);
-    return true;
-  }
-
-  m_bPreNull = m_bIsNull;
-  m_bIsNull = false;
-  WideString wsNewText(wsValue);
-  WideString wsPicture = GetPictureContent(eValueType);
-  bool bValidate = true;
-  bool bSyncData = false;
-  CXFA_Node* pNode = GetUIChild();
-  if (!pNode)
-    return true;
-
-  XFA_Element eType = pNode->GetElementType();
-  if (!wsPicture.IsEmpty()) {
-    CXFA_LocaleMgr* pLocalMgr = m_pNode->GetDocument()->GetLocalMgr();
-    IFX_Locale* pLocale = GetLocale();
-    CXFA_LocaleValue widgetValue = XFA_GetLocaleValue(GetNode());
-    bValidate =
-        widgetValue.ValidateValue(wsValue, wsPicture, pLocale, &wsPicture);
-    if (bValidate) {
-      widgetValue = CXFA_LocaleValue(widgetValue.GetType(), wsNewText,
-                                     wsPicture, pLocale, pLocalMgr);
-      wsNewText = widgetValue.GetValue();
-      if (eType == XFA_Element::NumericEdit)
-        wsNewText = NumericLimit(wsNewText, GetLeadDigits(), GetFracDigits());
-
-      bSyncData = true;
-    }
-  } else {
-    if (eType == XFA_Element::NumericEdit) {
-      if (wsNewText != L"0")
-        wsNewText = NumericLimit(wsNewText, GetLeadDigits(), GetFracDigits());
-
-      bSyncData = true;
-    }
-  }
-  if (eType != XFA_Element::NumericEdit || bSyncData) {
-    if (m_pNode)
-      m_pNode->SyncValue(wsNewText, true);
-  }
-
-  return bValidate;
-}
-
-WideString CXFA_WidgetAcc::GetPictureContent(XFA_VALUEPICTURE ePicture) {
-  if (ePicture == XFA_VALUEPICTURE_Raw)
-    return L"";
-
-  CXFA_LocaleValue widgetValue = XFA_GetLocaleValue(GetNode());
-  switch (ePicture) {
-    case XFA_VALUEPICTURE_Display: {
-      if (CXFA_Format* pFormat =
-              m_pNode->GetChild<CXFA_Format>(0, XFA_Element::Format, false)) {
-        if (CXFA_Picture* pPicture = pFormat->GetChild<CXFA_Picture>(
-                0, XFA_Element::Picture, false)) {
-          Optional<WideString> picture =
-              pPicture->JSObject()->TryContent(false, true);
-          if (picture)
-            return *picture;
-        }
-      }
-
-      IFX_Locale* pLocale = GetLocale();
-      if (!pLocale)
-        return L"";
-
-      uint32_t dwType = widgetValue.GetType();
-      switch (dwType) {
-        case XFA_VT_DATE:
-          return pLocale->GetDatePattern(FX_LOCALEDATETIMESUBCATEGORY_Medium);
-        case XFA_VT_TIME:
-          return pLocale->GetTimePattern(FX_LOCALEDATETIMESUBCATEGORY_Medium);
-        case XFA_VT_DATETIME:
-          return pLocale->GetDatePattern(FX_LOCALEDATETIMESUBCATEGORY_Medium) +
-                 L"T" +
-                 pLocale->GetTimePattern(FX_LOCALEDATETIMESUBCATEGORY_Medium);
-        case XFA_VT_DECIMAL:
-        case XFA_VT_FLOAT:
-        default:
-          return L"";
-      }
-    }
-    case XFA_VALUEPICTURE_Edit: {
-      CXFA_Ui* pUI = m_pNode->GetChild<CXFA_Ui>(0, XFA_Element::Ui, false);
-      if (pUI) {
-        if (CXFA_Picture* pPicture =
-                pUI->GetChild<CXFA_Picture>(0, XFA_Element::Picture, false)) {
-          Optional<WideString> picture =
-              pPicture->JSObject()->TryContent(false, true);
-          if (picture)
-            return *picture;
-        }
-      }
-
-      IFX_Locale* pLocale = GetLocale();
-      if (!pLocale)
-        return L"";
-
-      uint32_t dwType = widgetValue.GetType();
-      switch (dwType) {
-        case XFA_VT_DATE:
-          return pLocale->GetDatePattern(FX_LOCALEDATETIMESUBCATEGORY_Short);
-        case XFA_VT_TIME:
-          return pLocale->GetTimePattern(FX_LOCALEDATETIMESUBCATEGORY_Short);
-        case XFA_VT_DATETIME:
-          return pLocale->GetDatePattern(FX_LOCALEDATETIMESUBCATEGORY_Short) +
-                 L"T" +
-                 pLocale->GetTimePattern(FX_LOCALEDATETIMESUBCATEGORY_Short);
-        default:
-          return L"";
-      }
-    }
-    case XFA_VALUEPICTURE_DataBind: {
-      CXFA_Bind* bind = m_pNode->GetBindIfExists();
-      if (bind)
-        return bind->GetPicture();
-      break;
-    }
-    default:
-      break;
-  }
-  return L"";
-}
-
-IFX_Locale* CXFA_WidgetAcc::GetLocale() {
-  return m_pNode ? m_pNode->GetLocale() : nullptr;
-}
-
-WideString CXFA_WidgetAcc::GetValue(XFA_VALUEPICTURE eValueType) {
-  WideString wsValue = m_pNode->JSObject()->GetContent(false);
-
-  if (eValueType == XFA_VALUEPICTURE_Display)
-    GetItemLabel(wsValue.AsStringView(), wsValue);
-
-  WideString wsPicture = GetPictureContent(eValueType);
-  CXFA_Node* pNode = GetUIChild();
-  if (!pNode)
-    return wsValue;
-
-  switch (GetUIChild()->GetElementType()) {
-    case XFA_Element::ChoiceList: {
-      if (eValueType == XFA_VALUEPICTURE_Display) {
-        int32_t iSelItemIndex = GetSelectedItem(0);
-        if (iSelItemIndex >= 0) {
-          wsValue = GetChoiceListItem(iSelItemIndex, false).value_or(L"");
-          wsPicture.clear();
-        }
-      }
-    } break;
-    case XFA_Element::NumericEdit:
-      if (eValueType != XFA_VALUEPICTURE_Raw && wsPicture.IsEmpty()) {
-        IFX_Locale* pLocale = GetLocale();
-        if (eValueType == XFA_VALUEPICTURE_Display && pLocale)
-          wsValue = FormatNumStr(NormalizeNumStr(wsValue), pLocale);
-      }
-      break;
-    default:
-      break;
-  }
-  if (wsPicture.IsEmpty())
-    return wsValue;
-
-  if (IFX_Locale* pLocale = GetLocale()) {
-    CXFA_LocaleValue widgetValue = XFA_GetLocaleValue(GetNode());
-    CXFA_LocaleMgr* pLocalMgr = m_pNode->GetDocument()->GetLocalMgr();
-    switch (widgetValue.GetType()) {
-      case XFA_VT_DATE: {
-        WideString wsDate, wsTime;
-        if (SplitDateTime(wsValue, wsDate, wsTime)) {
-          CXFA_LocaleValue date(XFA_VT_DATE, wsDate, pLocalMgr);
-          if (date.FormatPatterns(wsValue, wsPicture, pLocale, eValueType))
-            return wsValue;
-        }
-        break;
-      }
-      case XFA_VT_TIME: {
-        WideString wsDate, wsTime;
-        if (SplitDateTime(wsValue, wsDate, wsTime)) {
-          CXFA_LocaleValue time(XFA_VT_TIME, wsTime, pLocalMgr);
-          if (time.FormatPatterns(wsValue, wsPicture, pLocale, eValueType))
-            return wsValue;
-        }
-        break;
-      }
-      default:
-        break;
-    }
-    widgetValue.FormatPatterns(wsValue, wsPicture, pLocale, eValueType);
-  }
-  return wsValue;
-}
-
-WideString CXFA_WidgetAcc::GetNormalizeDataValue(const WideString& wsValue) {
-  if (wsValue.IsEmpty())
-    return L"";
-
-  WideString wsPicture = GetPictureContent(XFA_VALUEPICTURE_DataBind);
-  if (wsPicture.IsEmpty())
-    return wsValue;
-
-  ASSERT(GetNode());
-  CXFA_LocaleMgr* pLocalMgr = GetNode()->GetDocument()->GetLocalMgr();
-  IFX_Locale* pLocale = GetLocale();
-  CXFA_LocaleValue widgetValue = XFA_GetLocaleValue(GetNode());
-  if (widgetValue.ValidateValue(wsValue, wsPicture, pLocale, &wsPicture)) {
-    widgetValue = CXFA_LocaleValue(widgetValue.GetType(), wsValue, wsPicture,
-                                   pLocale, pLocalMgr);
-    return widgetValue.GetValue();
-  }
-  return wsValue;
-}
-
-WideString CXFA_WidgetAcc::GetFormatDataValue(const WideString& wsValue) {
-  if (wsValue.IsEmpty())
-    return L"";
-
-  WideString wsPicture = GetPictureContent(XFA_VALUEPICTURE_DataBind);
-  if (wsPicture.IsEmpty())
-    return wsValue;
-
-  WideString wsFormattedValue = wsValue;
-  if (IFX_Locale* pLocale = GetLocale()) {
-    ASSERT(GetNode());
-    CXFA_Value* pNodeValue =
-        GetNode()->GetChild<CXFA_Value>(0, XFA_Element::Value, false);
-    if (!pNodeValue)
-      return wsValue;
-
-    CXFA_Node* pValueChild = pNodeValue->GetFirstChild();
-    if (!pValueChild)
-      return wsValue;
-
-    int32_t iVTType = XFA_VT_NULL;
-    switch (pValueChild->GetElementType()) {
-      case XFA_Element::Decimal:
-        iVTType = XFA_VT_DECIMAL;
-        break;
-      case XFA_Element::Float:
-        iVTType = XFA_VT_FLOAT;
-        break;
-      case XFA_Element::Date:
-        iVTType = XFA_VT_DATE;
-        break;
-      case XFA_Element::Time:
-        iVTType = XFA_VT_TIME;
-        break;
-      case XFA_Element::DateTime:
-        iVTType = XFA_VT_DATETIME;
-        break;
-      case XFA_Element::Boolean:
-        iVTType = XFA_VT_BOOLEAN;
-        break;
-      case XFA_Element::Integer:
-        iVTType = XFA_VT_INTEGER;
-        break;
-      case XFA_Element::Text:
-        iVTType = XFA_VT_TEXT;
-        break;
-      default:
-        iVTType = XFA_VT_NULL;
-        break;
-    }
-    CXFA_LocaleMgr* pLocalMgr = GetNode()->GetDocument()->GetLocalMgr();
-    CXFA_LocaleValue widgetValue(iVTType, wsValue, pLocalMgr);
-    switch (widgetValue.GetType()) {
-      case XFA_VT_DATE: {
-        WideString wsDate, wsTime;
-        if (SplitDateTime(wsValue, wsDate, wsTime)) {
-          CXFA_LocaleValue date(XFA_VT_DATE, wsDate, pLocalMgr);
-          if (date.FormatPatterns(wsFormattedValue, wsPicture, pLocale,
-                                  XFA_VALUEPICTURE_DataBind)) {
-            return wsFormattedValue;
-          }
-        }
-        break;
-      }
-      case XFA_VT_TIME: {
-        WideString wsDate, wsTime;
-        if (SplitDateTime(wsValue, wsDate, wsTime)) {
-          CXFA_LocaleValue time(XFA_VT_TIME, wsTime, pLocalMgr);
-          if (time.FormatPatterns(wsFormattedValue, wsPicture, pLocale,
-                                  XFA_VALUEPICTURE_DataBind)) {
-            return wsFormattedValue;
-          }
-        }
-        break;
-      }
-      default:
-        break;
-    }
-    widgetValue.FormatPatterns(wsFormattedValue, wsPicture, pLocale,
-                               XFA_VALUEPICTURE_DataBind);
-  }
-  return wsFormattedValue;
-}
-
-WideString CXFA_WidgetAcc::NormalizeNumStr(const WideString& wsValue) {
-  if (wsValue.IsEmpty())
-    return L"";
-
-  WideString wsOutput = wsValue;
-  wsOutput.TrimLeft('0');
-
-  if (!wsOutput.IsEmpty() && wsOutput.Contains('.') && GetFracDigits() != -1) {
-    wsOutput.TrimRight(L"0");
-    wsOutput.TrimRight(L".");
-  }
-  if (wsOutput.IsEmpty() || wsOutput[0] == '.')
-    wsOutput.InsertAtFront('0');
-
-  return wsOutput;
-}
-
-WideString CXFA_WidgetAcc::FormatNumStr(const WideString& wsValue,
-                                        IFX_Locale* pLocale) {
-  if (wsValue.IsEmpty())
-    return L"";
-
-  WideString wsSrcNum = wsValue;
-  WideString wsGroupSymbol =
-      pLocale->GetNumbericSymbol(FX_LOCALENUMSYMBOL_Grouping);
-  bool bNeg = false;
-  if (wsSrcNum[0] == '-') {
-    bNeg = true;
-    wsSrcNum.Delete(0, 1);
-  }
-
-  auto dot_index = wsSrcNum.Find('.');
-  dot_index = !dot_index.has_value() ? wsSrcNum.GetLength() : dot_index;
-
-  if (dot_index.value() < 1)
-    return L"";
-
-  size_t nPos = dot_index.value() % 3;
-  WideString wsOutput;
-  for (size_t i = 0; i < dot_index.value(); i++) {
-    if (i % 3 == nPos && i != 0)
-      wsOutput += wsGroupSymbol;
-
-    wsOutput += wsSrcNum[i];
-  }
-  if (dot_index.value() < wsSrcNum.GetLength()) {
-    wsOutput += pLocale->GetNumbericSymbol(FX_LOCALENUMSYMBOL_Decimal);
-    wsOutput += wsSrcNum.Right(wsSrcNum.GetLength() - dot_index.value() - 1);
-  }
-  if (bNeg)
-    return pLocale->GetNumbericSymbol(FX_LOCALENUMSYMBOL_Minus) + wsOutput;
-
-  return wsOutput;
-}
-
-void CXFA_WidgetAcc::InsertListTextItem(CXFA_Node* pItems,
-                                        const WideString& wsText,
-                                        int32_t nIndex) {
-  CXFA_Node* pText = pItems->CreateSamePacketNode(XFA_Element::Text);
-  pItems->InsertChild(nIndex, pText);
-  pText->JSObject()->SetContent(wsText, wsText, false, false, false);
-}
-
-WideString CXFA_WidgetAcc::NumericLimit(const WideString& wsValue,
-                                        int32_t iLead,
-                                        int32_t iTread) const {
-  if ((iLead == -1) && (iTread == -1))
-    return wsValue;
-
-  WideString wsRet;
-  int32_t iLead_ = 0, iTread_ = -1;
-  int32_t iCount = wsValue.GetLength();
-  if (iCount == 0)
-    return wsValue;
-
-  int32_t i = 0;
-  if (wsValue[i] == L'-') {
-    wsRet += L'-';
-    i++;
-  }
-  for (; i < iCount; i++) {
-    wchar_t wc = wsValue[i];
-    if (FXSYS_isDecimalDigit(wc)) {
-      if (iLead >= 0) {
-        iLead_++;
-        if (iLead_ > iLead)
-          return L"0";
-      } else if (iTread_ >= 0) {
-        iTread_++;
-        if (iTread_ > iTread) {
-          if (iTread != -1) {
-            CFX_Decimal wsDeci = CFX_Decimal(wsValue.AsStringView());
-            wsDeci.SetScale(iTread);
-            wsRet = wsDeci;
-          }
-          return wsRet;
-        }
-      }
-    } else if (wc == L'.') {
-      iTread_ = 0;
-      iLead = -1;
-    }
-    wsRet += wc;
-  }
-  return wsRet;
-}
diff --git a/xfa/fxfa/cxfa_widgetacc.h b/xfa/fxfa/cxfa_widgetacc.h
deleted file mode 100644
index f21ace9..0000000
--- a/xfa/fxfa/cxfa_widgetacc.h
+++ /dev/null
@@ -1,229 +0,0 @@
-// Copyright 2014 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_CXFA_WIDGETACC_H_
-#define XFA_FXFA_CXFA_WIDGETACC_H_
-
-#include <memory>
-#include <utility>
-#include <vector>
-
-#include "core/fxcrt/fx_coordinates.h"
-#include "core/fxcrt/fx_string.h"
-#include "core/fxcrt/fx_system.h"
-#include "core/fxcrt/retain_ptr.h"
-#include "core/fxge/dib/cfx_dibitmap.h"
-#include "core/fxge/fx_dib.h"
-#include "xfa/fxfa/fxfa_basic.h"
-
-enum XFA_CHECKSTATE {
-  XFA_CHECKSTATE_On = 0,
-  XFA_CHECKSTATE_Off = 1,
-  XFA_CHECKSTATE_Neutral = 2,
-};
-
-enum XFA_VALUEPICTURE {
-  XFA_VALUEPICTURE_Raw = 0,
-  XFA_VALUEPICTURE_Display,
-  XFA_VALUEPICTURE_Edit,
-  XFA_VALUEPICTURE_DataBind,
-};
-
-class CFGAS_GEFont;
-class CXFA_Bind;
-class CXFA_Border;
-class CXFA_Calculate;
-class CXFA_Caption;
-class CXFA_Event;
-class CXFA_EventParam;
-class CXFA_FFApp;
-class CXFA_FFDoc;
-class CXFA_FFDocView;
-class CXFA_FFWidget;
-class CXFA_Font;
-class CXFA_Margin;
-class CXFA_Node;
-class CXFA_Script;
-class CXFA_Para;
-class CXFA_TextLayout;
-class CXFA_Value;
-class CXFA_Validate;
-class CXFA_WidgetLayoutData;
-class IFX_Locale;
-
-class CXFA_WidgetAcc {
- public:
-  explicit CXFA_WidgetAcc(CXFA_Node* pNode);
-  ~CXFA_WidgetAcc();
-
-  void ResetData();
-
-  CXFA_FFWidget* GetNextWidget(CXFA_FFWidget* pWidget);
-  void StartWidgetLayout(CXFA_FFDoc* doc,
-                         float& fCalcWidth,
-                         float& fCalcHeight);
-  bool FindSplitPos(CXFA_FFDocView* docView,
-                    int32_t iBlockIndex,
-                    float& fCalcHeight);
-
-  bool LoadCaption(CXFA_FFDoc* doc);
-  CXFA_TextLayout* GetCaptionTextLayout();
-
-  void LoadText(CXFA_FFDoc* doc);
-  CXFA_TextLayout* GetTextLayout();
-
-  bool LoadImageImage(CXFA_FFDoc* doc);
-  bool LoadImageEditImage(CXFA_FFDoc* doc);
-  void GetImageDpi(int32_t& iImageXDpi, int32_t& iImageYDpi);
-  void GetImageEditDpi(int32_t& iImageXDpi, int32_t& iImageYDpi);
-
-  RetainPtr<CFX_DIBitmap> GetImageImage();
-  RetainPtr<CFX_DIBitmap> GetImageEditImage();
-  void SetImageEdit(const WideString& wsContentType,
-                    const WideString& wsHref,
-                    const WideString& wsData);
-  void SetImageImage(const RetainPtr<CFX_DIBitmap>& newImage);
-  void SetImageEditImage(const RetainPtr<CFX_DIBitmap>& newImage);
-  void UpdateUIDisplay(CXFA_FFDocView* docView, CXFA_FFWidget* pExcept);
-
-  RetainPtr<CFGAS_GEFont> GetFDEFont(CXFA_FFDoc* doc);
-
-  CXFA_Node* GetNode() const { return m_pNode; }
-
-  CXFA_Node* GetUIChild();
-  XFA_Element GetUIType();
-  CFX_RectF GetUIMargin();
-
-  bool IsOpenAccess() const;
-  bool IsListBox();
-  bool IsAllowNeutral();
-  bool IsRadioButton();
-  bool IsChoiceListAllowTextEntry();
-  bool IsMultiLine();
-
-  CXFA_Border* GetUIBorder();
-
-  std::vector<CXFA_Event*> GetEventByActivity(XFA_AttributeEnum iActivity,
-                                              bool bIsFormReady);
-
-  XFA_AttributeEnum GetButtonHighlight();
-  bool HasButtonRollover() const;
-  bool HasButtonDown() const;
-
-  bool IsCheckButtonRound();
-  XFA_AttributeEnum GetCheckButtonMark();
-  float GetCheckButtonSize();
-
-  XFA_CHECKSTATE GetCheckState();
-  void SetCheckState(XFA_CHECKSTATE eCheckState, bool bNotify);
-
-  CXFA_Node* GetSelectedMember();
-  CXFA_Node* SetSelectedMember(const WideStringView& wsName, bool bNotify);
-  void SetSelectedMemberByValue(const WideStringView& wsValue,
-                                bool bNotify,
-                                bool bScriptModify,
-                                bool bSyncData);
-
-  CXFA_Node* GetExclGroupFirstMember();
-  CXFA_Node* GetExclGroupNextMember(CXFA_Node* pNode);
-
-  int32_t CountChoiceListItems(bool bSaveValue);
-  Optional<WideString> GetChoiceListItem(int32_t nIndex, bool bSaveValue);
-  bool IsChoiceListMultiSelect();
-  bool IsChoiceListCommitOnSelect();
-  std::vector<WideString> GetChoiceListItems(bool bSaveValue);
-
-  int32_t CountSelectedItems();
-  int32_t GetSelectedItem(int32_t nIndex);
-  std::vector<int32_t> GetSelectedItems();
-  std::vector<WideString> GetSelectedItemsValue();
-  void SetSelectedItems(const std::vector<int32_t>& iSelArray,
-                        bool bNotify,
-                        bool bScriptModify,
-                        bool bSyncData);
-  void InsertItem(const WideString& wsLabel,
-                  const WideString& wsValue,
-                  bool bNotify);
-  bool DeleteItem(int32_t nIndex, bool bNotify, bool bScriptModify);
-  void ClearAllSelections();
-
-  bool GetItemState(int32_t nIndex);
-  void SetItemState(int32_t nIndex,
-                    bool bSelected,
-                    bool bNotify,
-                    bool bScriptModify,
-                    bool bSyncData);
-
-  WideString GetItemValue(const WideStringView& wsLabel);
-
-  bool IsHorizontalScrollPolicyOff();
-  bool IsVerticalScrollPolicyOff();
-  Optional<int32_t> GetNumberOfCells();
-
-  bool SetValue(XFA_VALUEPICTURE eValueType, const WideString& wsValue);
-  WideString GetValue(XFA_VALUEPICTURE eValueType);
-
-  WideString GetPictureContent(XFA_VALUEPICTURE ePicture);
-  IFX_Locale* GetLocale();
-
-  WideString GetNormalizeDataValue(const WideString& wsValue);
-  WideString GetFormatDataValue(const WideString& wsValue);
-  WideString NormalizeNumStr(const WideString& wsValue);
-
-  WideString GetPasswordChar();
-  std::pair<XFA_Element, int32_t> GetMaxChars();
-  int32_t GetFracDigits();
-  int32_t GetLeadDigits();
-
-  WideString NumericLimit(const WideString& wsValue,
-                          int32_t iLead,
-                          int32_t iTread) const;
-
-  bool IsPreNull() const { return m_bPreNull; }
-  void SetPreNull(bool val) { m_bPreNull = val; }
-  bool IsNull() const { return m_bIsNull; }
-  void SetIsNull(bool val) { m_bIsNull = val; }
-
- private:
-  void CalcCaptionSize(CXFA_FFDoc* doc, CFX_SizeF& szCap);
-  bool CalculateFieldAutoSize(CXFA_FFDoc* doc, CFX_SizeF& size);
-  bool CalculateWidgetAutoSize(CFX_SizeF& size);
-  bool CalculateTextEditAutoSize(CXFA_FFDoc* doc, CFX_SizeF& size);
-  bool CalculateCheckButtonAutoSize(CXFA_FFDoc* doc, CFX_SizeF& size);
-  bool CalculatePushButtonAutoSize(CXFA_FFDoc* doc, CFX_SizeF& size);
-  CFX_SizeF CalculateImageSize(float img_width,
-                               float img_height,
-                               float dpi_x,
-                               float dpi_y);
-  bool CalculateImageEditAutoSize(CXFA_FFDoc* doc, CFX_SizeF& size);
-  bool CalculateImageAutoSize(CXFA_FFDoc* doc, CFX_SizeF& size);
-  float CalculateWidgetAutoHeight(float fHeightCalc);
-  float CalculateWidgetAutoWidth(float fWidthCalc);
-  float GetWidthWithoutMargin(float fWidthCalc);
-  float GetHeightWithoutMargin(float fHeightCalc);
-  void CalculateTextContentSize(CXFA_FFDoc* doc, CFX_SizeF& size);
-  void CalculateAccWidthAndHeight(CXFA_FFDoc* doc,
-                                  XFA_Element eUIType,
-                                  float& fWidth,
-                                  float& fCalcHeight);
-  void InitLayoutData();
-  void StartTextLayout(CXFA_FFDoc* doc, float& fCalcWidth, float& fCalcHeight);
-
-  void InsertListTextItem(CXFA_Node* pItems,
-                          const WideString& wsText,
-                          int32_t nIndex);
-  WideString FormatNumStr(const WideString& wsValue, IFX_Locale* pLocale);
-  void GetItemLabel(const WideStringView& wsValue, WideString& wsLabel);
-
-  std::unique_ptr<CXFA_WidgetLayoutData> m_pLayoutData;
-  bool m_bIsNull;
-  bool m_bPreNull;
-  CXFA_Node* m_pUiChildNode;
-  XFA_Element m_eUIType;
-  CXFA_Node* m_pNode;
-};
-
-#endif  // XFA_FXFA_CXFA_WIDGETACC_H_
diff --git a/xfa/fxfa/cxfa_widgetacciterator.cpp b/xfa/fxfa/cxfa_widgetacciterator.cpp
deleted file mode 100644
index ece5604..0000000
--- a/xfa/fxfa/cxfa_widgetacciterator.cpp
+++ /dev/null
@@ -1,31 +0,0 @@
-// 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
-
-#include "xfa/fxfa/cxfa_widgetacciterator.h"
-
-#include "xfa/fxfa/cxfa_widgetacc.h"
-
-CXFA_WidgetAccIterator::CXFA_WidgetAccIterator(CXFA_Node* pTravelRoot)
-    : m_ContentIterator(pTravelRoot), m_pCurWidgetAcc(nullptr) {}
-
-CXFA_WidgetAccIterator::~CXFA_WidgetAccIterator() {}
-
-CXFA_WidgetAcc* CXFA_WidgetAccIterator::MoveToNext() {
-  CXFA_Node* pItem = m_pCurWidgetAcc ? m_ContentIterator.MoveToNext()
-                                     : m_ContentIterator.GetCurrent();
-  while (pItem) {
-    m_pCurWidgetAcc = pItem->GetWidgetAcc();
-    if (m_pCurWidgetAcc)
-      return m_pCurWidgetAcc.Get();
-    pItem = m_ContentIterator.MoveToNext();
-  }
-  return nullptr;
-}
-
-void CXFA_WidgetAccIterator::SkipTree() {
-  m_ContentIterator.SkipChildrenAndMoveToNext();
-  m_pCurWidgetAcc = nullptr;
-}
diff --git a/xfa/fxfa/cxfa_widgetacciterator.h b/xfa/fxfa/cxfa_widgetacciterator.h
deleted file mode 100644
index 79860a4..0000000
--- a/xfa/fxfa/cxfa_widgetacciterator.h
+++ /dev/null
@@ -1,29 +0,0 @@
-// 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_CXFA_WIDGETACCITERATOR_H_
-#define XFA_FXFA_CXFA_WIDGETACCITERATOR_H_
-
-#include "core/fxcrt/unowned_ptr.h"
-#include "xfa/fxfa/parser/cxfa_traversestrategy_xfacontainernode.h"
-
-class CXFA_Node;
-class CXFA_WidgetAcc;
-
-class CXFA_WidgetAccIterator {
- public:
-  explicit CXFA_WidgetAccIterator(CXFA_Node* pTravelRoot);
-  ~CXFA_WidgetAccIterator();
-
-  CXFA_WidgetAcc* MoveToNext();
-  void SkipTree();
-
- private:
-  CXFA_ContainerIterator m_ContentIterator;
-  UnownedPtr<CXFA_WidgetAcc> m_pCurWidgetAcc;
-};
-
-#endif  // XFA_FXFA_CXFA_WIDGETACCITERATOR_H_
diff --git a/xfa/fxfa/fm2js/BUILD.gn b/xfa/fxfa/fm2js/BUILD.gn
new file mode 100644
index 0000000..a6b2540
--- /dev/null
+++ b/xfa/fxfa/fm2js/BUILD.gn
@@ -0,0 +1,40 @@
+# Copyright 2018 The 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.
+
+import("../../../pdfium.gni")
+import("../../../testing/test.gni")
+
+assert(pdf_enable_xfa)
+
+source_set("fm2js") {
+  sources = [
+    "cxfa_fmexpression.cpp",
+    "cxfa_fmexpression.h",
+    "cxfa_fmlexer.cpp",
+    "cxfa_fmlexer.h",
+    "cxfa_fmparser.cpp",
+    "cxfa_fmparser.h",
+    "cxfa_fmsimpleexpression.cpp",
+    "cxfa_fmsimpleexpression.h",
+    "cxfa_fmtojavascriptdepth.cpp",
+    "cxfa_fmtojavascriptdepth.h",
+  ]
+  deps = [ "../../../core/fxcrt" ]
+  configs += [
+    "../../../:pdfium_core_config",
+    "../../:xfa_warnings",
+  ]
+  visibility = [ "../../../*" ]
+}
+
+pdfium_unittest_source_set("unittests") {
+  sources = [
+    "cxfa_fmexpression_unittest.cpp",
+    "cxfa_fmlexer_unittest.cpp",
+    "cxfa_fmparser_unittest.cpp",
+    "cxfa_fmsimpleexpression_unittest.cpp",
+  ]
+  deps = [ ":fm2js" ]
+  pdfium_root_dir = "../../../"
+}
diff --git a/xfa/fxfa/fm2js/DEPS b/xfa/fxfa/fm2js/DEPS
index 2be0352..e19a721 100644
--- a/xfa/fxfa/fm2js/DEPS
+++ b/xfa/fxfa/fm2js/DEPS
@@ -1,3 +1,6 @@
 include_rules = [
   '+third_party/icu',
+
+  # xfa/fwl should be standalone. https://crbug.com/pdfium/507
+  '-xfa/fwl',
 ]
diff --git a/xfa/fxfa/fm2js/cxfa_fmexpression.cpp b/xfa/fxfa/fm2js/cxfa_fmexpression.cpp
index 759a875..a87ecca 100644
--- a/xfa/fxfa/fm2js/cxfa_fmexpression.cpp
+++ b/xfa/fxfa/fm2js/cxfa_fmexpression.cpp
@@ -14,515 +14,342 @@
 
 namespace {
 
-const wchar_t RUNTIMEBLOCKTEMPARRAY[] = L"pfm_ary";
-
-const wchar_t RUNTIMEBLOCKTEMPARRAYINDEX[] = L"pfm_ary_idx";
-
 const wchar_t kLessEqual[] = L" <= ";
 const wchar_t kGreaterEqual[] = L" >= ";
 const wchar_t kPlusEqual[] = L" += ";
 const wchar_t kMinusEqual[] = L" -= ";
 
+WideString IdentifierToName(WideStringView ident) {
+  if (ident.IsEmpty())
+    return WideString();
+  if (ident[0] != L'!')
+    return WideString(ident);
+  return L"pfm__excl__" + ident.Last(ident.GetLength() - 1);
+}
+
 }  // namespace
 
-CXFA_FMExpression::CXFA_FMExpression(uint32_t line)
-    : m_type(XFA_FM_EXPTYPE_UNKNOWN), m_line(line) {}
-
-CXFA_FMExpression::CXFA_FMExpression(uint32_t line, XFA_FM_EXPTYPE type)
-    : m_type(type), m_line(line) {}
-
-bool CXFA_FMExpression::ToJavaScript(CFX_WideTextBuf& javascript) {
-  CXFA_FMToJavaScriptDepth depthManager;
-  return !CXFA_IsTooBig(javascript) && depthManager.IsWithinMaxDepth();
-}
-
-bool CXFA_FMExpression::ToImpliedReturnJS(CFX_WideTextBuf& javascript) {
-  CXFA_FMToJavaScriptDepth depthManager;
-  return !CXFA_IsTooBig(javascript) && depthManager.IsWithinMaxDepth();
-}
+CXFA_FMExpression::CXFA_FMExpression() = default;
 
 CXFA_FMFunctionDefinition::CXFA_FMFunctionDefinition(
-    uint32_t line,
-    bool isGlobal,
-    const WideStringView& wsName,
+    WideStringView wsName,
     std::vector<WideStringView>&& arguments,
     std::vector<std::unique_ptr<CXFA_FMExpression>>&& expressions)
-    : CXFA_FMExpression(line, XFA_FM_EXPTYPE_FUNC),
+    : CXFA_FMExpression(),
       m_wsName(wsName),
       m_pArguments(std::move(arguments)),
-      m_pExpressions(std::move(expressions)),
-      m_isGlobal(isGlobal) {}
-
-CXFA_FMFunctionDefinition::~CXFA_FMFunctionDefinition() {}
-
-bool CXFA_FMFunctionDefinition::ToJavaScript(CFX_WideTextBuf& javascript) {
-  CXFA_FMToJavaScriptDepth depthManager;
-  if (CXFA_IsTooBig(javascript) || !depthManager.IsWithinMaxDepth())
-    return false;
-
-  if (m_isGlobal && m_pExpressions.empty()) {
-    javascript << L"// comments only";
-    return !CXFA_IsTooBig(javascript);
-  }
-  if (m_isGlobal) {
-    javascript << L"(\n";
-  }
-  javascript << L"function ";
-  if (!m_wsName.IsEmpty() && m_wsName[0] == L'!') {
-    WideString tempName =
-        EXCLAMATION_IN_IDENTIFIER + m_wsName.Right(m_wsName.GetLength() - 1);
-    javascript << tempName;
-  } else {
-    javascript << m_wsName;
-  }
-  javascript << L"(";
-  bool bNeedComma = false;
-  for (const auto& identifier : m_pArguments) {
-    if (bNeedComma)
-      javascript << L", ";
-    if (identifier[0] == L'!') {
-      WideString tempIdentifier = EXCLAMATION_IN_IDENTIFIER +
-                                  identifier.Right(identifier.GetLength() - 1);
-      javascript << tempIdentifier;
-    } else {
-      javascript << identifier;
-    }
-    bNeedComma = true;
-  }
-  javascript << L")\n{\n";
-  javascript << L"var ";
-  javascript << RUNTIMEFUNCTIONRETURNVALUE;
-  javascript << L" = null;\n";
-  for (const auto& expr : m_pExpressions) {
-    bool ret;
-    if (expr == m_pExpressions.back())
-      ret = expr->ToImpliedReturnJS(javascript);
-    else
-      ret = expr->ToJavaScript(javascript);
-
-    if (!ret)
-      return false;
-  }
-  javascript << L"return ";
-  if (m_isGlobal) {
-    javascript << XFA_FM_EXPTypeToString(GETFMVALUE);
-    javascript << L"(";
-    javascript << RUNTIMEFUNCTIONRETURNVALUE;
-    javascript << L")";
-  } else {
-    javascript << RUNTIMEFUNCTIONRETURNVALUE;
-  }
-  javascript << L";\n}\n";
-  if (m_isGlobal) {
-    javascript << L").call(this);\n";
-  }
-  return !CXFA_IsTooBig(javascript);
+      m_pExpressions(std::move(expressions)) {
+  ASSERT(!wsName.IsEmpty());
 }
 
-bool CXFA_FMFunctionDefinition::ToImpliedReturnJS(CFX_WideTextBuf& javascript) {
+CXFA_FMFunctionDefinition::~CXFA_FMFunctionDefinition() = default;
+
+bool CXFA_FMFunctionDefinition::ToJavaScript(CFX_WideTextBuf* js,
+                                             ReturnType type) {
   CXFA_FMToJavaScriptDepth depthManager;
-  return !CXFA_IsTooBig(javascript) && depthManager.IsWithinMaxDepth();
+  if (CXFA_IsTooBig(js) || !depthManager.IsWithinMaxDepth())
+    return false;
+
+  if (m_wsName.IsEmpty())
+    return false;
+
+  *js << "function " << IdentifierToName(m_wsName) << "(";
+  for (const auto& identifier : m_pArguments) {
+    if (identifier != m_pArguments.front())
+      *js << ", ";
+
+    *js << IdentifierToName(identifier);
+  }
+  *js << ") {\n";
+
+  *js << "var pfm_ret = null;\n";
+  for (const auto& expr : m_pExpressions) {
+    ReturnType ret_type = expr == m_pExpressions.back() ? ReturnType::kImplied
+                                                        : ReturnType::kInfered;
+    if (!expr->ToJavaScript(js, ret_type))
+      return false;
+  }
+
+  *js << "return pfm_ret;\n";
+  *js << "}\n";
+
+  return !CXFA_IsTooBig(js);
+}
+
+CXFA_FMAST::CXFA_FMAST(
+    std::vector<std::unique_ptr<CXFA_FMExpression>> expressions)
+    : expressions_(std::move(expressions)) {}
+
+CXFA_FMAST::~CXFA_FMAST() = default;
+
+bool CXFA_FMAST::ToJavaScript(CFX_WideTextBuf* js) {
+  if (expressions_.empty()) {
+    *js << "// comments only";
+    return !CXFA_IsTooBig(js);
+  }
+
+  *js << "(function() {\n";
+  *js << "let pfm_method_runner = function(obj, cb) {\n";
+  *js << "  if (pfm_rt.is_ary(obj)) {\n";
+  *js << "    let pfm_method_return = null;\n";
+  *js << "    for (var idx = obj.length -1; idx > 1; idx--) {\n";
+  *js << "      pfm_method_return = cb(obj[idx]);\n";
+  *js << "    }\n";
+  *js << "    return pfm_method_return;\n";
+  *js << "  }\n";
+  *js << "  return cb(obj);\n";
+  *js << "};\n";
+  *js << "var pfm_ret = null;\n";
+
+  for (const auto& expr : expressions_) {
+    ReturnType ret_type = expr == expressions_.back() ? ReturnType::kImplied
+                                                      : ReturnType::kInfered;
+    if (!expr->ToJavaScript(js, ret_type))
+      return false;
+  }
+
+  *js << "return pfm_rt.get_val(pfm_ret);\n";
+  *js << "}).call(this);";
+  return !CXFA_IsTooBig(js);
 }
 
 CXFA_FMVarExpression::CXFA_FMVarExpression(
-    uint32_t line,
-    const WideStringView& wsName,
-    std::unique_ptr<CXFA_FMExpression> pInit)
-    : CXFA_FMExpression(line, XFA_FM_EXPTYPE_VAR),
-      m_wsName(wsName),
-      m_pInit(std::move(pInit)) {}
+    WideStringView wsName,
+    std::unique_ptr<CXFA_FMSimpleExpression> pInit)
+    : CXFA_FMExpression(), m_wsName(wsName), m_pInit(std::move(pInit)) {}
 
-CXFA_FMVarExpression::~CXFA_FMVarExpression() {}
+CXFA_FMVarExpression::~CXFA_FMVarExpression() = default;
 
-bool CXFA_FMVarExpression::ToJavaScript(CFX_WideTextBuf& javascript) {
+bool CXFA_FMVarExpression::ToJavaScript(CFX_WideTextBuf* js, ReturnType type) {
   CXFA_FMToJavaScriptDepth depthManager;
-  if (CXFA_IsTooBig(javascript) || !depthManager.IsWithinMaxDepth())
+  if (CXFA_IsTooBig(js) || !depthManager.IsWithinMaxDepth())
     return false;
 
-  javascript << L"var ";
-  WideString tempName(m_wsName);
-  if (m_wsName[0] == L'!') {
-    tempName =
-        EXCLAMATION_IN_IDENTIFIER + m_wsName.Right(m_wsName.GetLength() - 1);
-  }
-  javascript << tempName;
-  javascript << L" = ";
+  WideString tempName = IdentifierToName(m_wsName);
+  *js << "var " << tempName << " = ";
   if (m_pInit) {
-    if (!m_pInit->ToJavaScript(javascript))
+    if (!m_pInit->ToJavaScript(js, ReturnType::kInfered))
       return false;
-    javascript << tempName;
-    javascript << L" = ";
-    javascript << XFA_FM_EXPTypeToString(VARFILTER);
-    javascript << L"(";
-    javascript << tempName;
-    javascript << L");\n";
-  } else {
-    javascript << L"\"\";\n";
-  }
-  return !CXFA_IsTooBig(javascript);
-}
 
-bool CXFA_FMVarExpression::ToImpliedReturnJS(CFX_WideTextBuf& javascript) {
-  CXFA_FMToJavaScriptDepth depthManager;
-  if (CXFA_IsTooBig(javascript) || !depthManager.IsWithinMaxDepth())
-    return false;
-
-  javascript << L"var ";
-  WideString tempName(m_wsName);
-  if (m_wsName[0] == L'!') {
-    tempName =
-        EXCLAMATION_IN_IDENTIFIER + m_wsName.Right(m_wsName.GetLength() - 1);
-  }
-  javascript << tempName;
-  javascript << L" = ";
-  if (m_pInit) {
-    if (!m_pInit->ToJavaScript(javascript))
-      return false;
-    javascript << tempName;
-    javascript << L" = ";
-    javascript << XFA_FM_EXPTypeToString(VARFILTER);
-    javascript << L"(";
-    javascript << tempName;
-    javascript << L");\n";
+    *js << ";\n";
+    *js << tempName << " = pfm_rt.var_filter(" << tempName << ");\n";
   } else {
-    javascript << L"\"\";\n";
+    *js << "\"\";\n";
   }
-  javascript << RUNTIMEFUNCTIONRETURNVALUE;
-  javascript << L" = ";
-  javascript << tempName;
-  javascript << L";\n";
-  return !CXFA_IsTooBig(javascript);
+
+  if (type == ReturnType::kImplied)
+    *js << "pfm_ret = " << tempName << ";\n";
+
+  return !CXFA_IsTooBig(js);
 }
 
 CXFA_FMExpExpression::CXFA_FMExpExpression(
-    uint32_t line,
     std::unique_ptr<CXFA_FMSimpleExpression> pExpression)
-    : CXFA_FMExpression(line, XFA_FM_EXPTYPE_EXP),
-      m_pExpression(std::move(pExpression)) {}
+    : CXFA_FMExpression(), m_pExpression(std::move(pExpression)) {}
 
-CXFA_FMExpExpression::~CXFA_FMExpExpression() {}
+CXFA_FMExpExpression::~CXFA_FMExpExpression() = default;
 
-bool CXFA_FMExpExpression::ToJavaScript(CFX_WideTextBuf& javascript) {
+bool CXFA_FMExpExpression::ToJavaScript(CFX_WideTextBuf* js, ReturnType type) {
   CXFA_FMToJavaScriptDepth depthManager;
-  if (CXFA_IsTooBig(javascript) || !depthManager.IsWithinMaxDepth())
+  if (CXFA_IsTooBig(js) || !depthManager.IsWithinMaxDepth())
     return false;
 
-  bool ret = m_pExpression->ToJavaScript(javascript);
-  if (m_pExpression->GetOperatorToken() != TOKassign)
-    javascript << L";\n";
-  return ret;
-}
+  if (type == ReturnType::kInfered) {
+    bool ret = m_pExpression->ToJavaScript(js, ReturnType::kInfered);
+    if (m_pExpression->GetOperatorToken() != TOKassign)
+      *js << ";\n";
 
-bool CXFA_FMExpExpression::ToImpliedReturnJS(CFX_WideTextBuf& javascript) {
-  CXFA_FMToJavaScriptDepth depthManager;
-  if (CXFA_IsTooBig(javascript) || !depthManager.IsWithinMaxDepth())
-    return false;
+    return ret;
+  }
 
   if (m_pExpression->GetOperatorToken() == TOKassign)
-    return m_pExpression->ToImpliedReturnJS(javascript);
+    return m_pExpression->ToJavaScript(js, ReturnType::kImplied);
 
   if (m_pExpression->GetOperatorToken() == TOKstar ||
       m_pExpression->GetOperatorToken() == TOKdotstar ||
       m_pExpression->GetOperatorToken() == TOKdotscream ||
       m_pExpression->GetOperatorToken() == TOKdotdot ||
       m_pExpression->GetOperatorToken() == TOKdot) {
-    javascript << RUNTIMEFUNCTIONRETURNVALUE;
-    javascript << L" = ";
-    javascript << XFA_FM_EXPTypeToString(GETFMVALUE);
-    javascript << L"(";
-    if (!m_pExpression->ToJavaScript(javascript))
+    *js << "pfm_ret = pfm_rt.get_val(";
+    if (!m_pExpression->ToJavaScript(js, ReturnType::kInfered))
       return false;
-    javascript << L");\n";
-    return !CXFA_IsTooBig(javascript);
+
+    *js << ");\n";
+    return !CXFA_IsTooBig(js);
   }
 
-  javascript << RUNTIMEFUNCTIONRETURNVALUE;
-  javascript << L" = ";
-  if (!m_pExpression->ToJavaScript(javascript))
+  *js << "pfm_ret = ";
+  if (!m_pExpression->ToJavaScript(js, ReturnType::kInfered))
     return false;
-  javascript << L";\n";
-  return !CXFA_IsTooBig(javascript);
+
+  *js << ";\n";
+  return !CXFA_IsTooBig(js);
 }
 
 CXFA_FMBlockExpression::CXFA_FMBlockExpression(
-    uint32_t line,
     std::vector<std::unique_ptr<CXFA_FMExpression>>&& pExpressionList)
-    : CXFA_FMExpression(line, XFA_FM_EXPTYPE_BLOCK),
-      m_ExpressionList(std::move(pExpressionList)) {}
+    : CXFA_FMExpression(), m_ExpressionList(std::move(pExpressionList)) {}
 
-CXFA_FMBlockExpression::~CXFA_FMBlockExpression() {}
+CXFA_FMBlockExpression::~CXFA_FMBlockExpression() = default;
 
-bool CXFA_FMBlockExpression::ToJavaScript(CFX_WideTextBuf& javascript) {
+bool CXFA_FMBlockExpression::ToJavaScript(CFX_WideTextBuf* js,
+                                          ReturnType type) {
   CXFA_FMToJavaScriptDepth depthManager;
-  if (CXFA_IsTooBig(javascript) || !depthManager.IsWithinMaxDepth())
+  if (CXFA_IsTooBig(js) || !depthManager.IsWithinMaxDepth())
     return false;
 
-  javascript << L"{\n";
+  *js << "{\n";
   for (const auto& expr : m_ExpressionList) {
-    if (!expr->ToJavaScript(javascript))
-      return false;
+    if (type == ReturnType::kInfered) {
+      if (!expr->ToJavaScript(js, ReturnType::kInfered))
+        return false;
+    } else {
+      ReturnType ret_type = expr == m_ExpressionList.back()
+                                ? ReturnType::kImplied
+                                : ReturnType::kInfered;
+      if (!expr->ToJavaScript(js, ret_type))
+        return false;
+    }
   }
-  javascript << L"}\n";
-  return !CXFA_IsTooBig(javascript);
-}
+  *js << "}\n";
 
-bool CXFA_FMBlockExpression::ToImpliedReturnJS(CFX_WideTextBuf& javascript) {
-  CXFA_FMToJavaScriptDepth depthManager;
-  if (CXFA_IsTooBig(javascript) || !depthManager.IsWithinMaxDepth())
-    return false;
-
-  javascript << L"{\n";
-  for (const auto& expr : m_ExpressionList) {
-    bool ret;
-    if (expr == m_ExpressionList.back())
-      ret = expr->ToImpliedReturnJS(javascript);
-    else
-      ret = expr->ToJavaScript(javascript);
-
-    if (!ret)
-      return false;
-  }
-  javascript << L"}\n";
-  return !CXFA_IsTooBig(javascript);
+  return !CXFA_IsTooBig(js);
 }
 
 CXFA_FMDoExpression::CXFA_FMDoExpression(
-    uint32_t line,
     std::unique_ptr<CXFA_FMExpression> pList)
-    : CXFA_FMExpression(line), m_pList(std::move(pList)) {}
+    : CXFA_FMExpression(), m_pList(std::move(pList)) {}
 
-CXFA_FMDoExpression::~CXFA_FMDoExpression() {}
+CXFA_FMDoExpression::~CXFA_FMDoExpression() = default;
 
-bool CXFA_FMDoExpression::ToJavaScript(CFX_WideTextBuf& javascript) {
+bool CXFA_FMDoExpression::ToJavaScript(CFX_WideTextBuf* js, ReturnType type) {
   CXFA_FMToJavaScriptDepth depthManager;
-  if (CXFA_IsTooBig(javascript) || !depthManager.IsWithinMaxDepth())
+  if (CXFA_IsTooBig(js) || !depthManager.IsWithinMaxDepth())
     return false;
 
-  return m_pList->ToJavaScript(javascript);
-}
-
-bool CXFA_FMDoExpression::ToImpliedReturnJS(CFX_WideTextBuf& javascript) {
-  CXFA_FMToJavaScriptDepth depthManager;
-  if (CXFA_IsTooBig(javascript) || !depthManager.IsWithinMaxDepth())
-    return false;
-
-  return m_pList->ToImpliedReturnJS(javascript);
+  return m_pList->ToJavaScript(js, type);
 }
 
 CXFA_FMIfExpression::CXFA_FMIfExpression(
-    uint32_t line,
     std::unique_ptr<CXFA_FMSimpleExpression> pExpression,
     std::unique_ptr<CXFA_FMExpression> pIfExpression,
+    std::vector<std::unique_ptr<CXFA_FMIfExpression>> pElseIfExpressions,
     std::unique_ptr<CXFA_FMExpression> pElseExpression)
-    : CXFA_FMExpression(line, XFA_FM_EXPTYPE_IF),
+    : CXFA_FMExpression(),
       m_pExpression(std::move(pExpression)),
       m_pIfExpression(std::move(pIfExpression)),
-      m_pElseExpression(std::move(pElseExpression)) {}
+      m_pElseIfExpressions(std::move(pElseIfExpressions)),
+      m_pElseExpression(std::move(pElseExpression)) {
+  ASSERT(m_pExpression);
+}
 
-CXFA_FMIfExpression::~CXFA_FMIfExpression() {}
+CXFA_FMIfExpression::~CXFA_FMIfExpression() = default;
 
-bool CXFA_FMIfExpression::ToJavaScript(CFX_WideTextBuf& javascript) {
+bool CXFA_FMIfExpression::ToJavaScript(CFX_WideTextBuf* js, ReturnType type) {
   CXFA_FMToJavaScriptDepth depthManager;
-  if (CXFA_IsTooBig(javascript) || !depthManager.IsWithinMaxDepth())
+  if (CXFA_IsTooBig(js) || !depthManager.IsWithinMaxDepth())
     return false;
 
-  javascript << L"if (";
-  if (m_pExpression) {
-    javascript << XFA_FM_EXPTypeToString(GETFMVALUE);
-    javascript << L"(";
-    if (!m_pExpression->ToJavaScript(javascript))
-      return false;
-    javascript << L")";
-  }
-  javascript << L")\n";
-  if (CXFA_IsTooBig(javascript))
+  if (type == ReturnType::kImplied)
+    *js << "pfm_ret = 0;\n";
+
+  *js << "if (pfm_rt.get_val(";
+  if (!m_pExpression->ToJavaScript(js, ReturnType::kInfered))
+    return false;
+  *js << "))\n";
+
+  if (CXFA_IsTooBig(js))
     return false;
 
   if (m_pIfExpression) {
-    if (!m_pIfExpression->ToJavaScript(javascript))
+    if (!m_pIfExpression->ToJavaScript(js, type))
       return false;
-    if (CXFA_IsTooBig(javascript))
+    if (CXFA_IsTooBig(js))
+      return false;
+  }
+
+  for (auto& expr : m_pElseIfExpressions) {
+    *js << "else ";
+    if (!expr->ToJavaScript(js, ReturnType::kInfered))
       return false;
   }
 
   if (m_pElseExpression) {
-    if (m_pElseExpression->GetExpType() == XFA_FM_EXPTYPE_IF) {
-      javascript << L"else\n";
-      javascript << L"{\n";
-      if (!m_pElseExpression->ToJavaScript(javascript))
-        return false;
-      javascript << L"}\n";
-    } else {
-      javascript << L"else\n";
-      if (!m_pElseExpression->ToJavaScript(javascript))
-        return false;
-    }
-  }
-  return !CXFA_IsTooBig(javascript);
-}
-
-bool CXFA_FMIfExpression::ToImpliedReturnJS(CFX_WideTextBuf& javascript) {
-  CXFA_FMToJavaScriptDepth depthManager;
-  if (CXFA_IsTooBig(javascript) || !depthManager.IsWithinMaxDepth())
-    return false;
-
-  javascript << RUNTIMEFUNCTIONRETURNVALUE;
-  javascript << L" = 0;\n";
-  javascript << L"if (";
-  if (m_pExpression) {
-    javascript << XFA_FM_EXPTypeToString(GETFMVALUE);
-    javascript << L"(";
-    if (!m_pExpression->ToJavaScript(javascript))
-      return false;
-    javascript << L")";
-  }
-  javascript << L")\n";
-  if (CXFA_IsTooBig(javascript))
-    return false;
-
-  if (m_pIfExpression) {
-    if (!m_pIfExpression->ToImpliedReturnJS(javascript))
-      return false;
-    if (CXFA_IsTooBig(javascript))
+    *js << "else ";
+    if (!m_pElseExpression->ToJavaScript(js, type))
       return false;
   }
-  if (m_pElseExpression) {
-    if (m_pElseExpression->GetExpType() == XFA_FM_EXPTYPE_IF) {
-      javascript << L"else\n";
-      javascript << L"{\n";
-      if (!m_pElseExpression->ToImpliedReturnJS(javascript))
-        return false;
-      javascript << L"}\n";
-    } else {
-      javascript << L"else\n";
-      if (!m_pElseExpression->ToImpliedReturnJS(javascript))
-        return false;
-    }
-  }
-  return !CXFA_IsTooBig(javascript);
-}
-
-CXFA_FMLoopExpression::~CXFA_FMLoopExpression() {}
-
-bool CXFA_FMLoopExpression::ToJavaScript(CFX_WideTextBuf& javascript) {
-  CXFA_FMToJavaScriptDepth depthManager;
-  return !CXFA_IsTooBig(javascript) && depthManager.IsWithinMaxDepth();
-}
-
-bool CXFA_FMLoopExpression::ToImpliedReturnJS(CFX_WideTextBuf& javascript) {
-  CXFA_FMToJavaScriptDepth depthManager;
-  return !CXFA_IsTooBig(javascript) && depthManager.IsWithinMaxDepth();
+  return !CXFA_IsTooBig(js);
 }
 
 CXFA_FMWhileExpression::CXFA_FMWhileExpression(
-    uint32_t line,
     std::unique_ptr<CXFA_FMSimpleExpression> pCondition,
     std::unique_ptr<CXFA_FMExpression> pExpression)
-    : CXFA_FMLoopExpression(line),
+    : CXFA_FMExpression(),
       m_pCondition(std::move(pCondition)),
       m_pExpression(std::move(pExpression)) {}
 
-CXFA_FMWhileExpression::~CXFA_FMWhileExpression() {}
+CXFA_FMWhileExpression::~CXFA_FMWhileExpression() = default;
 
-bool CXFA_FMWhileExpression::ToJavaScript(CFX_WideTextBuf& javascript) {
+bool CXFA_FMWhileExpression::ToJavaScript(CFX_WideTextBuf* js,
+                                          ReturnType type) {
   CXFA_FMToJavaScriptDepth depthManager;
-  if (CXFA_IsTooBig(javascript) || !depthManager.IsWithinMaxDepth())
+  if (CXFA_IsTooBig(js) || !depthManager.IsWithinMaxDepth())
     return false;
 
-  javascript << L"while (";
-  if (!m_pCondition->ToJavaScript(javascript))
-    return false;
-  javascript << L")\n";
-  if (CXFA_IsTooBig(javascript))
+  if (type == ReturnType::kImplied)
+    *js << "pfm_ret = 0;\n";
+
+  *js << "while (";
+  if (!m_pCondition->ToJavaScript(js, ReturnType::kInfered))
     return false;
 
-  if (!m_pExpression->ToJavaScript(javascript))
+  *js << ")\n";
+  if (CXFA_IsTooBig(js))
     return false;
-  return !CXFA_IsTooBig(javascript);
+
+  if (!m_pExpression->ToJavaScript(js, type))
+    return false;
+
+  return !CXFA_IsTooBig(js);
 }
 
-bool CXFA_FMWhileExpression::ToImpliedReturnJS(CFX_WideTextBuf& javascript) {
+CXFA_FMBreakExpression::CXFA_FMBreakExpression() : CXFA_FMExpression() {}
+
+CXFA_FMBreakExpression::~CXFA_FMBreakExpression() = default;
+
+bool CXFA_FMBreakExpression::ToJavaScript(CFX_WideTextBuf* js,
+                                          ReturnType type) {
   CXFA_FMToJavaScriptDepth depthManager;
-  if (CXFA_IsTooBig(javascript) || !depthManager.IsWithinMaxDepth())
+  if (CXFA_IsTooBig(js) || !depthManager.IsWithinMaxDepth())
     return false;
 
-  javascript << RUNTIMEFUNCTIONRETURNVALUE;
-  javascript << L" = 0;\n";
-  javascript << L"while (";
-  if (!m_pCondition->ToJavaScript(javascript))
-    return false;
-  javascript << L")\n";
-  if (CXFA_IsTooBig(javascript))
-    return false;
-
-  if (!m_pExpression->ToImpliedReturnJS(javascript))
-    return false;
-  return !CXFA_IsTooBig(javascript);
+  *js << "pfm_ret = 0;\nbreak;\n";
+  return !CXFA_IsTooBig(js);
 }
 
-CXFA_FMBreakExpression::CXFA_FMBreakExpression(uint32_t line)
-    : CXFA_FMExpression(line, XFA_FM_EXPTYPE_BREAK) {}
+CXFA_FMContinueExpression::CXFA_FMContinueExpression() : CXFA_FMExpression() {}
 
-CXFA_FMBreakExpression::~CXFA_FMBreakExpression() {}
+CXFA_FMContinueExpression::~CXFA_FMContinueExpression() = default;
 
-bool CXFA_FMBreakExpression::ToJavaScript(CFX_WideTextBuf& javascript) {
+bool CXFA_FMContinueExpression::ToJavaScript(CFX_WideTextBuf* js,
+                                             ReturnType type) {
   CXFA_FMToJavaScriptDepth depthManager;
-  if (CXFA_IsTooBig(javascript) || !depthManager.IsWithinMaxDepth())
+  if (CXFA_IsTooBig(js) || !depthManager.IsWithinMaxDepth())
     return false;
 
-  javascript << RUNTIMEFUNCTIONRETURNVALUE;
-  javascript << L" = 0;\n";
-  javascript << L"break;\n";
-  return !CXFA_IsTooBig(javascript);
-}
-
-bool CXFA_FMBreakExpression::ToImpliedReturnJS(CFX_WideTextBuf& javascript) {
-  CXFA_FMToJavaScriptDepth depthManager;
-  if (CXFA_IsTooBig(javascript) || !depthManager.IsWithinMaxDepth())
-    return false;
-
-  javascript << RUNTIMEFUNCTIONRETURNVALUE;
-  javascript << L" = 0;\n";
-  javascript << L"break;\n";
-  return !CXFA_IsTooBig(javascript);
-}
-
-CXFA_FMContinueExpression::CXFA_FMContinueExpression(uint32_t line)
-    : CXFA_FMExpression(line, XFA_FM_EXPTYPE_CONTINUE) {}
-
-CXFA_FMContinueExpression::~CXFA_FMContinueExpression() {}
-
-bool CXFA_FMContinueExpression::ToJavaScript(CFX_WideTextBuf& javascript) {
-  CXFA_FMToJavaScriptDepth depthManager;
-  if (CXFA_IsTooBig(javascript) || !depthManager.IsWithinMaxDepth())
-    return false;
-
-  javascript << RUNTIMEFUNCTIONRETURNVALUE;
-  javascript << L" = 0;\n";
-  javascript << L"continue;\n";
-  return !CXFA_IsTooBig(javascript);
-}
-
-bool CXFA_FMContinueExpression::ToImpliedReturnJS(CFX_WideTextBuf& javascript) {
-  CXFA_FMToJavaScriptDepth depthManager;
-  if (CXFA_IsTooBig(javascript) || !depthManager.IsWithinMaxDepth())
-    return false;
-
-  javascript << RUNTIMEFUNCTIONRETURNVALUE;
-  javascript << L" = 0;\n";
-  javascript << L"continue;\n";
-  return !CXFA_IsTooBig(javascript);
+  *js << "pfm_ret = 0;\ncontinue;\n";
+  return !CXFA_IsTooBig(js);
 }
 
 CXFA_FMForExpression::CXFA_FMForExpression(
-    uint32_t line,
-    const WideStringView& wsVariant,
+    WideStringView wsVariant,
     std::unique_ptr<CXFA_FMSimpleExpression> pAssignment,
     std::unique_ptr<CXFA_FMSimpleExpression> pAccessor,
     int32_t iDirection,
     std::unique_ptr<CXFA_FMSimpleExpression> pStep,
     std::unique_ptr<CXFA_FMExpression> pList)
-    : CXFA_FMLoopExpression(line),
+    : CXFA_FMExpression(),
       m_wsVariant(wsVariant),
       m_pAssignment(std::move(pAssignment)),
       m_pAccessor(std::move(pAccessor)),
@@ -530,242 +357,92 @@
       m_pStep(std::move(pStep)),
       m_pList(std::move(pList)) {}
 
-CXFA_FMForExpression::~CXFA_FMForExpression() {}
+CXFA_FMForExpression::~CXFA_FMForExpression() = default;
 
-bool CXFA_FMForExpression::ToJavaScript(CFX_WideTextBuf& javascript) {
+bool CXFA_FMForExpression::ToJavaScript(CFX_WideTextBuf* js, ReturnType type) {
   CXFA_FMToJavaScriptDepth depthManager;
-  if (CXFA_IsTooBig(javascript) || !depthManager.IsWithinMaxDepth())
+  if (CXFA_IsTooBig(js) || !depthManager.IsWithinMaxDepth())
     return false;
 
-  javascript << L"{\nvar ";
-  WideString tempVariant;
-  if (m_wsVariant[0] == L'!') {
-    tempVariant = EXCLAMATION_IN_IDENTIFIER +
-                  m_wsVariant.Right(m_wsVariant.GetLength() - 1);
-    javascript << tempVariant;
-  } else {
-    tempVariant = m_wsVariant;
-    javascript << m_wsVariant;
-  }
-  javascript << L" = null;\n";
-  javascript << L"for (";
-  javascript << tempVariant;
-  javascript << L" = ";
-  javascript << XFA_FM_EXPTypeToString(GETFMVALUE);
-  javascript << L"(";
-  if (!m_pAssignment->ToJavaScript(javascript))
-    return false;
-  javascript << L"); ";
-  javascript << tempVariant;
+  if (type == ReturnType::kImplied)
+    *js << "pfm_ret = 0;\n";
 
-  javascript << (m_bDirection ? kLessEqual : kGreaterEqual);
-  javascript << XFA_FM_EXPTypeToString(GETFMVALUE);
-  javascript << L"(";
-  if (!m_pAccessor->ToJavaScript(javascript))
-    return false;
-  javascript << L"); ";
-  javascript << tempVariant;
-  javascript << (m_bDirection ? kPlusEqual : kMinusEqual);
-  if (CXFA_IsTooBig(javascript))
-    return false;
+  *js << "{\n";
 
+  WideString tmpName = IdentifierToName(m_wsVariant);
+  *js << "var " << tmpName << " = null;\n";
+
+  *js << "for (" << tmpName << " = pfm_rt.get_val(";
+  if (!m_pAssignment->ToJavaScript(js, ReturnType::kInfered))
+    return false;
+  *js << "); ";
+
+  *js << tmpName << (m_bDirection ? kLessEqual : kGreaterEqual);
+  *js << "pfm_rt.get_val(";
+  if (!m_pAccessor->ToJavaScript(js, ReturnType::kInfered))
+    return false;
+  *js << "); ";
+
+  *js << tmpName << (m_bDirection ? kPlusEqual : kMinusEqual);
   if (m_pStep) {
-    javascript << XFA_FM_EXPTypeToString(GETFMVALUE);
-    javascript << L"(";
-    if (!m_pStep->ToJavaScript(javascript))
+    *js << "pfm_rt.get_val(";
+    if (!m_pStep->ToJavaScript(js, ReturnType::kInfered))
       return false;
-    javascript << L")";
+    *js << ")";
   } else {
-    javascript << L"1";
+    *js << "1";
   }
-  javascript << L")\n";
-  if (!m_pList->ToJavaScript(javascript))
-    return false;
-  javascript << L"}\n";
-  return !CXFA_IsTooBig(javascript);
-}
-
-bool CXFA_FMForExpression::ToImpliedReturnJS(CFX_WideTextBuf& javascript) {
-  CXFA_FMToJavaScriptDepth depthManager;
-  if (CXFA_IsTooBig(javascript) || !depthManager.IsWithinMaxDepth())
+  *js << ")\n";
+  if (CXFA_IsTooBig(js))
     return false;
 
-  javascript << RUNTIMEFUNCTIONRETURNVALUE;
-  javascript << L" = 0;\n";
-  javascript << L"{\nvar ";
-  WideString tempVariant;
-  if (m_wsVariant[0] == L'!') {
-    tempVariant = EXCLAMATION_IN_IDENTIFIER +
-                  m_wsVariant.Right(m_wsVariant.GetLength() - 1);
-    javascript << tempVariant;
-  } else {
-    tempVariant = m_wsVariant;
-    javascript << m_wsVariant;
-  }
-  javascript << L" = null;\n";
-  javascript << L"for (";
-  javascript << tempVariant;
-  javascript << L" = ";
-  javascript << XFA_FM_EXPTypeToString(GETFMVALUE);
-  javascript << L"(";
-  if (!m_pAssignment->ToJavaScript(javascript))
-    return false;
-  javascript << L"); ";
-  javascript << tempVariant;
-
-  javascript << (m_bDirection ? kLessEqual : kGreaterEqual);
-  javascript << XFA_FM_EXPTypeToString(GETFMVALUE);
-  javascript << L"(";
-  if (!m_pAccessor->ToJavaScript(javascript))
-    return false;
-  javascript << L"); ";
-  javascript << tempVariant;
-  javascript << L" += ";
-  javascript << (m_bDirection ? kPlusEqual : kMinusEqual);
-  if (CXFA_IsTooBig(javascript))
+  if (!m_pList->ToJavaScript(js, type))
     return false;
 
-  if (m_pStep) {
-    javascript << XFA_FM_EXPTypeToString(GETFMVALUE);
-    javascript << L"(";
-    if (!m_pStep->ToJavaScript(javascript))
-      return false;
-    javascript << L")";
-    if (CXFA_IsTooBig(javascript))
-      return false;
-  } else {
-    javascript << L"1";
-  }
-  javascript << L")\n";
-  if (!m_pList->ToImpliedReturnJS(javascript))
-    return false;
-  javascript << L"}\n";
-  return !CXFA_IsTooBig(javascript);
+  *js << "}\n";
+  return !CXFA_IsTooBig(js);
 }
 
 CXFA_FMForeachExpression::CXFA_FMForeachExpression(
-    uint32_t line,
-    const WideStringView& wsIdentifier,
+    WideStringView wsIdentifier,
     std::vector<std::unique_ptr<CXFA_FMSimpleExpression>>&& pAccessors,
     std::unique_ptr<CXFA_FMExpression> pList)
-    : CXFA_FMLoopExpression(line),
+    : CXFA_FMExpression(),
       m_wsIdentifier(wsIdentifier),
       m_pAccessors(std::move(pAccessors)),
       m_pList(std::move(pList)) {}
 
-CXFA_FMForeachExpression::~CXFA_FMForeachExpression() {}
+CXFA_FMForeachExpression::~CXFA_FMForeachExpression() = default;
 
-bool CXFA_FMForeachExpression::ToJavaScript(CFX_WideTextBuf& javascript) {
+bool CXFA_FMForeachExpression::ToJavaScript(CFX_WideTextBuf* js,
+                                            ReturnType type) {
   CXFA_FMToJavaScriptDepth depthManager;
-  if (CXFA_IsTooBig(javascript) || !depthManager.IsWithinMaxDepth())
+  if (CXFA_IsTooBig(js) || !depthManager.IsWithinMaxDepth())
     return false;
 
-  javascript << L"{\n";
-  javascript << L"var ";
-  if (m_wsIdentifier[0] == L'!') {
-    WideString tempIdentifier =
-        EXCLAMATION_IN_IDENTIFIER +
-        m_wsIdentifier.Right(m_wsIdentifier.GetLength() - 1);
-    javascript << tempIdentifier;
-  } else {
-    javascript << m_wsIdentifier;
-  }
-  javascript << L" = null;\n";
-  javascript << L"var ";
-  javascript << RUNTIMEBLOCKTEMPARRAY;
-  javascript << L" = ";
-  javascript << XFA_FM_EXPTypeToString(CONCATFMOBJECT);
-  javascript << L"(";
+  if (type == ReturnType::kImplied)
+    *js << "pfm_ret = 0;\n";
 
+  *js << "{\n";
+
+  WideString tmpName = IdentifierToName(m_wsIdentifier);
+  *js << "var " << tmpName << " = null;\n";
+  *js << "var pfm_ary = pfm_rt.concat_obj(";
   for (const auto& expr : m_pAccessors) {
-    if (!expr->ToJavaScript(javascript))
+    if (!expr->ToJavaScript(js, ReturnType::kInfered))
       return false;
     if (expr != m_pAccessors.back())
-      javascript << L", ";
+      *js << ", ";
   }
-  javascript << L");\n";
-  javascript << L"var ";
-  javascript << RUNTIMEBLOCKTEMPARRAYINDEX;
-  javascript << (L" = 0;\n");
-  javascript << L"while(";
-  javascript << RUNTIMEBLOCKTEMPARRAYINDEX;
-  javascript << L" < ";
-  javascript << RUNTIMEBLOCKTEMPARRAY;
-  javascript << L".length)\n{\n";
-  if (m_wsIdentifier[0] == L'!') {
-    WideString tempIdentifier =
-        EXCLAMATION_IN_IDENTIFIER +
-        m_wsIdentifier.Right(m_wsIdentifier.GetLength() - 1);
-    javascript << tempIdentifier;
-  } else {
-    javascript << m_wsIdentifier;
-  }
-  javascript << L" = ";
-  javascript << RUNTIMEBLOCKTEMPARRAY;
-  javascript << L"[";
-  javascript << RUNTIMEBLOCKTEMPARRAYINDEX;
-  javascript << L"++];\n";
-  if (!m_pList->ToJavaScript(javascript))
-    return false;
-  javascript << L"}\n";
-  javascript << L"}\n";
-  return !CXFA_IsTooBig(javascript);
-}
+  *js << ");\n";
 
-bool CXFA_FMForeachExpression::ToImpliedReturnJS(CFX_WideTextBuf& javascript) {
-  CXFA_FMToJavaScriptDepth depthManager;
-  if (CXFA_IsTooBig(javascript) || !depthManager.IsWithinMaxDepth())
+  *js << "var pfm_ary_idx = 0;\n";
+  *js << "while(pfm_ary_idx < pfm_ary.length)\n{\n";
+  *js << tmpName << " = pfm_ary[pfm_ary_idx++];\n";
+  if (!m_pList->ToJavaScript(js, type))
     return false;
+  *js << "}\n";  // while
 
-  javascript << RUNTIMEFUNCTIONRETURNVALUE;
-  javascript << L" = 0;\n";
-  javascript << L"{\n";
-  javascript << L"var ";
-  if (m_wsIdentifier[0] == L'!') {
-    WideString tempIdentifier =
-        EXCLAMATION_IN_IDENTIFIER +
-        m_wsIdentifier.Right(m_wsIdentifier.GetLength() - 1);
-    javascript << tempIdentifier;
-  } else {
-    javascript << m_wsIdentifier;
-  }
-  javascript << L" = null;\n";
-  javascript << L"var ";
-  javascript << RUNTIMEBLOCKTEMPARRAY;
-  javascript << L" = ";
-  javascript << XFA_FM_EXPTypeToString(CONCATFMOBJECT);
-  javascript << L"(";
-  for (const auto& expr : m_pAccessors) {
-    if (!expr->ToJavaScript(javascript))
-      return false;
-    if (expr != m_pAccessors.back())
-      javascript << L", ";
-  }
-  javascript << L");\n";
-  javascript << L"var ";
-  javascript << RUNTIMEBLOCKTEMPARRAYINDEX;
-  javascript << L" = 0;\n";
-  javascript << L"while(";
-  javascript << RUNTIMEBLOCKTEMPARRAYINDEX;
-  javascript << L" < ";
-  javascript << RUNTIMEBLOCKTEMPARRAY;
-  javascript << L".length)\n{\n";
-  if (m_wsIdentifier[0] == L'!') {
-    WideString tempIdentifier =
-        EXCLAMATION_IN_IDENTIFIER +
-        m_wsIdentifier.Right(m_wsIdentifier.GetLength() - 1);
-    javascript << tempIdentifier;
-  } else {
-    javascript << m_wsIdentifier;
-  }
-  javascript << L" = ";
-  javascript << RUNTIMEBLOCKTEMPARRAY;
-  javascript << L"[";
-  javascript << RUNTIMEBLOCKTEMPARRAYINDEX;
-  javascript << L"++];\n";
-  if (!m_pList->ToImpliedReturnJS(javascript))
-    return false;
-  javascript << L"}\n";
-  javascript << L"}\n";
-  return !CXFA_IsTooBig(javascript);
+  *js << "}\n";  // block
+  return !CXFA_IsTooBig(js);
 }
diff --git a/xfa/fxfa/fm2js/cxfa_fmexpression.h b/xfa/fxfa/fm2js/cxfa_fmexpression.h
index cfbba3a..2761ef5 100644
--- a/xfa/fxfa/fm2js/cxfa_fmexpression.h
+++ b/xfa/fxfa/fm2js/cxfa_fmexpression.h
@@ -12,170 +12,143 @@
 
 #include "xfa/fxfa/fm2js/cxfa_fmsimpleexpression.h"
 
-enum XFA_FM_EXPTYPE {
-  XFA_FM_EXPTYPE_UNKNOWN,
-  XFA_FM_EXPTYPE_FUNC,
-  XFA_FM_EXPTYPE_VAR,
-  XFA_FM_EXPTYPE_EXP,
-  XFA_FM_EXPTYPE_BLOCK,
-  XFA_FM_EXPTYPE_IF,
-  XFA_FM_EXPTYPE_BREAK,
-  XFA_FM_EXPTYPE_CONTINUE,
-};
-
 class CFX_WideTextBuf;
 
 class CXFA_FMExpression {
  public:
-  explicit CXFA_FMExpression(uint32_t line);
-  CXFA_FMExpression(uint32_t line, XFA_FM_EXPTYPE type);
-  virtual ~CXFA_FMExpression() {}
+  virtual ~CXFA_FMExpression() = default;
+  virtual bool ToJavaScript(CFX_WideTextBuf* js, ReturnType type) = 0;
 
-  virtual bool ToJavaScript(CFX_WideTextBuf& javascript);
-  virtual bool ToImpliedReturnJS(CFX_WideTextBuf&);
-  uint32_t GetLine() { return m_line; }
-  XFA_FM_EXPTYPE GetExpType() const { return m_type; }
-
- private:
-  XFA_FM_EXPTYPE m_type;
-  uint32_t m_line;
+ protected:
+  CXFA_FMExpression();
 };
 
-class CXFA_FMFunctionDefinition : public CXFA_FMExpression {
+class CXFA_FMFunctionDefinition final : public CXFA_FMExpression {
  public:
-  // Takes ownership of |arguments| and |expressions|.
   CXFA_FMFunctionDefinition(
-      uint32_t line,
-      bool isGlobal,
-      const WideStringView& wsName,
+      WideStringView wsName,
       std::vector<WideStringView>&& arguments,
       std::vector<std::unique_ptr<CXFA_FMExpression>>&& expressions);
   ~CXFA_FMFunctionDefinition() override;
 
-  bool ToJavaScript(CFX_WideTextBuf& javascript) override;
-  bool ToImpliedReturnJS(CFX_WideTextBuf&) override;
+  bool ToJavaScript(CFX_WideTextBuf* js, ReturnType type) override;
 
  private:
   WideStringView m_wsName;
   std::vector<WideStringView> m_pArguments;
   std::vector<std::unique_ptr<CXFA_FMExpression>> m_pExpressions;
-  bool m_isGlobal;
 };
 
-class CXFA_FMVarExpression : public CXFA_FMExpression {
+class CXFA_FMAST {
  public:
-  CXFA_FMVarExpression(uint32_t line,
-                       const WideStringView& wsName,
-                       std::unique_ptr<CXFA_FMExpression> pInit);
+  explicit CXFA_FMAST(
+      std::vector<std::unique_ptr<CXFA_FMExpression>> expressions);
+  ~CXFA_FMAST();
+
+  bool ToJavaScript(CFX_WideTextBuf* js);
+
+ private:
+  std::vector<std::unique_ptr<CXFA_FMExpression>> expressions_;
+};
+
+class CXFA_FMVarExpression final : public CXFA_FMExpression {
+ public:
+  CXFA_FMVarExpression(WideStringView wsName,
+                       std::unique_ptr<CXFA_FMSimpleExpression> pInit);
   ~CXFA_FMVarExpression() override;
 
-  bool ToJavaScript(CFX_WideTextBuf& javascript) override;
-  bool ToImpliedReturnJS(CFX_WideTextBuf&) override;
+  bool ToJavaScript(CFX_WideTextBuf* js, ReturnType type) override;
 
  private:
   WideStringView m_wsName;
-  std::unique_ptr<CXFA_FMExpression> m_pInit;
+  std::unique_ptr<CXFA_FMSimpleExpression> m_pInit;
 };
 
-class CXFA_FMExpExpression : public CXFA_FMExpression {
+class CXFA_FMExpExpression final : public CXFA_FMExpression {
  public:
-  CXFA_FMExpExpression(uint32_t line,
-                       std::unique_ptr<CXFA_FMSimpleExpression> pExpression);
+  explicit CXFA_FMExpExpression(
+      std::unique_ptr<CXFA_FMSimpleExpression> pExpression);
   ~CXFA_FMExpExpression() override;
 
-  bool ToJavaScript(CFX_WideTextBuf& javascript) override;
-  bool ToImpliedReturnJS(CFX_WideTextBuf&) override;
+  bool ToJavaScript(CFX_WideTextBuf* js, ReturnType type) override;
 
  private:
   std::unique_ptr<CXFA_FMSimpleExpression> m_pExpression;
 };
 
-class CXFA_FMBlockExpression : public CXFA_FMExpression {
+class CXFA_FMBlockExpression final : public CXFA_FMExpression {
  public:
   CXFA_FMBlockExpression(
-      uint32_t line,
       std::vector<std::unique_ptr<CXFA_FMExpression>>&& pExpressionList);
   ~CXFA_FMBlockExpression() override;
 
-  bool ToJavaScript(CFX_WideTextBuf& javascript) override;
-  bool ToImpliedReturnJS(CFX_WideTextBuf&) override;
+  bool ToJavaScript(CFX_WideTextBuf* js, ReturnType type) override;
 
  private:
   std::vector<std::unique_ptr<CXFA_FMExpression>> m_ExpressionList;
 };
 
-class CXFA_FMDoExpression : public CXFA_FMExpression {
+class CXFA_FMDoExpression final : public CXFA_FMExpression {
  public:
-  CXFA_FMDoExpression(uint32_t line, std::unique_ptr<CXFA_FMExpression> pList);
+  explicit CXFA_FMDoExpression(std::unique_ptr<CXFA_FMExpression> pList);
   ~CXFA_FMDoExpression() override;
 
-  bool ToJavaScript(CFX_WideTextBuf& javascript) override;
-  bool ToImpliedReturnJS(CFX_WideTextBuf&) override;
+  bool ToJavaScript(CFX_WideTextBuf* js, ReturnType type) override;
 
  private:
   std::unique_ptr<CXFA_FMExpression> m_pList;
 };
 
-class CXFA_FMIfExpression : public CXFA_FMExpression {
+class CXFA_FMIfExpression final : public CXFA_FMExpression {
  public:
-  CXFA_FMIfExpression(uint32_t line,
-                      std::unique_ptr<CXFA_FMSimpleExpression> pExpression,
-                      std::unique_ptr<CXFA_FMExpression> pIfExpression,
-                      std::unique_ptr<CXFA_FMExpression> pElseExpression);
+  CXFA_FMIfExpression(
+      std::unique_ptr<CXFA_FMSimpleExpression> pExpression,
+      std::unique_ptr<CXFA_FMExpression> pIfExpression,
+      std::vector<std::unique_ptr<CXFA_FMIfExpression>> pElseIfExpressions,
+      std::unique_ptr<CXFA_FMExpression> pElseExpression);
   ~CXFA_FMIfExpression() override;
 
-  bool ToJavaScript(CFX_WideTextBuf& javascript) override;
-  bool ToImpliedReturnJS(CFX_WideTextBuf&) override;
+  bool ToJavaScript(CFX_WideTextBuf* js, ReturnType type) override;
 
  private:
   std::unique_ptr<CXFA_FMSimpleExpression> m_pExpression;
   std::unique_ptr<CXFA_FMExpression> m_pIfExpression;
+  std::vector<std::unique_ptr<CXFA_FMIfExpression>> m_pElseIfExpressions;
   std::unique_ptr<CXFA_FMExpression> m_pElseExpression;
 };
 
-class CXFA_FMLoopExpression : public CXFA_FMExpression {
+class CXFA_FMWhileExpression final : public CXFA_FMExpression {
  public:
-  explicit CXFA_FMLoopExpression(uint32_t line) : CXFA_FMExpression(line) {}
-  ~CXFA_FMLoopExpression() override;
-  bool ToJavaScript(CFX_WideTextBuf& javascript) override;
-  bool ToImpliedReturnJS(CFX_WideTextBuf&) override;
-};
-
-class CXFA_FMWhileExpression : public CXFA_FMLoopExpression {
- public:
-  CXFA_FMWhileExpression(uint32_t line,
-                         std::unique_ptr<CXFA_FMSimpleExpression> pCodition,
+  CXFA_FMWhileExpression(std::unique_ptr<CXFA_FMSimpleExpression> pCodition,
                          std::unique_ptr<CXFA_FMExpression> pExpression);
   ~CXFA_FMWhileExpression() override;
 
-  bool ToJavaScript(CFX_WideTextBuf& javascript) override;
-  bool ToImpliedReturnJS(CFX_WideTextBuf&) override;
+  bool ToJavaScript(CFX_WideTextBuf* js, ReturnType type) override;
 
  private:
   std::unique_ptr<CXFA_FMSimpleExpression> m_pCondition;
   std::unique_ptr<CXFA_FMExpression> m_pExpression;
 };
 
-class CXFA_FMBreakExpression : public CXFA_FMExpression {
+class CXFA_FMBreakExpression final : public CXFA_FMExpression {
  public:
-  explicit CXFA_FMBreakExpression(uint32_t line);
+  CXFA_FMBreakExpression();
   ~CXFA_FMBreakExpression() override;
-  bool ToJavaScript(CFX_WideTextBuf& javascript) override;
-  bool ToImpliedReturnJS(CFX_WideTextBuf&) override;
+
+  bool ToJavaScript(CFX_WideTextBuf* js, ReturnType type) override;
 };
 
-class CXFA_FMContinueExpression : public CXFA_FMExpression {
+class CXFA_FMContinueExpression final : public CXFA_FMExpression {
  public:
-  explicit CXFA_FMContinueExpression(uint32_t line);
+  CXFA_FMContinueExpression();
   ~CXFA_FMContinueExpression() override;
-  bool ToJavaScript(CFX_WideTextBuf& javascript) override;
-  bool ToImpliedReturnJS(CFX_WideTextBuf&) override;
+
+  bool ToJavaScript(CFX_WideTextBuf* js, ReturnType type) override;
 };
 
-class CXFA_FMForExpression : public CXFA_FMLoopExpression {
+class CXFA_FMForExpression final : public CXFA_FMExpression {
  public:
-  CXFA_FMForExpression(uint32_t line,
-                       const WideStringView& wsVariant,
+  CXFA_FMForExpression(WideStringView wsVariant,
                        std::unique_ptr<CXFA_FMSimpleExpression> pAssignment,
                        std::unique_ptr<CXFA_FMSimpleExpression> pAccessor,
                        int32_t iDirection,
@@ -183,8 +156,7 @@
                        std::unique_ptr<CXFA_FMExpression> pList);
   ~CXFA_FMForExpression() override;
 
-  bool ToJavaScript(CFX_WideTextBuf& javascript) override;
-  bool ToImpliedReturnJS(CFX_WideTextBuf&) override;
+  bool ToJavaScript(CFX_WideTextBuf* js, ReturnType type) override;
 
  private:
   WideStringView m_wsVariant;
@@ -195,18 +167,16 @@
   std::unique_ptr<CXFA_FMExpression> m_pList;
 };
 
-class CXFA_FMForeachExpression : public CXFA_FMLoopExpression {
+class CXFA_FMForeachExpression final : public CXFA_FMExpression {
  public:
   // Takes ownership of |pAccessors|.
   CXFA_FMForeachExpression(
-      uint32_t line,
-      const WideStringView& wsIdentifier,
+      WideStringView wsIdentifier,
       std::vector<std::unique_ptr<CXFA_FMSimpleExpression>>&& pAccessors,
       std::unique_ptr<CXFA_FMExpression> pList);
   ~CXFA_FMForeachExpression() override;
 
-  bool ToJavaScript(CFX_WideTextBuf& javascript) override;
-  bool ToImpliedReturnJS(CFX_WideTextBuf&) override;
+  bool ToJavaScript(CFX_WideTextBuf* js, ReturnType type) override;
 
  private:
   WideStringView m_wsIdentifier;
diff --git a/xfa/fxfa/fm2js/cxfa_fmexpression_unittest.cpp b/xfa/fxfa/fm2js/cxfa_fmexpression_unittest.cpp
new file mode 100644
index 0000000..9d1a64c
--- /dev/null
+++ b/xfa/fxfa/fm2js/cxfa_fmexpression_unittest.cpp
@@ -0,0 +1,68 @@
+// Copyright 2018 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/fm2js/cxfa_fmexpression.h"
+
+#include <memory>
+#include <utility>
+
+#include "core/fxcrt/cfx_widetextbuf.h"
+#include "core/fxcrt/fx_string.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/base/ptr_util.h"
+#include "xfa/fxfa/fm2js/cxfa_fmtojavascriptdepth.h"
+
+TEST(CXFA_FMExpressionTest, VarExpressionInitNull) {
+  CXFA_FMToJavaScriptDepth::Reset();
+  CFX_WideTextBuf accumulator;
+
+  CXFA_FMVarExpression(L"s", nullptr)
+      .ToJavaScript(&accumulator, ReturnType::kInfered);
+  EXPECT_STREQ(
+      LR"***(var s = "";
+)***",
+      accumulator.MakeString().c_str());
+}
+
+TEST(CXFA_FMExpressionTest, VarExpressionInitBlank) {
+  CXFA_FMToJavaScriptDepth::Reset();
+  CFX_WideTextBuf accumulator;
+
+  auto init = pdfium::MakeUnique<CXFA_FMStringExpression>(LR"("")");
+  CXFA_FMVarExpression(L"s", std::move(init))
+      .ToJavaScript(&accumulator, ReturnType::kInfered);
+  EXPECT_STREQ(
+      LR"***(var s = "";
+s = pfm_rt.var_filter(s);
+)***",
+      accumulator.MakeString().c_str());
+}
+
+TEST(CXFA_FMExpressionTest, VarExpressionInitString) {
+  CXFA_FMToJavaScriptDepth::Reset();
+  CFX_WideTextBuf accumulator;
+
+  auto init = pdfium::MakeUnique<CXFA_FMStringExpression>(LR"("foo")");
+  CXFA_FMVarExpression(L"s", std::move(init))
+      .ToJavaScript(&accumulator, ReturnType::kInfered);
+  EXPECT_STREQ(
+      LR"***(var s = "foo";
+s = pfm_rt.var_filter(s);
+)***",
+      accumulator.MakeString().c_str());
+}
+
+TEST(CXFA_FMExpressionTest, VarExpressionInitNumeric) {
+  CXFA_FMToJavaScriptDepth::Reset();
+  CFX_WideTextBuf accumulator;
+
+  auto init = pdfium::MakeUnique<CXFA_FMNumberExpression>(L"112");
+  CXFA_FMVarExpression(L"s", std::move(init))
+      .ToJavaScript(&accumulator, ReturnType::kInfered);
+  EXPECT_STREQ(
+      LR"***(var s = 112;
+s = pfm_rt.var_filter(s);
+)***",
+      accumulator.MakeString().c_str());
+}
diff --git a/xfa/fxfa/fm2js/cxfa_fmlexer.cpp b/xfa/fxfa/fm2js/cxfa_fmlexer.cpp
index 675abc3..efb59f2 100644
--- a/xfa/fxfa/fm2js/cxfa_fmlexer.cpp
+++ b/xfa/fxfa/fm2js/cxfa_fmlexer.cpp
@@ -1,4 +1,4 @@
-// Copright 2014 PDFium Authors. All rights reserved.
+// Copyright 2014 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.
 
@@ -9,8 +9,6 @@
 #include <algorithm>
 
 #include "core/fxcrt/fx_extension.h"
-#include "third_party/base/ptr_util.h"
-#include "third_party/icu/source/common/unicode/uchar.h"
 
 namespace {
 
@@ -20,14 +18,14 @@
 }
 
 bool IsIdentifierCharacter(wchar_t c) {
-  return u_isalnum(c) || c == 0x005F ||  // '_'
-         c == 0x0024;                    // '$'
+  return FXSYS_iswalnum(c) || c == 0x005F ||  // '_'
+         c == 0x0024;                         // '$'
 }
 
 bool IsInitialIdentifierCharacter(wchar_t c) {
-  return u_isalpha(c) || c == 0x005F ||  // '_'
-         c == 0x0024 ||                  // '$'
-         c == 0x0021;                    // '!'
+  return FXSYS_iswalpha(c) || c == 0x005F ||  // '_'
+         c == 0x0024 ||                       // '$'
+         c == 0x0021;                         // '!'
 }
 
 bool IsWhitespaceCharacter(wchar_t c) {
@@ -38,158 +36,125 @@
 }
 
 const XFA_FMKeyword keyWords[] = {
-    {TOKand, 0x00000026, L"&"},
-    {TOKlparen, 0x00000028, L"("},
-    {TOKrparen, 0x00000029, L")"},
-    {TOKmul, 0x0000002a, L"*"},
-    {TOKplus, 0x0000002b, L"+"},
-    {TOKcomma, 0x0000002c, L","},
-    {TOKminus, 0x0000002d, L"-"},
-    {TOKdot, 0x0000002e, L"."},
-    {TOKdiv, 0x0000002f, L"/"},
-    {TOKlt, 0x0000003c, L"<"},
-    {TOKassign, 0x0000003d, L"="},
-    {TOKgt, 0x0000003e, L">"},
-    {TOKlbracket, 0x0000005b, L"["},
-    {TOKrbracket, 0x0000005d, L"]"},
-    {TOKor, 0x0000007c, L"|"},
-    {TOKdotscream, 0x0000ec11, L".#"},
-    {TOKdotstar, 0x0000ec18, L".*"},
-    {TOKdotdot, 0x0000ec1c, L".."},
-    {TOKle, 0x000133f9, L"<="},
-    {TOKne, 0x000133fa, L"<>"},
-    {TOKeq, 0x0001391a, L"=="},
-    {TOKge, 0x00013e3b, L">="},
-    {TOKdo, 0x00020153, L"do"},
-    {TOKkseq, 0x00020676, L"eq"},
-    {TOKksge, 0x000210ac, L"ge"},
-    {TOKksgt, 0x000210bb, L"gt"},
-    {TOKif, 0x00021aef, L"if"},
-    {TOKin, 0x00021af7, L"in"},
-    {TOKksle, 0x00022a51, L"le"},
-    {TOKkslt, 0x00022a60, L"lt"},
-    {TOKksne, 0x00023493, L"ne"},
-    {TOKksor, 0x000239c1, L"or"},
-    {TOKnull, 0x052931bb, L"null"},
-    {TOKbreak, 0x05518c25, L"break"},
-    {TOKksand, 0x09f9db33, L"and"},
-    {TOKend, 0x0a631437, L"end"},
-    {TOKeof, 0x0a63195a, L"eof"},
-    {TOKfor, 0x0a7d67a7, L"for"},
-    {TOKnan, 0x0b4f91dd, L"nan"},
-    {TOKksnot, 0x0b4fd9b1, L"not"},
-    {TOKvar, 0x0c2203e9, L"var"},
-    {TOKthen, 0x2d5738cf, L"then"},
-    {TOKelse, 0x45f65ee9, L"else"},
-    {TOKexit, 0x4731d6ba, L"exit"},
-    {TOKdownto, 0x4caadc3b, L"downto"},
-    {TOKreturn, 0x4db8bd60, L"return"},
-    {TOKinfinity, 0x5c0a010a, L"infinity"},
-    {TOKendwhile, 0x5c64bff0, L"endwhile"},
-    {TOKforeach, 0x67e31f38, L"foreach"},
-    {TOKendfunc, 0x68f984a3, L"endfunc"},
-    {TOKelseif, 0x78253218, L"elseif"},
-    {TOKwhile, 0x84229259, L"while"},
-    {TOKendfor, 0x8ab49d7e, L"endfor"},
-    {TOKthrow, 0x8db05c94, L"throw"},
-    {TOKstep, 0xa7a7887c, L"step"},
-    {TOKupto, 0xb5155328, L"upto"},
-    {TOKcontinue, 0xc0340685, L"continue"},
-    {TOKfunc, 0xcdce60ec, L"func"},
-    {TOKendif, 0xe0e8fee6, L"endif"},
+    {TOKdo, "do"},
+    {TOKkseq, "eq"},
+    {TOKksge, "ge"},
+    {TOKksgt, "gt"},
+    {TOKif, "if"},
+    {TOKin, "in"},
+    {TOKksle, "le"},
+    {TOKkslt, "lt"},
+    {TOKksne, "ne"},
+    {TOKksor, "or"},
+    {TOKnull, "null"},
+    {TOKbreak, "break"},
+    {TOKksand, "and"},
+    {TOKend, "end"},
+    {TOKeof, "eof"},
+    {TOKfor, "for"},
+    {TOKnan, "nan"},
+    {TOKksnot, "not"},
+    {TOKvar, "var"},
+    {TOKthen, "then"},
+    {TOKelse, "else"},
+    {TOKexit, "exit"},
+    {TOKdownto, "downto"},
+    {TOKreturn, "return"},
+    {TOKinfinity, "infinity"},
+    {TOKendwhile, "endwhile"},
+    {TOKforeach, "foreach"},
+    {TOKendfunc, "endfunc"},
+    {TOKelseif, "elseif"},
+    {TOKwhile, "while"},
+    {TOKendfor, "endfor"},
+    {TOKthrow, "throw"},
+    {TOKstep, "step"},
+    {TOKupto, "upto"},
+    {TOKcontinue, "continue"},
+    {TOKfunc, "func"},
+    {TOKendif, "endif"},
 };
 
-const XFA_FM_TOKEN KEYWORD_START = TOKdo;
-const XFA_FM_TOKEN KEYWORD_END = TOKendif;
-
-const wchar_t* tokenStrings[] = {
-    L"TOKand",        L"TOKlparen",     L"TOKrparen",   L"TOKmul",
-    L"TOKplus",       L"TOKcomma",      L"TOKminus",    L"TOKdot",
-    L"TOKdiv",        L"TOKlt",         L"TOKassign",   L"TOKgt",
-    L"TOKlbracket",   L"TOKrbracket",   L"TOKor",       L"TOKdotscream",
-    L"TOKdotstar",    L"TOKdotdot",     L"TOKle",       L"TOKne",
-    L"TOKeq",         L"TOKge",         L"TOKdo",       L"TOKkseq",
-    L"TOKksge",       L"TOKksgt",       L"TOKif",       L"TOKin",
-    L"TOKksle",       L"TOKkslt",       L"TOKksne",     L"TOKksor",
-    L"TOKnull",       L"TOKbreak",      L"TOKksand",    L"TOKend",
-    L"TOKeof",        L"TOKfor",        L"TOKnan",      L"TOKksnot",
-    L"TOKvar",        L"TOKthen",       L"TOKelse",     L"TOKexit",
-    L"TOKdownto",     L"TOKreturn",     L"TOKinfinity", L"TOKendwhile",
-    L"TOKforeach",    L"TOKendfunc",    L"TOKelseif",   L"TOKwhile",
-    L"TOKendfor",     L"TOKthrow",      L"TOKstep",     L"TOKupto",
-    L"TOKcontinue",   L"TOKfunc",       L"TOKendif",    L"TOKstar",
-    L"TOKidentifier", L"TOKunderscore", L"TOKdollar",   L"TOKexclamation",
-    L"TOKcall",       L"TOKstring",     L"TOKnumber",   L"TOKreserver",
+#ifndef NDEBUG
+const char* const tokenStrings[] = {
+    "TOKand",        "TOKlparen",     "TOKrparen",   "TOKmul",
+    "TOKplus",       "TOKcomma",      "TOKminus",    "TOKdot",
+    "TOKdiv",        "TOKlt",         "TOKassign",   "TOKgt",
+    "TOKlbracket",   "TOKrbracket",   "TOKor",       "TOKdotscream",
+    "TOKdotstar",    "TOKdotdot",     "TOKle",       "TOKne",
+    "TOKeq",         "TOKge",         "TOKdo",       "TOKkseq",
+    "TOKksge",       "TOKksgt",       "TOKif",       "TOKin",
+    "TOKksle",       "TOKkslt",       "TOKksne",     "TOKksor",
+    "TOKnull",       "TOKbreak",      "TOKksand",    "TOKend",
+    "TOKeof",        "TOKfor",        "TOKnan",      "TOKksnot",
+    "TOKvar",        "TOKthen",       "TOKelse",     "TOKexit",
+    "TOKdownto",     "TOKreturn",     "TOKinfinity", "TOKendwhile",
+    "TOKforeach",    "TOKendfunc",    "TOKelseif",   "TOKwhile",
+    "TOKendfor",     "TOKthrow",      "TOKstep",     "TOKupto",
+    "TOKcontinue",   "TOKfunc",       "TOKendif",    "TOKstar",
+    "TOKidentifier", "TOKunderscore", "TOKdollar",   "TOKexclamation",
+    "TOKcall",       "TOKstring",     "TOKnumber",   "TOKreserver",
 };
+#endif  // NDEBUG
 
-XFA_FM_TOKEN TokenizeIdentifier(const WideStringView& str) {
-  uint32_t key = FX_HashCode_GetW(str, true);
-
-  const XFA_FMKeyword* end = std::begin(keyWords) + KEYWORD_END + 1;
+XFA_FM_TOKEN TokenizeIdentifier(WideStringView str) {
   const XFA_FMKeyword* result =
-      std::lower_bound(std::begin(keyWords) + KEYWORD_START, end, key,
-                       [](const XFA_FMKeyword& iter, const uint32_t& val) {
-                         return iter.m_hash < val;
-                       });
-  if (result != end && result->m_hash == key)
+      std::find_if(std::begin(keyWords), std::end(keyWords),
+                   [str](const XFA_FMKeyword& iter) {
+                     return str.EqualsASCII(iter.m_keyword);
+                   });
+  if (result != std::end(keyWords) && str.EqualsASCII(result->m_keyword))
     return result->m_type;
   return TOKidentifier;
 }
 
 }  // namespace
 
-CXFA_FMToken::CXFA_FMToken() : m_type(TOKreserver), m_line_num(1) {}
+CXFA_FMToken::CXFA_FMToken(XFA_FM_TOKEN token) : m_type(token) {}
 
-CXFA_FMToken::CXFA_FMToken(uint32_t line_num)
-    : m_type(TOKreserver), m_line_num(line_num) {}
+CXFA_FMToken::CXFA_FMToken() : CXFA_FMToken(TOKreserver) {}
 
-CXFA_FMToken::~CXFA_FMToken() {}
+CXFA_FMToken::CXFA_FMToken(const CXFA_FMToken&) = default;
 
+CXFA_FMToken::~CXFA_FMToken() = default;
+
+#ifndef NDEBUG
 WideString CXFA_FMToken::ToDebugString() const {
-  WideString str(L"type = ");
-  str += tokenStrings[m_type];
-  str += L", string = ";
+  WideString str = WideString::FromASCII("type = ");
+  str += WideString::FromASCII(tokenStrings[m_type]);
+  str += WideString::FromASCII(", string = ");
   str += m_string;
-  str += L", line_num = ";
-  str += std::to_wstring(m_line_num).c_str();
   return str;
 }
+#endif  // NDEBUG
 
-CXFA_FMLexer::CXFA_FMLexer(const WideStringView& wsFormCalc)
-    : m_cursor(wsFormCalc.unterminated_c_str()),
-      m_end(m_cursor + wsFormCalc.GetLength() - 1),
-      m_current_line(1),
-      m_lexer_error(false) {}
+CXFA_FMLexer::CXFA_FMLexer(WideStringView wsFormCalc)
+    : m_spInput(wsFormCalc.span()) {}
 
-CXFA_FMLexer::~CXFA_FMLexer() {}
+CXFA_FMLexer::~CXFA_FMLexer() = default;
 
-std::unique_ptr<CXFA_FMToken> CXFA_FMLexer::NextToken() {
-  if (m_lexer_error)
-    return nullptr;
+CXFA_FMToken CXFA_FMLexer::NextToken() {
+  if (m_bLexerError)
+    return CXFA_FMToken();
 
-  m_token = pdfium::MakeUnique<CXFA_FMToken>(m_current_line);
-  while (m_cursor <= m_end && *m_cursor) {
-    if (!IsFormCalcCharacter(*m_cursor)) {
+  while (!IsComplete() && m_spInput[m_nCursor]) {
+    if (!IsFormCalcCharacter(m_spInput[m_nCursor])) {
       RaiseError();
-      return nullptr;
+      return CXFA_FMToken();
     }
 
-    switch (*m_cursor) {
+    switch (m_spInput[m_nCursor]) {
       case '\n':
-        ++m_current_line;
-        m_token->m_line_num = m_current_line;
-        ++m_cursor;
+        ++m_nCursor;
         break;
       case '\r':
-        ++m_cursor;
+        ++m_nCursor;
         break;
       case ';':
         AdvanceForComment();
         break;
       case '"':
-        m_token->m_type = TOKstring;
-        AdvanceForString();
-        return std::move(m_token);
+        return AdvanceForString();
       case '0':
       case '1':
       case '2':
@@ -200,257 +165,232 @@
       case '7':
       case '8':
       case '9':
-        m_token->m_type = TOKnumber;
-        AdvanceForNumber();
-        return std::move(m_token);
+        return AdvanceForNumber();
       case '=':
-        ++m_cursor;
-        if (m_cursor > m_end) {
-          m_token->m_type = TOKassign;
-          return std::move(m_token);
-        }
+        ++m_nCursor;
+        if (m_nCursor >= m_spInput.size())
+          return CXFA_FMToken(TOKassign);
 
-        if (!IsFormCalcCharacter(*m_cursor)) {
+        if (!IsFormCalcCharacter(m_spInput[m_nCursor])) {
           RaiseError();
-          return nullptr;
+          return CXFA_FMToken();
         }
-        if (*m_cursor == '=') {
-          m_token->m_type = TOKeq;
-          ++m_cursor;
-        } else {
-          m_token->m_type = TOKassign;
+        if (m_spInput[m_nCursor] == '=') {
+          ++m_nCursor;
+          return CXFA_FMToken(TOKeq);
         }
-        return std::move(m_token);
+        return CXFA_FMToken(TOKassign);
       case '<':
-        ++m_cursor;
-        if (m_cursor > m_end) {
-          m_token->m_type = TOKlt;
-          return std::move(m_token);
-        }
+        ++m_nCursor;
+        if (m_nCursor >= m_spInput.size())
+          return CXFA_FMToken(TOKlt);
 
-        if (!IsFormCalcCharacter(*m_cursor)) {
+        if (!IsFormCalcCharacter(m_spInput[m_nCursor])) {
           RaiseError();
-          return nullptr;
+          return CXFA_FMToken();
         }
-        if (*m_cursor == '=') {
-          m_token->m_type = TOKle;
-          ++m_cursor;
-        } else if (*m_cursor == '>') {
-          m_token->m_type = TOKne;
-          ++m_cursor;
-        } else {
-          m_token->m_type = TOKlt;
+        if (m_spInput[m_nCursor] == '=') {
+          ++m_nCursor;
+          return CXFA_FMToken(TOKle);
         }
-        return std::move(m_token);
+        if (m_spInput[m_nCursor] == '>') {
+          ++m_nCursor;
+          return CXFA_FMToken(TOKne);
+        }
+        return CXFA_FMToken(TOKlt);
       case '>':
-        ++m_cursor;
-        if (m_cursor > m_end) {
-          m_token->m_type = TOKgt;
-          return std::move(m_token);
-        }
+        ++m_nCursor;
+        if (m_nCursor >= m_spInput.size())
+          return CXFA_FMToken(TOKgt);
 
-        if (!IsFormCalcCharacter(*m_cursor)) {
+        if (!IsFormCalcCharacter(m_spInput[m_nCursor])) {
           RaiseError();
-          return nullptr;
+          return CXFA_FMToken();
         }
-        if (*m_cursor == '=') {
-          m_token->m_type = TOKge;
-          ++m_cursor;
-        } else {
-          m_token->m_type = TOKgt;
+        if (m_spInput[m_nCursor] == '=') {
+          ++m_nCursor;
+          return CXFA_FMToken(TOKge);
         }
-        return std::move(m_token);
+        return CXFA_FMToken(TOKgt);
       case ',':
-        m_token->m_type = TOKcomma;
-        ++m_cursor;
-        return std::move(m_token);
+        ++m_nCursor;
+        return CXFA_FMToken(TOKcomma);
       case '(':
-        m_token->m_type = TOKlparen;
-        ++m_cursor;
-        return std::move(m_token);
+        ++m_nCursor;
+        return CXFA_FMToken(TOKlparen);
       case ')':
-        m_token->m_type = TOKrparen;
-        ++m_cursor;
-        return std::move(m_token);
+        ++m_nCursor;
+        return CXFA_FMToken(TOKrparen);
       case '[':
-        m_token->m_type = TOKlbracket;
-        ++m_cursor;
-        return std::move(m_token);
+        ++m_nCursor;
+        return CXFA_FMToken(TOKlbracket);
       case ']':
-        m_token->m_type = TOKrbracket;
-        ++m_cursor;
-        return std::move(m_token);
+        ++m_nCursor;
+        return CXFA_FMToken(TOKrbracket);
       case '&':
-        ++m_cursor;
-        m_token->m_type = TOKand;
-        return std::move(m_token);
+        ++m_nCursor;
+        return CXFA_FMToken(TOKand);
       case '|':
-        ++m_cursor;
-        m_token->m_type = TOKor;
-        return std::move(m_token);
+        ++m_nCursor;
+        return CXFA_FMToken(TOKor);
       case '+':
-        ++m_cursor;
-        m_token->m_type = TOKplus;
-        return std::move(m_token);
+        ++m_nCursor;
+        return CXFA_FMToken(TOKplus);
       case '-':
-        ++m_cursor;
-        m_token->m_type = TOKminus;
-        return std::move(m_token);
+        ++m_nCursor;
+        return CXFA_FMToken(TOKminus);
       case '*':
-        ++m_cursor;
-        m_token->m_type = TOKmul;
-        return std::move(m_token);
+        ++m_nCursor;
+        return CXFA_FMToken(TOKmul);
       case '/': {
-        ++m_cursor;
-        if (m_cursor > m_end) {
-          m_token->m_type = TOKdiv;
-          return std::move(m_token);
-        }
+        ++m_nCursor;
+        if (m_nCursor >= m_spInput.size())
+          return CXFA_FMToken(TOKdiv);
 
-        if (!IsFormCalcCharacter(*m_cursor)) {
+        if (!IsFormCalcCharacter(m_spInput[m_nCursor])) {
           RaiseError();
-          return nullptr;
+          return CXFA_FMToken();
         }
-        if (*m_cursor != '/') {
-          m_token->m_type = TOKdiv;
-          return std::move(m_token);
-        }
+        if (m_spInput[m_nCursor] != '/')
+          return CXFA_FMToken(TOKdiv);
+
         AdvanceForComment();
         break;
       }
       case '.':
-        ++m_cursor;
-        if (m_cursor > m_end) {
-          m_token->m_type = TOKdot;
-          return std::move(m_token);
-        }
+        ++m_nCursor;
+        if (m_nCursor >= m_spInput.size())
+          return CXFA_FMToken(TOKdot);
 
-        if (!IsFormCalcCharacter(*m_cursor)) {
+        if (!IsFormCalcCharacter(m_spInput[m_nCursor])) {
           RaiseError();
-          return nullptr;
+          return CXFA_FMToken();
         }
 
-        if (*m_cursor == '.') {
-          m_token->m_type = TOKdotdot;
-          ++m_cursor;
-        } else if (*m_cursor == '*') {
-          m_token->m_type = TOKdotstar;
-          ++m_cursor;
-        } else if (*m_cursor == '#') {
-          m_token->m_type = TOKdotscream;
-          ++m_cursor;
-        } else if (*m_cursor <= '9' && *m_cursor >= '0') {
-          m_token->m_type = TOKnumber;
-          --m_cursor;
-          AdvanceForNumber();
-        } else {
-          m_token->m_type = TOKdot;
+        if (m_spInput[m_nCursor] == '.') {
+          ++m_nCursor;
+          return CXFA_FMToken(TOKdotdot);
         }
-        return std::move(m_token);
+        if (m_spInput[m_nCursor] == '*') {
+          ++m_nCursor;
+          return CXFA_FMToken(TOKdotstar);
+        }
+        if (m_spInput[m_nCursor] == '#') {
+          ++m_nCursor;
+          return CXFA_FMToken(TOKdotscream);
+        }
+        if (FXSYS_IsDecimalDigit(m_spInput[m_nCursor])) {
+          --m_nCursor;
+          return AdvanceForNumber();
+        }
+        return CXFA_FMToken(TOKdot);
       default:
-        if (IsWhitespaceCharacter(*m_cursor)) {
-          ++m_cursor;
+        if (IsWhitespaceCharacter(m_spInput[m_nCursor])) {
+          ++m_nCursor;
           break;
         }
-        if (!IsInitialIdentifierCharacter(*m_cursor)) {
+        if (!IsInitialIdentifierCharacter(m_spInput[m_nCursor])) {
           RaiseError();
-          return nullptr;
+          return CXFA_FMToken();
         }
-        AdvanceForIdentifier();
-        return std::move(m_token);
+        return AdvanceForIdentifier();
     }
   }
-
-  // If there isn't currently a token type then mark it EOF.
-  if (m_token->m_type == TOKreserver)
-    m_token->m_type = TOKeof;
-  return std::move(m_token);
+  return CXFA_FMToken(TOKeof);
 }
 
-void CXFA_FMLexer::AdvanceForNumber() {
+CXFA_FMToken CXFA_FMLexer::AdvanceForNumber() {
   // This will set end to the character after the end of the number.
-  wchar_t* end = nullptr;
-  if (m_cursor)
-    wcstod(const_cast<wchar_t*>(m_cursor), &end);
-  if (!end || FXSYS_iswalpha(*end)) {
-    RaiseError();
-    return;
+  int32_t used_length = 0;
+  if (m_nCursor < m_spInput.size()) {
+    FXSYS_wcstof(&m_spInput[m_nCursor], m_spInput.size() - m_nCursor,
+                 &used_length);
   }
-
-  m_token->m_string =
-      WideStringView(m_cursor, static_cast<size_t>(end - m_cursor));
-  m_cursor = end;
+  size_t end = m_nCursor + used_length;
+  if (used_length == 0 ||
+      (end < m_spInput.size() && FXSYS_iswalpha(m_spInput[end]))) {
+    RaiseError();
+    return CXFA_FMToken();
+  }
+  CXFA_FMToken token(TOKnumber);
+  token.m_string =
+      WideStringView(m_spInput.subspan(m_nCursor, end - m_nCursor));
+  m_nCursor = end;
+  return token;
 }
 
-void CXFA_FMLexer::AdvanceForString() {
-  const wchar_t* start = m_cursor;
-  ++m_cursor;
-  while (m_cursor <= m_end && *m_cursor) {
-    if (!IsFormCalcCharacter(*m_cursor))
+CXFA_FMToken CXFA_FMLexer::AdvanceForString() {
+  CXFA_FMToken token(TOKstring);
+  size_t start = m_nCursor;
+  ++m_nCursor;
+  while (!IsComplete() && m_spInput[m_nCursor]) {
+    if (!IsFormCalcCharacter(m_spInput[m_nCursor]))
       break;
 
-    if (*m_cursor == '"') {
+    if (m_spInput[m_nCursor] == '"') {
       // Check for escaped "s, i.e. "".
-      ++m_cursor;
+      ++m_nCursor;
       // If the end of the input has been reached it was not escaped.
-      if (m_cursor > m_end) {
-        m_token->m_string =
-            WideStringView(start, static_cast<size_t>(m_cursor - start));
-        return;
+      if (m_nCursor >= m_spInput.size()) {
+        token.m_string =
+            WideStringView(m_spInput.subspan(start, m_nCursor - start));
+        return token;
       }
       // If the next character is not a " then the end of the string has been
       // found.
-      if (*m_cursor != '"') {
-        if (!IsFormCalcCharacter(*m_cursor)) {
+      if (m_spInput[m_nCursor] != '"') {
+        if (!IsFormCalcCharacter(m_spInput[m_nCursor]))
           break;
-        }
-        m_token->m_string = WideStringView(start, (m_cursor - start));
-        return;
+
+        token.m_string =
+            WideStringView(m_spInput.subspan(start, m_nCursor - start));
+        return token;
       }
     }
-    ++m_cursor;
+    ++m_nCursor;
   }
 
   // Didn't find the end of the string.
   RaiseError();
+  return CXFA_FMToken();
 }
 
-void CXFA_FMLexer::AdvanceForIdentifier() {
-  const wchar_t* start = m_cursor;
-  ++m_cursor;
-  while (m_cursor <= m_end && *m_cursor) {
-    if (!IsFormCalcCharacter(*m_cursor)) {
+CXFA_FMToken CXFA_FMLexer::AdvanceForIdentifier() {
+  size_t start = m_nCursor;
+  ++m_nCursor;
+  while (!IsComplete() && m_spInput[m_nCursor]) {
+    if (!IsFormCalcCharacter(m_spInput[m_nCursor])) {
       RaiseError();
-      return;
+      return CXFA_FMToken();
     }
-
-    if (!IsIdentifierCharacter(*m_cursor)) {
+    if (!IsIdentifierCharacter(m_spInput[m_nCursor]))
       break;
-    }
-    ++m_cursor;
+
+    ++m_nCursor;
   }
-  m_token->m_string =
-      WideStringView(start, static_cast<size_t>(m_cursor - start));
-  m_token->m_type = TokenizeIdentifier(m_token->m_string);
+
+  WideStringView str =
+      WideStringView(m_spInput.subspan(start, m_nCursor - start));
+  CXFA_FMToken token(TokenizeIdentifier(str));
+  token.m_string = str;
+  return token;
 }
 
 void CXFA_FMLexer::AdvanceForComment() {
-  m_cursor++;
-  while (m_cursor <= m_end && *m_cursor) {
-    if (!IsFormCalcCharacter(*m_cursor)) {
+  ++m_nCursor;
+  while (!IsComplete() && m_spInput[m_nCursor]) {
+    if (!IsFormCalcCharacter(m_spInput[m_nCursor])) {
       RaiseError();
       return;
     }
-
-    if (*m_cursor == L'\r') {
-      ++m_cursor;
+    if (m_spInput[m_nCursor] == L'\r') {
+      ++m_nCursor;
       return;
     }
-    if (*m_cursor == L'\n') {
-      ++m_current_line;
-      ++m_cursor;
+    if (m_spInput[m_nCursor] == L'\n') {
+      ++m_nCursor;
       return;
     }
-    ++m_cursor;
+    ++m_nCursor;
   }
 }
diff --git a/xfa/fxfa/fm2js/cxfa_fmlexer.h b/xfa/fxfa/fm2js/cxfa_fmlexer.h
index b9764c5..2d9e5fc 100644
--- a/xfa/fxfa/fm2js/cxfa_fmlexer.h
+++ b/xfa/fxfa/fm2js/cxfa_fmlexer.h
@@ -7,9 +7,6 @@
 #ifndef XFA_FXFA_FM2JS_CXFA_FMLEXER_H_
 #define XFA_FXFA_FM2JS_CXFA_FMLEXER_H_
 
-#include <memory>
-#include <utility>
-
 #include "core/fxcrt/fx_string.h"
 
 enum XFA_FM_TOKEN {
@@ -85,50 +82,43 @@
 
 struct XFA_FMKeyword {
   XFA_FM_TOKEN m_type;
-  uint32_t m_hash;
-  const wchar_t* m_keyword;
+  const char* m_keyword;  // Raw, POD struct.
 };
 
 class CXFA_FMToken {
  public:
   CXFA_FMToken();
-  explicit CXFA_FMToken(uint32_t line_num);
+  explicit CXFA_FMToken(XFA_FM_TOKEN token);
+  CXFA_FMToken(const CXFA_FMToken&);
   ~CXFA_FMToken();
 
+#ifndef NDEBUG
   WideString ToDebugString() const;
+#endif  // NDEBUG
 
   WideStringView m_string;
   XFA_FM_TOKEN m_type;
-  uint32_t m_line_num;
 };
 
 class CXFA_FMLexer {
  public:
-  explicit CXFA_FMLexer(const WideStringView& wsFormcalc);
+  explicit CXFA_FMLexer(WideStringView wsFormcalc);
   ~CXFA_FMLexer();
 
-  std::unique_ptr<CXFA_FMToken> NextToken();
-
-  void SetCurrentLine(uint32_t line) { m_current_line = line; }
-  const wchar_t* GetPos() { return m_cursor; }
-  void SetPos(const wchar_t* pos) { m_cursor = pos; }
+  CXFA_FMToken NextToken();
+  bool IsComplete() const { return m_nCursor >= m_spInput.size(); }
 
  private:
-  void AdvanceForNumber();
-  void AdvanceForString();
-  void AdvanceForIdentifier();
+  CXFA_FMToken AdvanceForNumber();
+  CXFA_FMToken AdvanceForString();
+  CXFA_FMToken AdvanceForIdentifier();
   void AdvanceForComment();
 
-  void RaiseError() {
-    m_token.reset();
-    m_lexer_error = true;
-  }
+  void RaiseError() { m_bLexerError = true; }
 
-  const wchar_t* m_cursor;
-  const wchar_t* const m_end;
-  uint32_t m_current_line;
-  std::unique_ptr<CXFA_FMToken> m_token;
-  bool m_lexer_error;
+  pdfium::span<const wchar_t> m_spInput;
+  size_t m_nCursor = 0;
+  bool m_bLexerError = false;
 };
 
 #endif  // XFA_FXFA_FM2JS_CXFA_FMLEXER_H_
diff --git a/xfa/fxfa/fm2js/cxfa_fmlexer_unittest.cpp b/xfa/fxfa/fm2js/cxfa_fmlexer_unittest.cpp
index a6ab871..3627e15 100644
--- a/xfa/fxfa/fm2js/cxfa_fmlexer_unittest.cpp
+++ b/xfa/fxfa/fm2js/cxfa_fmlexer_unittest.cpp
@@ -7,91 +7,101 @@
 #include <vector>
 
 #include "testing/gtest/include/gtest/gtest.h"
-#include "testing/test_support.h"
 #include "third_party/base/ptr_util.h"
 
+TEST(CXFA_FMLexerTest, NullString) {
+  WideStringView null_string;
+  CXFA_FMLexer lexer(null_string);
+  CXFA_FMToken token = lexer.NextToken();
+  EXPECT_EQ(TOKeof, token.m_type);
+  EXPECT_TRUE(lexer.IsComplete());
+}
+
 TEST(CXFA_FMLexerTest, EmptyString) {
   CXFA_FMLexer lexer(L"");
-  std::unique_ptr<CXFA_FMToken> token = lexer.NextToken();
-  EXPECT_EQ(TOKeof, token->m_type);
+  CXFA_FMToken token = lexer.NextToken();
+  EXPECT_EQ(TOKeof, token.m_type);
+  EXPECT_TRUE(lexer.IsComplete());
 }
 
 TEST(CXFA_FMLexerTest, Numbers) {
   auto lexer = pdfium::MakeUnique<CXFA_FMLexer>(L"-12");
-  std::unique_ptr<CXFA_FMToken> token = lexer->NextToken();
+  CXFA_FMToken token = lexer->NextToken();
   // TODO(dsinclair): Should this return -12 instead of two tokens?
-  EXPECT_EQ(TOKminus, token->m_type);
+  EXPECT_EQ(TOKminus, token.m_type);
   token = lexer->NextToken();
-  EXPECT_EQ(L"12", token->m_string);
+  EXPECT_EQ(L"12", token.m_string);
   token = lexer->NextToken();
-  EXPECT_EQ(TOKeof, token->m_type);
+  EXPECT_EQ(TOKeof, token.m_type);
 
   lexer = pdfium::MakeUnique<CXFA_FMLexer>(L"1.5362");
   token = lexer->NextToken();
-  EXPECT_EQ(TOKnumber, token->m_type);
-  EXPECT_EQ(L"1.5362", token->m_string);
+  EXPECT_EQ(TOKnumber, token.m_type);
+  EXPECT_EQ(L"1.5362", token.m_string);
 
   lexer = pdfium::MakeUnique<CXFA_FMLexer>(L"0.875");
   token = lexer->NextToken();
-  EXPECT_EQ(TOKnumber, token->m_type);
-  EXPECT_EQ(L"0.875", token->m_string);
+  EXPECT_EQ(TOKnumber, token.m_type);
+  EXPECT_EQ(L"0.875", token.m_string);
 
   lexer = pdfium::MakeUnique<CXFA_FMLexer>(L"5.56e-2");
   token = lexer->NextToken();
-  EXPECT_EQ(TOKnumber, token->m_type);
-  EXPECT_EQ(L"5.56e-2", token->m_string);
+  EXPECT_EQ(TOKnumber, token.m_type);
+  EXPECT_EQ(L"5.56e-2", token.m_string);
 
   lexer = pdfium::MakeUnique<CXFA_FMLexer>(L"1.234E10");
   token = lexer->NextToken();
-  EXPECT_EQ(TOKnumber, token->m_type);
-  EXPECT_EQ(L"1.234E10", token->m_string);
+  EXPECT_EQ(TOKnumber, token.m_type);
+  EXPECT_EQ(L"1.234E10", token.m_string);
 
   lexer = pdfium::MakeUnique<CXFA_FMLexer>(L"123456789.012345678");
   token = lexer->NextToken();
-  EXPECT_EQ(TOKnumber, token->m_type);
+  EXPECT_EQ(TOKnumber, token.m_type);
   // TODO(dsinclair): This should round as per IEEE 64-bit values.
-  // EXPECT_EQ(L"123456789.01234567", token->m_string);
-  EXPECT_EQ(L"123456789.012345678", token->m_string);
+  // EXPECT_EQ(L"123456789.01234567", token.m_string);
+  EXPECT_EQ(L"123456789.012345678", token.m_string);
 
   lexer = pdfium::MakeUnique<CXFA_FMLexer>(L"99999999999999999");
   token = lexer->NextToken();
-  EXPECT_EQ(TOKnumber, token->m_type);
+  EXPECT_EQ(TOKnumber, token.m_type);
   // TODO(dsinclair): This is spec'd as rounding when > 16 significant digits
   // prior to the exponent.
-  // EXPECT_EQ(L"100000000000000000", token->m_string);
-  EXPECT_EQ(L"99999999999999999", token->m_string);
+  // EXPECT_EQ(L"100000000000000000", token.m_string);
+  EXPECT_EQ(L"99999999999999999", token.m_string);
+  EXPECT_TRUE(lexer->IsComplete());
 }
 
 // The quotes are stripped in CXFA_FMStringExpression::ToJavaScript.
 TEST(CXFA_FMLexerTest, Strings) {
   auto lexer =
       pdfium::MakeUnique<CXFA_FMLexer>(L"\"The cat jumped over the fence.\"");
-  std::unique_ptr<CXFA_FMToken> token = lexer->NextToken();
-  EXPECT_EQ(TOKstring, token->m_type);
-  EXPECT_EQ(L"\"The cat jumped over the fence.\"", token->m_string);
+  CXFA_FMToken token = lexer->NextToken();
+  EXPECT_EQ(TOKstring, token.m_type);
+  EXPECT_EQ(L"\"The cat jumped over the fence.\"", token.m_string);
 
   token = lexer->NextToken();
-  EXPECT_EQ(TOKeof, token->m_type);
+  EXPECT_EQ(TOKeof, token.m_type);
 
   lexer = pdfium::MakeUnique<CXFA_FMLexer>(L"\"\"");
   token = lexer->NextToken();
-  EXPECT_EQ(TOKstring, token->m_type);
-  EXPECT_EQ(L"\"\"", token->m_string);
+  EXPECT_EQ(TOKstring, token.m_type);
+  EXPECT_EQ(L"\"\"", token.m_string);
 
   lexer = pdfium::MakeUnique<CXFA_FMLexer>(
       L"\"The message reads: \"\"Warning: Insufficient Memory\"\"\"");
   token = lexer->NextToken();
-  EXPECT_EQ(TOKstring, token->m_type);
+  EXPECT_EQ(TOKstring, token.m_type);
   EXPECT_EQ(L"\"The message reads: \"\"Warning: Insufficient Memory\"\"\"",
-            token->m_string);
+            token.m_string);
 
   lexer = pdfium::MakeUnique<CXFA_FMLexer>(
       L"\"\\u0047\\u006f\\u0066\\u0069\\u0073\\u0068\\u0021\\u000d\\u000a\"");
   token = lexer->NextToken();
-  EXPECT_EQ(TOKstring, token->m_type);
+  EXPECT_EQ(TOKstring, token.m_type);
   EXPECT_EQ(
       L"\"\\u0047\\u006f\\u0066\\u0069\\u0073\\u0068\\u0021\\u000d\\u000a\"",
-      token->m_string);
+      token.m_string);
+  EXPECT_TRUE(lexer->IsComplete());
 }
 
 // Note, 'this' is a keyword but is not matched by the lexer.
@@ -161,51 +171,53 @@
 
   for (size_t i = 0; i < FX_ArraySize(op); ++i) {
     auto lexer = pdfium::MakeUnique<CXFA_FMLexer>(op[i].op);
-    std::unique_ptr<CXFA_FMToken> token = lexer->NextToken();
-    EXPECT_EQ(op[i].token, token->m_type);
+    CXFA_FMToken token = lexer->NextToken();
+    EXPECT_EQ(op[i].token, token.m_type);
+    EXPECT_TRUE(lexer->IsComplete());
   }
 }
 
 TEST(CXFA_FMLexerTest, Comments) {
   auto lexer = pdfium::MakeUnique<CXFA_FMLexer>(L"// Empty.");
-  std::unique_ptr<CXFA_FMToken> token = lexer->NextToken();
-  EXPECT_EQ(TOKeof, token->m_type);
+  CXFA_FMToken token = lexer->NextToken();
+  EXPECT_EQ(TOKeof, token.m_type);
 
   lexer = pdfium::MakeUnique<CXFA_FMLexer>(L"//");
   token = lexer->NextToken();
-  EXPECT_EQ(TOKeof, token->m_type);
+  EXPECT_EQ(TOKeof, token.m_type);
 
   lexer = pdfium::MakeUnique<CXFA_FMLexer>(L"123 // Empty.\n\"str\"");
   token = lexer->NextToken();
-  EXPECT_EQ(TOKnumber, token->m_type);
-  EXPECT_EQ(L"123", token->m_string);
+  EXPECT_EQ(TOKnumber, token.m_type);
+  EXPECT_EQ(L"123", token.m_string);
 
   token = lexer->NextToken();
-  EXPECT_EQ(TOKstring, token->m_type);
-  EXPECT_EQ(L"\"str\"", token->m_string);
+  EXPECT_EQ(TOKstring, token.m_type);
+  EXPECT_EQ(L"\"str\"", token.m_string);
 
   token = lexer->NextToken();
-  EXPECT_EQ(TOKeof, token->m_type);
+  EXPECT_EQ(TOKeof, token.m_type);
 
   lexer = pdfium::MakeUnique<CXFA_FMLexer>(L";");
   token = lexer->NextToken();
-  EXPECT_EQ(TOKeof, token->m_type);
+  EXPECT_EQ(TOKeof, token.m_type);
 
   lexer = pdfium::MakeUnique<CXFA_FMLexer>(L"; Empty.");
   token = lexer->NextToken();
-  EXPECT_EQ(TOKeof, token->m_type);
+  EXPECT_EQ(TOKeof, token.m_type);
 
   lexer = pdfium::MakeUnique<CXFA_FMLexer>(L"123 ;Empty.\n\"str\"");
   token = lexer->NextToken();
-  EXPECT_EQ(TOKnumber, token->m_type);
-  EXPECT_EQ(L"123", token->m_string);
+  EXPECT_EQ(TOKnumber, token.m_type);
+  EXPECT_EQ(L"123", token.m_string);
 
   token = lexer->NextToken();
-  EXPECT_EQ(TOKstring, token->m_type);
-  EXPECT_EQ(L"\"str\"", token->m_string);
+  EXPECT_EQ(TOKstring, token.m_type);
+  EXPECT_EQ(L"\"str\"", token.m_string);
 
   token = lexer->NextToken();
-  EXPECT_EQ(TOKeof, token->m_type);
+  EXPECT_EQ(TOKeof, token.m_type);
+  EXPECT_TRUE(lexer->IsComplete());
 }
 
 TEST(CXFA_FMLexerTest, ValidIdentifiers) {
@@ -213,43 +225,68 @@
       L"a", L"an_identifier", L"_ident", L"$ident", L"!ident", L"GetAddr"};
   for (const auto* ident : identifiers) {
     auto lexer = pdfium::MakeUnique<CXFA_FMLexer>(ident);
-    std::unique_ptr<CXFA_FMToken> token = lexer->NextToken();
-    EXPECT_EQ(TOKidentifier, token->m_type);
-    EXPECT_EQ(ident, token->m_string);
+    CXFA_FMToken token = lexer->NextToken();
+    EXPECT_EQ(TOKidentifier, token.m_type);
+    EXPECT_EQ(ident, token.m_string);
+    EXPECT_TRUE(lexer->IsComplete());
   }
 }
 
 TEST(CXFA_FMLexerTest, InvalidIdentifiers) {
   auto lexer = pdfium::MakeUnique<CXFA_FMLexer>(L"#a");
-  EXPECT_EQ(nullptr, lexer->NextToken());
+  auto token = lexer->NextToken();
+  EXPECT_EQ(TOKreserver, token.m_type);
 
   lexer = pdfium::MakeUnique<CXFA_FMLexer>(L"1a");
-  EXPECT_EQ(nullptr, lexer->NextToken());
+  token = lexer->NextToken();
+  EXPECT_EQ(TOKreserver, token.m_type);
 
   lexer = pdfium::MakeUnique<CXFA_FMLexer>(L"an@identifier");
-  EXPECT_NE(nullptr, lexer->NextToken());
-  EXPECT_EQ(nullptr, lexer->NextToken());
-  EXPECT_EQ(nullptr, lexer->NextToken());
+  token = lexer->NextToken();
+  EXPECT_NE(TOKreserver, token.m_type);
+  token = lexer->NextToken();
+  EXPECT_EQ(TOKreserver, token.m_type);
+  token = lexer->NextToken();
+  EXPECT_EQ(TOKreserver, token.m_type);
 
   lexer = pdfium::MakeUnique<CXFA_FMLexer>(L"_ident@");
-  EXPECT_NE(nullptr, lexer->NextToken());
-  EXPECT_EQ(nullptr, lexer->NextToken());
+  token = lexer->NextToken();
+  EXPECT_NE(TOKreserver, token.m_type);
+  token = lexer->NextToken();
+  EXPECT_EQ(TOKreserver, token.m_type);
+  EXPECT_FALSE(lexer->IsComplete());
 }
 
 TEST(CXFA_FMLexerTest, Whitespace) {
   auto lexer = pdfium::MakeUnique<CXFA_FMLexer>(L" \t\xc\x9\xb");
-  std::unique_ptr<CXFA_FMToken> token = lexer->NextToken();
-  EXPECT_EQ(TOKeof, token->m_type);
+  CXFA_FMToken token = lexer->NextToken();
+  EXPECT_EQ(TOKeof, token.m_type);
 
   lexer = pdfium::MakeUnique<CXFA_FMLexer>(L"123 \t\xc\x9\xb 456");
   token = lexer->NextToken();
-  EXPECT_EQ(TOKnumber, token->m_type);
-  EXPECT_EQ(L"123", token->m_string);
+  EXPECT_EQ(TOKnumber, token.m_type);
+  EXPECT_EQ(L"123", token.m_string);
 
   token = lexer->NextToken();
-  EXPECT_EQ(TOKnumber, token->m_type);
-  EXPECT_EQ(L"456", token->m_string);
+  EXPECT_EQ(TOKnumber, token.m_type);
+  EXPECT_EQ(L"456", token.m_string);
 
   token = lexer->NextToken();
-  EXPECT_EQ(TOKeof, token->m_type);
+  EXPECT_EQ(TOKeof, token.m_type);
+  EXPECT_TRUE(lexer->IsComplete());
+}
+
+TEST(CXFA_FMLexerTest, NullData) {
+  auto lexer = pdfium::MakeUnique<CXFA_FMLexer>(
+      WideStringView(L"\x2d\x32\x00\x2d\x32", 5));
+  CXFA_FMToken token = lexer->NextToken();
+  EXPECT_EQ(TOKminus, token.m_type);
+
+  token = lexer->NextToken();
+  EXPECT_EQ(TOKnumber, token.m_type);
+  EXPECT_EQ(L"2", token.m_string);
+
+  token = lexer->NextToken();
+  EXPECT_EQ(TOKeof, token.m_type);
+  EXPECT_FALSE(lexer->IsComplete());
 }
diff --git a/xfa/fxfa/fm2js/cxfa_fmparser.cpp b/xfa/fxfa/fm2js/cxfa_fmparser.cpp
index 644fdf2..152b5a1 100644
--- a/xfa/fxfa/fm2js/cxfa_fmparser.cpp
+++ b/xfa/fxfa/fm2js/cxfa_fmparser.cpp
@@ -15,34 +15,42 @@
 
 namespace {
 
-const unsigned int kMaxAssignmentChainLength = 12;
-const unsigned int kMaxParseDepth = 1250;
+constexpr unsigned int kMaxParseDepth = 1250;
+constexpr unsigned int kMaxPostExpressions = 256;
+constexpr unsigned int kMaxExpressionListSize = 10000;
 
 }  // namespace
 
-CXFA_FMParser::CXFA_FMParser(const WideStringView& wsFormcalc)
-    : m_error(false), m_parse_depth(0), m_max_parse_depth(kMaxParseDepth) {
-  m_lexer = pdfium::MakeUnique<CXFA_FMLexer>(wsFormcalc);
+CXFA_FMParser::CXFA_FMParser(WideStringView wsFormcalc)
+    : m_lexer(pdfium::MakeUnique<CXFA_FMLexer>(wsFormcalc)),
+      m_error(false),
+      m_parse_depth(0),
+      m_max_parse_depth(kMaxParseDepth) {}
+
+CXFA_FMParser::~CXFA_FMParser() = default;
+
+std::unique_ptr<CXFA_FMAST> CXFA_FMParser::Parse() {
   m_token = m_lexer->NextToken();
-}
-
-CXFA_FMParser::~CXFA_FMParser() {}
-
-std::unique_ptr<CXFA_FMFunctionDefinition> CXFA_FMParser::Parse() {
-  auto expressions = ParseTopExpression();
   if (HasError())
     return nullptr;
 
-  std::vector<WideStringView> arguments;
-  return pdfium::MakeUnique<CXFA_FMFunctionDefinition>(
-      1, true, L"", std::move(arguments), std::move(expressions));
+  auto expressions = ParseExpressionList();
+  if (HasError())
+    return nullptr;
+
+  // We failed to parse all of the input so something has gone wrong.
+  if (!m_lexer->IsComplete())
+    return nullptr;
+
+  return pdfium::MakeUnique<CXFA_FMAST>(std::move(expressions));
 }
 
 bool CXFA_FMParser::NextToken() {
   if (HasError())
     return false;
+
   m_token = m_lexer->NextToken();
-  while (!HasError() && m_token->m_type == TOKreserver)
+  while (!HasError() && m_token.m_type == TOKreserver)
     m_token = m_lexer->NextToken();
   return !HasError();
 }
@@ -51,7 +59,7 @@
   if (HasError())
     return false;
 
-  if (m_token->m_type != op) {
+  if (m_token.m_type != op) {
     m_error = true;
     return false;
   }
@@ -63,103 +71,104 @@
 }
 
 std::vector<std::unique_ptr<CXFA_FMExpression>>
-CXFA_FMParser::ParseTopExpression() {
+CXFA_FMParser::ParseExpressionList() {
   AutoRestorer<unsigned long> restorer(&m_parse_depth);
   if (HasError() || !IncrementParseDepthAndCheck())
     return std::vector<std::unique_ptr<CXFA_FMExpression>>();
 
-  std::unique_ptr<CXFA_FMExpression> expr;
   std::vector<std::unique_ptr<CXFA_FMExpression>> expressions;
   while (!HasError()) {
-    if (m_token->m_type == TOKeof || m_token->m_type == TOKendfunc ||
-        m_token->m_type == TOKendif || m_token->m_type == TOKelseif ||
-        m_token->m_type == TOKelse || m_token->m_type == TOKreserver) {
-      return expressions;
-    }
-
-    expr = m_token->m_type == TOKfunc ? ParseFunction() : ParseExpression();
-    if (!expr) {
-      m_error = true;
+    if (m_token.m_type == TOKeof || m_token.m_type == TOKendfunc ||
+        m_token.m_type == TOKendif || m_token.m_type == TOKelseif ||
+        m_token.m_type == TOKelse || m_token.m_type == TOKendwhile ||
+        m_token.m_type == TOKendfor || m_token.m_type == TOKend ||
+        m_token.m_type == TOKendfunc || m_token.m_type == TOKreserver) {
       break;
     }
+
+    std::unique_ptr<CXFA_FMExpression> expr =
+        m_token.m_type == TOKfunc ? ParseFunction() : ParseExpression();
+    if (!expr) {
+      m_error = true;
+      return std::vector<std::unique_ptr<CXFA_FMExpression>>();
+    }
+
+    if (expressions.size() >= kMaxExpressionListSize) {
+      m_error = true;
+      return std::vector<std::unique_ptr<CXFA_FMExpression>>();
+    }
+
     expressions.push_back(std::move(expr));
   }
-  return std::vector<std::unique_ptr<CXFA_FMExpression>>();
+  return expressions;
 }
 
+// Func := 'func' Identifier '(' ParameterList ')' do ExpressionList 'endfunc'
+// ParamterList := (Not actually defined in the grammar) .....
+//                 (Identifier (',' Identifier)*)?
 std::unique_ptr<CXFA_FMExpression> CXFA_FMParser::ParseFunction() {
   AutoRestorer<unsigned long> restorer(&m_parse_depth);
   if (HasError() || !IncrementParseDepthAndCheck())
     return nullptr;
+  if (!CheckThenNext(TOKfunc))
+    return nullptr;
+  if (m_token.m_type != TOKidentifier)
+    return nullptr;
 
-  WideStringView ident;
-  std::vector<WideStringView> arguments;
-  std::vector<std::unique_ptr<CXFA_FMExpression>> expressions;
-  uint32_t line = m_token->m_line_num;
+  WideStringView ident = m_token.m_string;
   if (!NextToken())
     return nullptr;
-  if (m_token->m_type != TOKidentifier) {
-    m_error = true;
-    return nullptr;
-  } else {
-    ident = m_token->m_string;
-    if (!NextToken())
-      return nullptr;
-  }
   if (!CheckThenNext(TOKlparen))
     return nullptr;
-  if (m_token->m_type == TOKrparen) {
+
+  std::vector<WideStringView> arguments;
+  bool last_was_comma = false;
+  while (1) {
+    if (m_token.m_type == TOKrparen)
+      break;
+    if (m_token.m_type != TOKidentifier)
+      return nullptr;
+
+    last_was_comma = false;
+
+    arguments.push_back(m_token.m_string);
     if (!NextToken())
       return nullptr;
-  } else {
-    while (1) {
-      if (m_token->m_type != TOKidentifier) {
-        m_error = true;
-        return nullptr;
-      }
-      arguments.push_back(m_token->m_string);
-      if (!NextToken())
-        return nullptr;
-      if (m_token->m_type == TOKcomma) {
-        if (!NextToken())
-          return nullptr;
-        continue;
-      }
-      if (m_token->m_type == TOKrparen) {
-        if (!NextToken())
-          return nullptr;
-      } else {
-        if (!CheckThenNext(TOKrparen))
-          return nullptr;
-      }
-      break;
-    }
+    if (m_token.m_type != TOKcomma)
+      continue;
+
+    last_was_comma = true;
+    if (!NextToken())
+      return nullptr;
   }
+  if (last_was_comma || !CheckThenNext(TOKrparen))
+    return nullptr;
   if (!CheckThenNext(TOKdo))
     return nullptr;
-  if (m_token->m_type == TOKendfunc) {
-    if (!NextToken())
-      return nullptr;
-  } else {
-    expressions = ParseTopExpression();
-    if (!expressions.size() || !CheckThenNext(TOKendfunc))
-      return nullptr;
-  }
+
+  std::vector<std::unique_ptr<CXFA_FMExpression>> expressions;
+  if (m_token.m_type != TOKendfunc)
+    expressions = ParseExpressionList();
+
+  if (!CheckThenNext(TOKendfunc))
+    return nullptr;
 
   return pdfium::MakeUnique<CXFA_FMFunctionDefinition>(
-      line, false, ident, std::move(arguments), std::move(expressions));
+      ident, std::move(arguments), std::move(expressions));
 }
 
+// Expression := IfExpression | WhileExpression | ForExpression |
+//               ForEachExpression | AssignmentExpression |
+//               DeclarationExpression | SimpleExpression
 std::unique_ptr<CXFA_FMExpression> CXFA_FMParser::ParseExpression() {
   AutoRestorer<unsigned long> restorer(&m_parse_depth);
   if (HasError() || !IncrementParseDepthAndCheck())
     return nullptr;
 
   std::unique_ptr<CXFA_FMExpression> expr;
-  uint32_t line = m_token->m_line_num;
-  switch (m_token->m_type) {
+  switch (m_token.m_type) {
     case TOKvar:
-      expr = ParseVarExpression();
+      expr = ParseDeclarationExpression();
       break;
     case TOKnull:
     case TOKnumber:
@@ -187,104 +196,103 @@
       expr = ParseDoExpression();
       break;
     case TOKbreak:
-      expr = pdfium::MakeUnique<CXFA_FMBreakExpression>(line);
+      expr = pdfium::MakeUnique<CXFA_FMBreakExpression>();
       if (!NextToken())
         return nullptr;
       break;
     case TOKcontinue:
-      expr = pdfium::MakeUnique<CXFA_FMContinueExpression>(line);
+      expr = pdfium::MakeUnique<CXFA_FMContinueExpression>();
       if (!NextToken())
         return nullptr;
       break;
     default:
-      m_error = true;
       return nullptr;
   }
   return expr;
 }
 
-std::unique_ptr<CXFA_FMExpression> CXFA_FMParser::ParseVarExpression() {
+// Declaration := 'var' Variable | 'var' Variable '=' SimpleExpression |
+//           'Func' Identifier '(' ParameterList ')' do ExpressionList 'EndFunc'
+// TODO(dsinclair): We appear to be handling the 'func' case elsewhere.
+std::unique_ptr<CXFA_FMExpression> CXFA_FMParser::ParseDeclarationExpression() {
   AutoRestorer<unsigned long> restorer(&m_parse_depth);
   if (HasError() || !IncrementParseDepthAndCheck())
     return nullptr;
 
   WideStringView ident;
-  uint32_t line = m_token->m_line_num;
   if (!NextToken())
     return nullptr;
-  if (m_token->m_type != TOKidentifier) {
-    m_error = true;
+  if (m_token.m_type != TOKidentifier)
     return nullptr;
-  }
 
-  ident = m_token->m_string;
+  ident = m_token.m_string;
   if (!NextToken())
     return nullptr;
 
-  std::unique_ptr<CXFA_FMExpression> expr;
-  if (m_token->m_type == TOKassign) {
+  std::unique_ptr<CXFA_FMSimpleExpression> expr;
+  if (m_token.m_type == TOKassign) {
     if (!NextToken())
       return nullptr;
 
-    expr = ParseExpExpression();
+    expr = ParseSimpleExpression();
     if (!expr)
       return nullptr;
   }
 
-  return pdfium::MakeUnique<CXFA_FMVarExpression>(line, ident, std::move(expr));
+  return pdfium::MakeUnique<CXFA_FMVarExpression>(ident, std::move(expr));
 }
 
+// SimpleExpression := LogicalOrExpression
 std::unique_ptr<CXFA_FMSimpleExpression>
 CXFA_FMParser::ParseSimpleExpression() {
   if (HasError())
     return nullptr;
 
-  uint32_t line = m_token->m_line_num;
-  std::unique_ptr<CXFA_FMSimpleExpression> pExp1 = ParseLogicalOrExpression();
-  if (!pExp1)
-    return nullptr;
-  int level = 1;
-  while (m_token->m_type == TOKassign) {
-    if (!NextToken())
-      return nullptr;
-    std::unique_ptr<CXFA_FMSimpleExpression> pExp2 = ParseLogicalOrExpression();
-    if (!pExp2)
-      return nullptr;
-    if (level++ == kMaxAssignmentChainLength) {
-      m_error = true;
-      return nullptr;
-    }
-    pExp1 = pdfium::MakeUnique<CXFA_FMAssignExpression>(
-        line, TOKassign, std::move(pExp1), std::move(pExp2));
-  }
-  return pExp1;
+  return ParseLogicalOrExpression();
 }
 
+// Exp := SimpleExpression ( '=' SimpleExpression )?
 std::unique_ptr<CXFA_FMExpression> CXFA_FMParser::ParseExpExpression() {
   AutoRestorer<unsigned long> restorer(&m_parse_depth);
   if (HasError() || !IncrementParseDepthAndCheck())
     return nullptr;
 
-  uint32_t line = m_token->m_line_num;
   std::unique_ptr<CXFA_FMSimpleExpression> pExp1 = ParseSimpleExpression();
   if (!pExp1)
     return nullptr;
-  return pdfium::MakeUnique<CXFA_FMExpExpression>(line, std::move(pExp1));
+
+  if (m_token.m_type == TOKassign) {
+    if (!NextToken())
+      return nullptr;
+
+    std::unique_ptr<CXFA_FMSimpleExpression> pExp2 = ParseSimpleExpression();
+    if (!pExp2)
+      return nullptr;
+
+    pExp1 = pdfium::MakeUnique<CXFA_FMAssignExpression>(
+        TOKassign, std::move(pExp1), std::move(pExp2));
+  }
+  return pdfium::MakeUnique<CXFA_FMExpExpression>(std::move(pExp1));
 }
 
+// LogicalOr := LogicalAndExpression |
+//              LogicalOrExpression LogicalOrOperator LogicalAndExpression
 std::unique_ptr<CXFA_FMSimpleExpression>
 CXFA_FMParser::ParseLogicalOrExpression() {
   AutoRestorer<unsigned long> restorer(&m_parse_depth);
   if (HasError() || !IncrementParseDepthAndCheck())
     return nullptr;
 
-  uint32_t line = m_token->m_line_num;
   std::unique_ptr<CXFA_FMSimpleExpression> e1 = ParseLogicalAndExpression();
   if (!e1)
     return nullptr;
 
+  // TODO(dsinclair): Is this for() needed?
   for (;;) {
-    switch (m_token->m_type) {
+    if (!IncrementParseDepthAndCheck())
+      return nullptr;
+
+    switch (m_token.m_type) {
       case TOKor:
       case TOKksor: {
         if (!NextToken())
@@ -296,7 +304,7 @@
           return nullptr;
 
         e1 = pdfium::MakeUnique<CXFA_FMLogicalOrExpression>(
-            line, TOKor, std::move(e1), std::move(e2));
+            TOKor, std::move(e1), std::move(e2));
         continue;
       }
       default:
@@ -307,19 +315,24 @@
   return e1;
 }
 
+// LogicalAnd := EqualityExpression |
+//               LogicalAndExpression LogicalAndOperator EqualityExpression
 std::unique_ptr<CXFA_FMSimpleExpression>
 CXFA_FMParser::ParseLogicalAndExpression() {
   AutoRestorer<unsigned long> restorer(&m_parse_depth);
   if (HasError() || !IncrementParseDepthAndCheck())
     return nullptr;
 
-  uint32_t line = m_token->m_line_num;
   std::unique_ptr<CXFA_FMSimpleExpression> e1 = ParseEqualityExpression();
   if (!e1)
     return nullptr;
 
+  // TODO(dsinclair): Is this for() needed?
   for (;;) {
-    switch (m_token->m_type) {
+    if (!IncrementParseDepthAndCheck())
+      return nullptr;
+
+    switch (m_token.m_type) {
       case TOKand:
       case TOKksand: {
         if (!NextToken())
@@ -330,7 +343,7 @@
           return nullptr;
 
         e1 = pdfium::MakeUnique<CXFA_FMLogicalAndExpression>(
-            line, TOKand, std::move(e1), std::move(e2));
+            TOKand, std::move(e1), std::move(e2));
         continue;
       }
       default:
@@ -341,43 +354,52 @@
   return e1;
 }
 
+// Equality := RelationExpression |
+//             EqualityExpression EqulaityOperator RelationalExpression
 std::unique_ptr<CXFA_FMSimpleExpression>
 CXFA_FMParser::ParseEqualityExpression() {
   AutoRestorer<unsigned long> restorer(&m_parse_depth);
   if (HasError() || !IncrementParseDepthAndCheck())
     return nullptr;
 
-  uint32_t line = m_token->m_line_num;
   std::unique_ptr<CXFA_FMSimpleExpression> e1 = ParseRelationalExpression();
   if (!e1)
     return nullptr;
+
+  // TODO(dsinclair): Is this for() needed?
   for (;;) {
-    std::unique_ptr<CXFA_FMSimpleExpression> e2;
-    switch (m_token->m_type) {
+    if (!IncrementParseDepthAndCheck())
+      return nullptr;
+
+    switch (m_token.m_type) {
       case TOKeq:
-      case TOKkseq:
+      case TOKkseq: {
         if (!NextToken())
           return nullptr;
 
-        e2 = ParseRelationalExpression();
+        std::unique_ptr<CXFA_FMSimpleExpression> e2 =
+            ParseRelationalExpression();
         if (!e2)
           return nullptr;
 
-        e1 = pdfium::MakeUnique<CXFA_FMEqualityExpression>(
-            line, TOKeq, std::move(e1), std::move(e2));
+        e1 = pdfium::MakeUnique<CXFA_FMEqualExpression>(TOKeq, std::move(e1),
+                                                        std::move(e2));
         continue;
+      }
       case TOKne:
-      case TOKksne:
+      case TOKksne: {
         if (!NextToken())
           return nullptr;
 
-        e2 = ParseRelationalExpression();
+        std::unique_ptr<CXFA_FMSimpleExpression> e2 =
+            ParseRelationalExpression();
         if (!e2)
           return nullptr;
 
-        e1 = pdfium::MakeUnique<CXFA_FMEqualityExpression>(
-            line, TOKne, std::move(e1), std::move(e2));
+        e1 = pdfium::MakeUnique<CXFA_FMNotEqualExpression>(TOKne, std::move(e1),
+                                                           std::move(e2));
         continue;
+      }
       default:
         break;
     }
@@ -386,67 +408,72 @@
   return e1;
 }
 
+// Relational := AdditiveExpression |
+//               RelationalExpression RelationalOperator AdditiveExpression
 std::unique_ptr<CXFA_FMSimpleExpression>
 CXFA_FMParser::ParseRelationalExpression() {
   AutoRestorer<unsigned long> restorer(&m_parse_depth);
   if (HasError() || !IncrementParseDepthAndCheck())
     return nullptr;
 
-  uint32_t line = m_token->m_line_num;
-  std::unique_ptr<CXFA_FMSimpleExpression> e1 = ParseAddtiveExpression();
+  std::unique_ptr<CXFA_FMSimpleExpression> e1 = ParseAdditiveExpression();
   if (!e1)
     return nullptr;
 
+  // TODO(dsinclair): Is this for() needed?
   for (;;) {
+    if (!IncrementParseDepthAndCheck())
+      return nullptr;
+
     std::unique_ptr<CXFA_FMSimpleExpression> e2;
-    switch (m_token->m_type) {
+    switch (m_token.m_type) {
       case TOKlt:
       case TOKkslt:
         if (!NextToken())
           return nullptr;
 
-        e2 = ParseAddtiveExpression();
+        e2 = ParseAdditiveExpression();
         if (!e2)
           return nullptr;
 
-        e1 = pdfium::MakeUnique<CXFA_FMRelationalExpression>(
-            line, TOKlt, std::move(e1), std::move(e2));
+        e1 = pdfium::MakeUnique<CXFA_FMLtExpression>(TOKlt, std::move(e1),
+                                                     std::move(e2));
         continue;
       case TOKgt:
       case TOKksgt:
         if (!NextToken())
           return nullptr;
 
-        e2 = ParseAddtiveExpression();
+        e2 = ParseAdditiveExpression();
         if (!e2)
           return nullptr;
 
-        e1 = pdfium::MakeUnique<CXFA_FMRelationalExpression>(
-            line, TOKgt, std::move(e1), std::move(e2));
+        e1 = pdfium::MakeUnique<CXFA_FMGtExpression>(TOKgt, std::move(e1),
+                                                     std::move(e2));
         continue;
       case TOKle:
       case TOKksle:
         if (!NextToken())
           return nullptr;
 
-        e2 = ParseAddtiveExpression();
+        e2 = ParseAdditiveExpression();
         if (!e2)
           return nullptr;
 
-        e1 = pdfium::MakeUnique<CXFA_FMRelationalExpression>(
-            line, TOKle, std::move(e1), std::move(e2));
+        e1 = pdfium::MakeUnique<CXFA_FMLeExpression>(TOKle, std::move(e1),
+                                                     std::move(e2));
         continue;
       case TOKge:
       case TOKksge:
         if (!NextToken())
           return nullptr;
 
-        e2 = ParseAddtiveExpression();
+        e2 = ParseAdditiveExpression();
         if (!e2)
           return nullptr;
 
-        e1 = pdfium::MakeUnique<CXFA_FMRelationalExpression>(
-            line, TOKge, std::move(e1), std::move(e2));
+        e1 = pdfium::MakeUnique<CXFA_FMGeExpression>(TOKge, std::move(e1),
+                                                     std::move(e2));
         continue;
       default:
         break;
@@ -456,20 +483,25 @@
   return e1;
 }
 
+// Additive := MultiplicativeExpression |
+//             AdditiveExpression AdditiveOperator MultiplicativeExpression
 std::unique_ptr<CXFA_FMSimpleExpression>
-CXFA_FMParser::ParseAddtiveExpression() {
+CXFA_FMParser::ParseAdditiveExpression() {
   AutoRestorer<unsigned long> restorer(&m_parse_depth);
   if (HasError() || !IncrementParseDepthAndCheck())
     return nullptr;
 
-  uint32_t line = m_token->m_line_num;
   std::unique_ptr<CXFA_FMSimpleExpression> e1 = ParseMultiplicativeExpression();
   if (!e1)
     return nullptr;
 
+  // TODO(dsinclair): Is this for() needed?
   for (;;) {
+    if (!IncrementParseDepthAndCheck())
+      return nullptr;
+
     std::unique_ptr<CXFA_FMSimpleExpression> e2;
-    switch (m_token->m_type) {
+    switch (m_token.m_type) {
       case TOKplus:
         if (!NextToken())
           return nullptr;
@@ -478,8 +510,8 @@
         if (!e2)
           return nullptr;
 
-        e1 = pdfium::MakeUnique<CXFA_FMAdditiveExpression>(
-            line, TOKplus, std::move(e1), std::move(e2));
+        e1 = pdfium::MakeUnique<CXFA_FMPlusExpression>(TOKplus, std::move(e1),
+                                                       std::move(e2));
         continue;
       case TOKminus:
         if (!NextToken())
@@ -489,8 +521,8 @@
         if (!e2)
           return nullptr;
 
-        e1 = pdfium::MakeUnique<CXFA_FMAdditiveExpression>(
-            line, TOKminus, std::move(e1), std::move(e2));
+        e1 = pdfium::MakeUnique<CXFA_FMMinusExpression>(TOKminus, std::move(e1),
+                                                        std::move(e2));
         continue;
       default:
         break;
@@ -500,20 +532,25 @@
   return e1;
 }
 
+// Multiplicative := UnaryExpression |
+//                 MultiplicateExpression MultiplicativeOperator UnaryExpression
 std::unique_ptr<CXFA_FMSimpleExpression>
 CXFA_FMParser::ParseMultiplicativeExpression() {
   AutoRestorer<unsigned long> restorer(&m_parse_depth);
   if (HasError() || !IncrementParseDepthAndCheck())
     return nullptr;
 
-  uint32_t line = m_token->m_line_num;
   std::unique_ptr<CXFA_FMSimpleExpression> e1 = ParseUnaryExpression();
   if (!e1)
     return nullptr;
 
+  // TODO(dsinclair): Is this for() needed?
   for (;;) {
+    if (!IncrementParseDepthAndCheck())
+      return nullptr;
+
     std::unique_ptr<CXFA_FMSimpleExpression> e2;
-    switch (m_token->m_type) {
+    switch (m_token.m_type) {
       case TOKmul:
         if (!NextToken())
           return nullptr;
@@ -522,8 +559,8 @@
         if (!e2)
           return nullptr;
 
-        e1 = pdfium::MakeUnique<CXFA_FMMultiplicativeExpression>(
-            line, TOKmul, std::move(e1), std::move(e2));
+        e1 = pdfium::MakeUnique<CXFA_FMMulExpression>(TOKmul, std::move(e1),
+                                                      std::move(e2));
         continue;
       case TOKdiv:
         if (!NextToken())
@@ -533,8 +570,8 @@
         if (!e2)
           return nullptr;
 
-        e1 = pdfium::MakeUnique<CXFA_FMMultiplicativeExpression>(
-            line, TOKdiv, std::move(e1), std::move(e2));
+        e1 = pdfium::MakeUnique<CXFA_FMDivExpression>(TOKdiv, std::move(e1),
+                                                      std::move(e2));
         continue;
       default:
         break;
@@ -544,14 +581,14 @@
   return e1;
 }
 
+// Unary := PrimaryExpression | UnaryOperator UnaryExpression
 std::unique_ptr<CXFA_FMSimpleExpression> CXFA_FMParser::ParseUnaryExpression() {
   AutoRestorer<unsigned long> restorer(&m_parse_depth);
   if (HasError() || !IncrementParseDepthAndCheck())
     return nullptr;
 
   std::unique_ptr<CXFA_FMSimpleExpression> expr;
-  uint32_t line = m_token->m_line_num;
-  switch (m_token->m_type) {
+  switch (m_token.m_type) {
     case TOKplus:
       if (!NextToken())
         return nullptr;
@@ -560,7 +597,7 @@
       if (!expr)
         return nullptr;
 
-      expr = pdfium::MakeUnique<CXFA_FMPosExpression>(line, std::move(expr));
+      expr = pdfium::MakeUnique<CXFA_FMPosExpression>(std::move(expr));
       break;
     case TOKminus:
       if (!NextToken())
@@ -570,7 +607,7 @@
       if (!expr)
         return nullptr;
 
-      expr = pdfium::MakeUnique<CXFA_FMNegExpression>(line, std::move(expr));
+      expr = pdfium::MakeUnique<CXFA_FMNegExpression>(std::move(expr));
       break;
     case TOKksnot:
       if (!NextToken())
@@ -580,127 +617,101 @@
       if (!expr)
         return nullptr;
 
-      expr = pdfium::MakeUnique<CXFA_FMNotExpression>(line, std::move(expr));
+      expr = pdfium::MakeUnique<CXFA_FMNotExpression>(std::move(expr));
       break;
     default:
-      expr = ParsePrimaryExpression();
-      if (!expr)
-        return nullptr;
-      break;
+      return ParsePrimaryExpression();
   }
   return expr;
 }
 
+// Primary := Literal | FunctionCall | Accessor ('.*' )? |
+//           '(' SimpleExpression ')'
 std::unique_ptr<CXFA_FMSimpleExpression>
 CXFA_FMParser::ParsePrimaryExpression() {
   AutoRestorer<unsigned long> restorer(&m_parse_depth);
   if (HasError() || !IncrementParseDepthAndCheck())
     return nullptr;
 
-  std::unique_ptr<CXFA_FMSimpleExpression> expr;
-  uint32_t line = m_token->m_line_num;
-  switch (m_token->m_type) {
-    case TOKnumber:
-      expr =
-          pdfium::MakeUnique<CXFA_FMNumberExpression>(line, m_token->m_string);
-      if (!NextToken())
-        return nullptr;
-      break;
-    case TOKstring:
-      expr =
-          pdfium::MakeUnique<CXFA_FMStringExpression>(line, m_token->m_string);
-      if (!NextToken())
-        return nullptr;
-      break;
+  std::unique_ptr<CXFA_FMSimpleExpression> expr = ParseLiteral();
+  if (expr)
+    return NextToken() ? std::move(expr) : nullptr;
+
+  switch (m_token.m_type) {
     case TOKidentifier: {
-      WideStringView wsIdentifier(m_token->m_string);
+      WideStringView wsIdentifier(m_token.m_string);
       if (!NextToken())
         return nullptr;
-      if (m_token->m_type == TOKlbracket) {
+      if (m_token.m_type == TOKlbracket) {
         std::unique_ptr<CXFA_FMSimpleExpression> s = ParseIndexExpression();
         if (!s)
           return nullptr;
 
         expr = pdfium::MakeUnique<CXFA_FMDotAccessorExpression>(
-            line, nullptr, TOKdot, wsIdentifier, std::move(s));
+            nullptr, TOKdot, wsIdentifier, std::move(s));
         if (!expr)
           return nullptr;
         if (!NextToken())
           return nullptr;
       } else {
-        expr =
-            pdfium::MakeUnique<CXFA_FMIdentifierExpression>(line, wsIdentifier);
+        expr = pdfium::MakeUnique<CXFA_FMIdentifierExpression>(wsIdentifier);
       }
       break;
     }
-    case TOKif:
-      expr = pdfium::MakeUnique<CXFA_FMIdentifierExpression>(line,
-                                                             m_token->m_string);
-      if (!expr || !NextToken())
-        return nullptr;
-      break;
-    case TOKnull:
-      expr = pdfium::MakeUnique<CXFA_FMNullExpression>(line);
-      if (!expr || !NextToken())
-        return nullptr;
-      break;
     case TOKlparen:
       expr = ParseParenExpression();
       if (!expr)
         return nullptr;
       break;
     default:
-      m_error = true;
       return nullptr;
   }
-  expr = ParsePostExpression(std::move(expr));
-  if (!expr)
-    return nullptr;
-  return expr;
+  return ParsePostExpression(std::move(expr));
 }
 
+// Literal := String | Number | Null
+std::unique_ptr<CXFA_FMSimpleExpression> CXFA_FMParser::ParseLiteral() {
+  switch (m_token.m_type) {
+    case TOKnumber:
+      return pdfium::MakeUnique<CXFA_FMNumberExpression>(m_token.m_string);
+    case TOKstring:
+      return pdfium::MakeUnique<CXFA_FMStringExpression>(m_token.m_string);
+    case TOKnull:
+      return pdfium::MakeUnique<CXFA_FMNullExpression>();
+    default:
+      return nullptr;
+  }
+}
+
+// TODO(dsinclair): Make this match up to the grammar
+// I believe this is parsing the accessor ( '.' | '..' | '.#' )
 std::unique_ptr<CXFA_FMSimpleExpression> CXFA_FMParser::ParsePostExpression(
     std::unique_ptr<CXFA_FMSimpleExpression> expr) {
   AutoRestorer<unsigned long> restorer(&m_parse_depth);
   if (HasError() || !IncrementParseDepthAndCheck())
     return nullptr;
 
-  if (HasError())
-    return nullptr;
-
-  uint32_t line = m_token->m_line_num;
+  size_t expr_count = 0;
   while (1) {
-    switch (m_token->m_type) {
-      case TOKlparen: {
-        if (!NextToken())
-          return nullptr;
-        std::vector<std::unique_ptr<CXFA_FMSimpleExpression>> expressions;
-        if (m_token->m_type != TOKrparen) {
-          while (m_token->m_type != TOKrparen) {
-            std::unique_ptr<CXFA_FMSimpleExpression> simple_expr =
-                ParseSimpleExpression();
-            if (!simple_expr)
-              return nullptr;
+    ++expr_count;
+    // Limit the number of expressions allowed in the post expression statement.
+    // If we don't do this then its possible to generate a stack overflow
+    // by having a very large number of things like .. expressions.
+    if (expr_count > kMaxPostExpressions)
+      return nullptr;
 
-            expressions.push_back(std::move(simple_expr));
-            if (m_token->m_type == TOKcomma) {
-              if (!NextToken())
-                return nullptr;
-            } else if (m_token->m_type == TOKeof ||
-                       m_token->m_type == TOKreserver) {
-              break;
-            }
-          }
-          if (m_token->m_type != TOKrparen) {
-            m_error = true;
-            return nullptr;
-          }
-        }
+    switch (m_token.m_type) {
+      case TOKlparen: {
+        std::unique_ptr<std::vector<std::unique_ptr<CXFA_FMSimpleExpression>>>
+            expressions = ParseArgumentList();
+        if (!expressions)
+          return nullptr;
+
         expr = pdfium::MakeUnique<CXFA_FMCallExpression>(
-            line, std::move(expr), std::move(expressions), false);
+            std::move(expr), std::move(*expressions), false);
         if (!NextToken())
           return nullptr;
-        if (m_token->m_type != TOKlbracket)
+        if (m_token.m_type != TOKlbracket)
           continue;
 
         std::unique_ptr<CXFA_FMSimpleExpression> s = ParseIndexExpression();
@@ -708,57 +719,33 @@
           return nullptr;
 
         expr = pdfium::MakeUnique<CXFA_FMDotAccessorExpression>(
-            line, std::move(expr), TOKcall, L"", std::move(s));
+            std::move(expr), TOKcall, WideStringView(), std::move(s));
         break;
       }
       case TOKdot: {
         if (!NextToken())
           return nullptr;
-        if (m_token->m_type != TOKidentifier) {
-          m_error = true;
+        if (m_token.m_type != TOKidentifier)
           return nullptr;
-        }
-        WideStringView tempStr = m_token->m_string;
-        uint32_t tempLine = m_token->m_line_num;
+
+        WideStringView tempStr = m_token.m_string;
         if (!NextToken())
           return nullptr;
-        if (m_token->m_type == TOKlparen) {
-          std::unique_ptr<CXFA_FMSimpleExpression> pExpCall;
-          if (!NextToken())
+        if (m_token.m_type == TOKlparen) {
+          std::unique_ptr<std::vector<std::unique_ptr<CXFA_FMSimpleExpression>>>
+              expressions = ParseArgumentList();
+          if (!expressions)
             return nullptr;
 
-          std::vector<std::unique_ptr<CXFA_FMSimpleExpression>> expressions;
-          if (m_token->m_type != TOKrparen) {
-            while (m_token->m_type != TOKrparen) {
-              std::unique_ptr<CXFA_FMSimpleExpression> exp =
-                  ParseSimpleExpression();
-              if (!exp)
-                return nullptr;
-
-              expressions.push_back(std::move(exp));
-              if (m_token->m_type == TOKcomma) {
-                if (!NextToken())
-                  return nullptr;
-              } else if (m_token->m_type == TOKeof ||
-                         m_token->m_type == TOKreserver) {
-                break;
-              }
-            }
-            if (m_token->m_type != TOKrparen) {
-              m_error = true;
-              return nullptr;
-            }
-          }
-          std::unique_ptr<CXFA_FMSimpleExpression> pIdentifier =
-              pdfium::MakeUnique<CXFA_FMIdentifierExpression>(tempLine,
-                                                              tempStr);
-          pExpCall = pdfium::MakeUnique<CXFA_FMCallExpression>(
-              line, std::move(pIdentifier), std::move(expressions), true);
+          auto pIdentifier =
+              pdfium::MakeUnique<CXFA_FMIdentifierExpression>(tempStr);
+          auto pExpCall = pdfium::MakeUnique<CXFA_FMCallExpression>(
+              std::move(pIdentifier), std::move(*expressions), true);
           expr = pdfium::MakeUnique<CXFA_FMMethodCallExpression>(
-              line, std::move(expr), std::move(pExpCall));
+              std::move(expr), std::move(pExpCall));
           if (!NextToken())
             return nullptr;
-          if (m_token->m_type != TOKlbracket)
+          if (m_token.m_type != TOKlbracket)
             continue;
 
           std::unique_ptr<CXFA_FMSimpleExpression> s = ParseIndexExpression();
@@ -766,83 +753,83 @@
             return nullptr;
 
           expr = pdfium::MakeUnique<CXFA_FMDotAccessorExpression>(
-              line, std::move(expr), TOKcall, L"", std::move(s));
-        } else if (m_token->m_type == TOKlbracket) {
+              std::move(expr), TOKcall, WideStringView(), std::move(s));
+        } else if (m_token.m_type == TOKlbracket) {
           std::unique_ptr<CXFA_FMSimpleExpression> s = ParseIndexExpression();
           if (!s)
             return nullptr;
 
           expr = pdfium::MakeUnique<CXFA_FMDotAccessorExpression>(
-              tempLine, std::move(expr), TOKdot, tempStr, std::move(s));
+              std::move(expr), TOKdot, tempStr, std::move(s));
         } else {
           std::unique_ptr<CXFA_FMSimpleExpression> s =
-              pdfium::MakeUnique<CXFA_FMIndexExpression>(
-                  tempLine, ACCESSOR_NO_INDEX, nullptr, false);
+              pdfium::MakeUnique<CXFA_FMIndexExpression>(ACCESSOR_NO_INDEX,
+                                                         nullptr, false);
           expr = pdfium::MakeUnique<CXFA_FMDotAccessorExpression>(
-              line, std::move(expr), TOKdot, tempStr, std::move(s));
+              std::move(expr), TOKdot, tempStr, std::move(s));
           continue;
         }
-      } break;
+        break;
+      }
       case TOKdotdot: {
         if (!NextToken())
           return nullptr;
-        if (m_token->m_type != TOKidentifier) {
-          m_error = true;
+        if (m_token.m_type != TOKidentifier)
           return nullptr;
-        }
-        WideStringView tempStr = m_token->m_string;
-        uint32_t tempLine = m_token->m_line_num;
+
+        WideStringView tempStr = m_token.m_string;
         if (!NextToken())
           return nullptr;
-        if (m_token->m_type == TOKlbracket) {
+        if (m_token.m_type == TOKlbracket) {
           std::unique_ptr<CXFA_FMSimpleExpression> s = ParseIndexExpression();
           if (!s)
             return nullptr;
 
           expr = pdfium::MakeUnique<CXFA_FMDotDotAccessorExpression>(
-              tempLine, std::move(expr), TOKdotdot, tempStr, std::move(s));
+              std::move(expr), TOKdotdot, tempStr, std::move(s));
         } else {
           std::unique_ptr<CXFA_FMSimpleExpression> s =
-              pdfium::MakeUnique<CXFA_FMIndexExpression>(
-                  tempLine, ACCESSOR_NO_INDEX, nullptr, false);
+              pdfium::MakeUnique<CXFA_FMIndexExpression>(ACCESSOR_NO_INDEX,
+                                                         nullptr, false);
           expr = pdfium::MakeUnique<CXFA_FMDotDotAccessorExpression>(
-              line, std::move(expr), TOKdotdot, tempStr, std::move(s));
+              std::move(expr), TOKdotdot, tempStr, std::move(s));
           continue;
         }
-      } break;
+        break;
+      }
       case TOKdotscream: {
         if (!NextToken())
           return nullptr;
-        if (m_token->m_type != TOKidentifier) {
-          m_error = true;
+        if (m_token.m_type != TOKidentifier)
           return nullptr;
-        }
-        WideStringView tempStr = m_token->m_string;
-        uint32_t tempLine = m_token->m_line_num;
+
+        WideStringView tempStr = m_token.m_string;
         if (!NextToken())
           return nullptr;
-        if (m_token->m_type != TOKlbracket) {
+
+        if (m_token.m_type != TOKlbracket) {
           std::unique_ptr<CXFA_FMSimpleExpression> s =
-              pdfium::MakeUnique<CXFA_FMIndexExpression>(
-                  tempLine, ACCESSOR_NO_INDEX, nullptr, false);
+              pdfium::MakeUnique<CXFA_FMIndexExpression>(ACCESSOR_NO_INDEX,
+                                                         nullptr, false);
           expr = pdfium::MakeUnique<CXFA_FMDotAccessorExpression>(
-              line, std::move(expr), TOKdotscream, tempStr, std::move(s));
+              std::move(expr), TOKdotscream, tempStr, std::move(s));
           continue;
         }
+
         std::unique_ptr<CXFA_FMSimpleExpression> s = ParseIndexExpression();
         if (!s)
           return nullptr;
 
         expr = pdfium::MakeUnique<CXFA_FMDotAccessorExpression>(
-            tempLine, std::move(expr), TOKdotscream, tempStr, std::move(s));
+            std::move(expr), TOKdotscream, tempStr, std::move(s));
         break;
       }
       case TOKdotstar: {
         std::unique_ptr<CXFA_FMSimpleExpression> s =
-            pdfium::MakeUnique<CXFA_FMIndexExpression>(line, ACCESSOR_NO_INDEX,
+            pdfium::MakeUnique<CXFA_FMIndexExpression>(ACCESSOR_NO_INDEX,
                                                        nullptr, false);
         expr = pdfium::MakeUnique<CXFA_FMDotAccessorExpression>(
-            line, std::move(expr), TOKdotstar, L"*", std::move(s));
+            std::move(expr), TOKdotstar, L"*", std::move(s));
         break;
       }
       default:
@@ -854,49 +841,79 @@
   return expr;
 }
 
+// Argument lists are zero or more comma seperated simple expressions found
+// between '(' and ')'
+std::unique_ptr<std::vector<std::unique_ptr<CXFA_FMSimpleExpression>>>
+CXFA_FMParser::ParseArgumentList() {
+  if (m_token.m_type != TOKlparen || !NextToken())
+    return nullptr;
+
+  auto expressions = pdfium::MakeUnique<
+      std::vector<std::unique_ptr<CXFA_FMSimpleExpression>>>();
+  bool first_arg = true;
+  while (m_token.m_type != TOKrparen) {
+    if (first_arg) {
+      first_arg = false;
+    } else {
+      if (m_token.m_type != TOKcomma || !NextToken())
+        return nullptr;
+    }
+
+    std::unique_ptr<CXFA_FMSimpleExpression> exp = ParseSimpleExpression();
+    if (!exp)
+      return nullptr;
+
+    expressions->push_back(std::move(exp));
+    if (expressions->size() > kMaxPostExpressions)
+      return nullptr;
+  }
+
+  return expressions;
+}
+
+// Index := '[' ('*' | '+' SimpleExpression | '-' SimpleExpression) ']'
 std::unique_ptr<CXFA_FMSimpleExpression> CXFA_FMParser::ParseIndexExpression() {
   AutoRestorer<unsigned long> restorer(&m_parse_depth);
   if (HasError() || !IncrementParseDepthAndCheck())
     return nullptr;
-
-  uint32_t line = m_token->m_line_num;
-  if (!NextToken())
+  if (!CheckThenNext(TOKlbracket))
     return nullptr;
 
-  std::unique_ptr<CXFA_FMSimpleExpression> s;
-  XFA_FM_AccessorIndex accessorIndex = ACCESSOR_NO_RELATIVEINDEX;
-  std::unique_ptr<CXFA_FMSimpleExpression> pExp;
-  if (m_token->m_type == TOKmul) {
-    pExp = pdfium::MakeUnique<CXFA_FMIndexExpression>(line, accessorIndex,
-                                                      std::move(s), true);
+  if (m_token.m_type == TOKmul) {
+    auto pExp = pdfium::MakeUnique<CXFA_FMIndexExpression>(
+        ACCESSOR_NO_RELATIVEINDEX, nullptr, true);
     if (!pExp || !NextToken())
       return nullptr;
-    if (m_token->m_type != TOKrbracket) {
-      m_error = true;
+
+    // TODO(dsinclair): This should CheckThenNext(TOKrbracket) but need to clean
+    // up the callsites.
+    if (m_token.m_type != TOKrbracket)
       return nullptr;
-    }
     return pExp;
   }
-  if (m_token->m_type == TOKplus) {
+
+  XFA_FM_AccessorIndex accessorIndex = ACCESSOR_NO_RELATIVEINDEX;
+  if (m_token.m_type == TOKplus) {
     accessorIndex = ACCESSOR_POSITIVE_INDEX;
     if (!NextToken())
       return nullptr;
-  } else if (m_token->m_type == TOKminus) {
+  } else if (m_token.m_type == TOKminus) {
     accessorIndex = ACCESSOR_NEGATIVE_INDEX;
     if (!NextToken())
       return nullptr;
   }
-  s = ParseSimpleExpression();
+
+  std::unique_ptr<CXFA_FMSimpleExpression> s = ParseSimpleExpression();
   if (!s)
     return nullptr;
-  if (m_token->m_type != TOKrbracket) {
-    m_error = true;
+  if (m_token.m_type != TOKrbracket)
     return nullptr;
-  }
-  return pdfium::MakeUnique<CXFA_FMIndexExpression>(line, accessorIndex,
-                                                    std::move(s), false);
+
+  return pdfium::MakeUnique<CXFA_FMIndexExpression>(accessorIndex, std::move(s),
+                                                    false);
 }
 
+// Paren := '(' SimpleExpression ')'
 std::unique_ptr<CXFA_FMSimpleExpression> CXFA_FMParser::ParseParenExpression() {
   AutoRestorer<unsigned long> restorer(&m_parse_depth);
   if (HasError() || !IncrementParseDepthAndCheck())
@@ -904,214 +921,111 @@
 
   if (!CheckThenNext(TOKlparen))
     return nullptr;
-
-  if (m_token->m_type == TOKrparen) {
-    m_error = true;
+  if (m_token.m_type == TOKrparen)
     return nullptr;
-  }
 
-  uint32_t line = m_token->m_line_num;
-  std::unique_ptr<CXFA_FMSimpleExpression> pExp1 = ParseLogicalOrExpression();
+  std::unique_ptr<CXFA_FMSimpleExpression> pExp1 = ParseSimpleExpression();
   if (!pExp1)
     return nullptr;
 
-  int level = 1;
-  while (m_token->m_type == TOKassign) {
-    if (!NextToken())
-      return nullptr;
-
-    std::unique_ptr<CXFA_FMSimpleExpression> pExp2 = ParseLogicalOrExpression();
-    if (!pExp2)
-      return nullptr;
-    if (level++ == kMaxAssignmentChainLength) {
-      m_error = true;
-      return nullptr;
-    }
-
-    pExp1 = pdfium::MakeUnique<CXFA_FMAssignExpression>(
-        line, TOKassign, std::move(pExp1), std::move(pExp2));
-  }
   if (!CheckThenNext(TOKrparen))
     return nullptr;
   return pExp1;
 }
 
-std::unique_ptr<CXFA_FMExpression> CXFA_FMParser::ParseBlockExpression() {
-  AutoRestorer<unsigned long> restorer(&m_parse_depth);
-  if (HasError() || !IncrementParseDepthAndCheck())
-    return nullptr;
-
-  if (HasError())
-    return nullptr;
-
-  uint32_t line = m_token->m_line_num;
-  std::vector<std::unique_ptr<CXFA_FMExpression>> expressions;
-  while (1) {
-    std::unique_ptr<CXFA_FMExpression> expr;
-    switch (m_token->m_type) {
-      case TOKeof:
-      case TOKendif:
-      case TOKelseif:
-      case TOKelse:
-      case TOKendwhile:
-      case TOKendfor:
-      case TOKend:
-      case TOKendfunc:
-      case TOKreserver:
-        break;
-      case TOKfunc:
-        expr = ParseFunction();
-        if (!expr)
-          return nullptr;
-
-        expressions.push_back(std::move(expr));
-        continue;
-      default:
-        expr = ParseExpression();
-        if (!expr)
-          return nullptr;
-
-        expressions.push_back(std::move(expr));
-        continue;
-    }
-    break;
-  }
-  return pdfium::MakeUnique<CXFA_FMBlockExpression>(line,
-                                                    std::move(expressions));
-}
-
+// If := 'if' '(' SimpleExpression ')' 'then' ExpressionList
+//       ('elseif' '(' SimpleExpression ')' 'then' ExpressionList)*
+//       ('else' ExpressionList)?
+//       'endif'
 std::unique_ptr<CXFA_FMExpression> CXFA_FMParser::ParseIfExpression() {
   AutoRestorer<unsigned long> restorer(&m_parse_depth);
   if (HasError() || !IncrementParseDepthAndCheck())
     return nullptr;
 
-  uint32_t line = m_token->m_line_num;
-  const wchar_t* pStartPos = m_lexer->GetPos();
-  if (!NextToken() || !CheckThenNext(TOKlparen))
+  if (!CheckThenNext(TOKif))
     return nullptr;
 
-  std::unique_ptr<CXFA_FMSimpleExpression> pExpression;
-  while (m_token->m_type != TOKrparen) {
-    pExpression = ParseSimpleExpression();
-    if (!pExpression)
-      return nullptr;
-    if (m_token->m_type != TOKcomma)
-      break;
-    if (!NextToken())
-      return nullptr;
-  }
-  if (!CheckThenNext(TOKrparen))
+  std::unique_ptr<CXFA_FMSimpleExpression> pCondition = ParseParenExpression();
+  if (!pCondition)
     return nullptr;
-  if (m_token->m_type != TOKthen) {
-    m_lexer->SetCurrentLine(line);
-    auto pNewToken = pdfium::MakeUnique<CXFA_FMToken>(line);
-    m_token = std::move(pNewToken);
-    m_token->m_type = TOKidentifier;
-    m_token->m_string = L"if";
-    m_lexer->SetPos(pStartPos);
-    return ParseExpExpression();
-  }
   if (!CheckThenNext(TOKthen))
     return nullptr;
 
-  std::unique_ptr<CXFA_FMExpression> pIfExpression = ParseBlockExpression();
-  if (!pIfExpression)
-    return nullptr;
+  auto pIfExpressions =
+      pdfium::MakeUnique<CXFA_FMBlockExpression>(ParseExpressionList());
+
+  std::vector<std::unique_ptr<CXFA_FMIfExpression>> pElseIfExpressions;
+  while (m_token.m_type == TOKelseif) {
+    if (!NextToken())
+      return nullptr;
+
+    auto elseIfCondition = ParseParenExpression();
+    if (!elseIfCondition)
+      return nullptr;
+    if (!CheckThenNext(TOKthen))
+      return nullptr;
+
+    auto elseIfExprs = ParseExpressionList();
+    pElseIfExpressions.push_back(pdfium::MakeUnique<CXFA_FMIfExpression>(
+        std::move(elseIfCondition),
+        pdfium::MakeUnique<CXFA_FMBlockExpression>(std::move(elseIfExprs)),
+        std::vector<std::unique_ptr<CXFA_FMIfExpression>>(), nullptr));
+  }
 
   std::unique_ptr<CXFA_FMExpression> pElseExpression;
-  switch (m_token->m_type) {
-    case TOKeof:
-    case TOKendif:
-      if (!CheckThenNext(TOKendif))
-        return nullptr;
-      break;
-    case TOKif:
-      pElseExpression = ParseIfExpression();
-      if (!pElseExpression || !CheckThenNext(TOKendif))
-        return nullptr;
-      break;
-    case TOKelseif:
-      pElseExpression = ParseIfExpression();
-      if (!pElseExpression)
-        return nullptr;
-      break;
-    case TOKelse:
-      if (!NextToken())
-        return nullptr;
-      pElseExpression = ParseBlockExpression();
-      if (!pElseExpression || !CheckThenNext(TOKendif))
-        return nullptr;
-      break;
-    default:
-      m_error = true;
+  if (m_token.m_type == TOKelse) {
+    if (!NextToken())
       return nullptr;
+
+    pElseExpression =
+        pdfium::MakeUnique<CXFA_FMBlockExpression>(ParseExpressionList());
   }
-  return pdfium::MakeUnique<CXFA_FMIfExpression>(line, std::move(pExpression),
-                                                 std::move(pIfExpression),
-                                                 std::move(pElseExpression));
+  if (!CheckThenNext(TOKendif))
+    return nullptr;
+
+  return pdfium::MakeUnique<CXFA_FMIfExpression>(
+      std::move(pCondition), std::move(pIfExpressions),
+      std::move(pElseIfExpressions), std::move(pElseExpression));
 }
 
+// While := 'while' '(' SimpleExpression ')' 'do' ExpressionList 'endwhile'
 std::unique_ptr<CXFA_FMExpression> CXFA_FMParser::ParseWhileExpression() {
   AutoRestorer<unsigned long> restorer(&m_parse_depth);
   if (HasError() || !IncrementParseDepthAndCheck())
     return nullptr;
-
-  uint32_t line = m_token->m_line_num;
-  if (!NextToken())
+  if (!CheckThenNext(TOKwhile))
     return nullptr;
 
   std::unique_ptr<CXFA_FMSimpleExpression> pCondition = ParseParenExpression();
   if (!pCondition || !CheckThenNext(TOKdo))
     return nullptr;
 
-  std::unique_ptr<CXFA_FMExpression> pExpression = ParseBlockExpression();
-  if (!pExpression || !CheckThenNext(TOKendwhile))
+  auto exprs = ParseExpressionList();
+  if (!CheckThenNext(TOKendwhile))
     return nullptr;
-  return pdfium::MakeUnique<CXFA_FMWhileExpression>(line, std::move(pCondition),
-                                                    std::move(pExpression));
+
+  return pdfium::MakeUnique<CXFA_FMWhileExpression>(
+      std::move(pCondition),
+      pdfium::MakeUnique<CXFA_FMBlockExpression>(std::move(exprs)));
 }
 
-std::unique_ptr<CXFA_FMSimpleExpression>
-CXFA_FMParser::ParseSubassignmentInForExpression() {
-  AutoRestorer<unsigned long> restorer(&m_parse_depth);
-  if (HasError() || !IncrementParseDepthAndCheck())
-    return nullptr;
-
-  if (HasError())
-    return nullptr;
-
-  if (m_token->m_type != TOKidentifier) {
-    m_error = true;
-    return nullptr;
-  }
-  std::unique_ptr<CXFA_FMSimpleExpression> expr = ParseSimpleExpression();
-  if (!expr)
-    return nullptr;
-  return expr;
-}
-
+// For := 'for' Assignment 'upto' Accessor ('step' SimpleExpression)?
+//            'do' ExpressionList 'endfor' |
+//         'for' Assignment 'downto' Accessor ('step' SimpleExpression)?
+//            'do' ExpressionList 'endfor'
 std::unique_ptr<CXFA_FMExpression> CXFA_FMParser::ParseForExpression() {
   AutoRestorer<unsigned long> restorer(&m_parse_depth);
   if (HasError() || !IncrementParseDepthAndCheck())
     return nullptr;
+  if (!CheckThenNext(TOKfor))
+    return nullptr;
+  if (m_token.m_type != TOKidentifier)
+    return nullptr;
 
-  WideStringView wsVariant;
-  uint32_t line = m_token->m_line_num;
+  WideStringView wsVariant = m_token.m_string;
   if (!NextToken())
     return nullptr;
-  if (m_token->m_type != TOKidentifier) {
-    m_error = true;
-    return nullptr;
-  }
-
-  wsVariant = m_token->m_string;
-  if (!NextToken())
-    return nullptr;
-  if (m_token->m_type != TOKassign) {
-    m_error = true;
-    return nullptr;
-  }
-  if (!NextToken())
+  if (!CheckThenNext(TOKassign))
     return nullptr;
 
   std::unique_ptr<CXFA_FMSimpleExpression> pAssignment =
@@ -1120,14 +1034,12 @@
     return nullptr;
 
   int32_t iDirection = 0;
-  if (m_token->m_type == TOKupto) {
+  if (m_token.m_type == TOKupto)
     iDirection = 1;
-  } else if (m_token->m_type == TOKdownto) {
+  else if (m_token.m_type == TOKdownto)
     iDirection = -1;
-  } else {
-    m_error = true;
+  else
     return nullptr;
-  }
 
   if (!NextToken())
     return nullptr;
@@ -1137,7 +1049,7 @@
     return nullptr;
 
   std::unique_ptr<CXFA_FMSimpleExpression> pStep;
-  if (m_token->m_type == TOKstep) {
+  if (m_token.m_type == TOKstep) {
     if (!NextToken())
       return nullptr;
     pStep = ParseSimpleExpression();
@@ -1147,85 +1059,80 @@
   if (!CheckThenNext(TOKdo))
     return nullptr;
 
-  std::unique_ptr<CXFA_FMExpression> pList = ParseBlockExpression();
-  if (!pList || !CheckThenNext(TOKendfor))
+  auto exprs = ParseExpressionList();
+  if (!CheckThenNext(TOKendfor))
     return nullptr;
 
-  std::unique_ptr<CXFA_FMExpression> expr;
-  if (!expr)
-    return nullptr;
   return pdfium::MakeUnique<CXFA_FMForExpression>(
-      line, wsVariant, std::move(pAssignment), std::move(pAccessor), iDirection,
-      std::move(pStep), std::move(pList));
+      wsVariant, std::move(pAssignment), std::move(pAccessor), iDirection,
+      std::move(pStep),
+      pdfium::MakeUnique<CXFA_FMBlockExpression>(std::move(exprs)));
 }
 
+// Foreach := 'foreach' Identifier 'in' '(' ArgumentList ')'
+//            'do' ExpressionList 'endfor'
 std::unique_ptr<CXFA_FMExpression> CXFA_FMParser::ParseForeachExpression() {
+  if (m_token.m_type != TOKforeach)
+    return nullptr;
+
   AutoRestorer<unsigned long> restorer(&m_parse_depth);
   if (HasError() || !IncrementParseDepthAndCheck())
     return nullptr;
-
-  if (HasError())
+  if (!CheckThenNext(TOKforeach))
+    return nullptr;
+  if (m_token.m_type != TOKidentifier)
     return nullptr;
 
-  std::unique_ptr<CXFA_FMExpression> expr;
-  WideStringView wsIdentifier;
-  std::vector<std::unique_ptr<CXFA_FMSimpleExpression>> pAccessors;
-  std::unique_ptr<CXFA_FMExpression> pList;
-  uint32_t line = m_token->m_line_num;
-  if (!NextToken())
-    return nullptr;
-  if (m_token->m_type != TOKidentifier) {
-    m_error = true;
-    return nullptr;
-  }
-
-  wsIdentifier = m_token->m_string;
+  WideStringView wsIdentifier = m_token.m_string;
   if (!NextToken() || !CheckThenNext(TOKin) || !CheckThenNext(TOKlparen))
     return nullptr;
-  if (m_token->m_type == TOKrparen) {
-    m_error = true;
-    return nullptr;
-  }
 
-  while (m_token->m_type != TOKrparen) {
+  std::vector<std::unique_ptr<CXFA_FMSimpleExpression>> pArgumentList;
+  while (m_token.m_type != TOKrparen) {
     std::unique_ptr<CXFA_FMSimpleExpression> s = ParseSimpleExpression();
     if (!s)
       return nullptr;
 
-    pAccessors.push_back(std::move(s));
-    if (m_token->m_type != TOKcomma)
+    pArgumentList.push_back(std::move(s));
+    if (m_token.m_type != TOKcomma)
       break;
     if (!NextToken())
       return nullptr;
   }
-  if (!CheckThenNext(TOKrparen) || !CheckThenNext(TOKdo))
+  // We must have arguments.
+  if (pArgumentList.empty())
+    return nullptr;
+  if (!CheckThenNext(TOKrparen))
     return nullptr;
 
-  pList = ParseBlockExpression();
-  if (!pList || !CheckThenNext(TOKendfor))
+  auto exprs = ParseExpressionList();
+  if (!CheckThenNext(TOKendfor))
     return nullptr;
+
   return pdfium::MakeUnique<CXFA_FMForeachExpression>(
-      line, wsIdentifier, std::move(pAccessors), std::move(pList));
+      wsIdentifier, std::move(pArgumentList),
+      pdfium::MakeUnique<CXFA_FMBlockExpression>(std::move(exprs)));
 }
 
+// Block := 'do' ExpressionList 'end'
 std::unique_ptr<CXFA_FMExpression> CXFA_FMParser::ParseDoExpression() {
+  if (m_token.m_type != TOKdo)
+    return nullptr;
+
   AutoRestorer<unsigned long> restorer(&m_parse_depth);
   if (HasError() || !IncrementParseDepthAndCheck())
     return nullptr;
-
-  if (HasError())
+  if (!CheckThenNext(TOKdo))
     return nullptr;
 
-  uint32_t line = m_token->m_line_num;
-  if (!NextToken())
+  auto exprs = ParseExpressionList();
+  if (!CheckThenNext(TOKend))
     return nullptr;
 
-  std::unique_ptr<CXFA_FMExpression> expr = ParseBlockExpression();
-  if (!expr || !CheckThenNext(TOKend))
-    return nullptr;
-  return pdfium::MakeUnique<CXFA_FMDoExpression>(line, std::move(expr));
+  return pdfium::MakeUnique<CXFA_FMDoExpression>(
+      pdfium::MakeUnique<CXFA_FMBlockExpression>(std::move(exprs)));
 }
 
 bool CXFA_FMParser::HasError() const {
-  return m_error || m_token == nullptr;
+  return m_error || m_token.m_type == TOKreserver;
 }
diff --git a/xfa/fxfa/fm2js/cxfa_fmparser.h b/xfa/fxfa/fm2js/cxfa_fmparser.h
index c536838..ad2b367 100644
--- a/xfa/fxfa/fm2js/cxfa_fmparser.h
+++ b/xfa/fxfa/fm2js/cxfa_fmparser.h
@@ -15,10 +15,10 @@
 
 class CXFA_FMParser {
  public:
-  explicit CXFA_FMParser(const WideStringView& wsFormcalc);
+  explicit CXFA_FMParser(WideStringView wsFormcalc);
   ~CXFA_FMParser();
 
-  std::unique_ptr<CXFA_FMFunctionDefinition> Parse();
+  std::unique_ptr<CXFA_FMAST> Parse();
   bool HasError() const;
 
   void SetMaxParseDepthForTest(unsigned long max_depth) {
@@ -30,12 +30,11 @@
   bool CheckThenNext(XFA_FM_TOKEN op);
   bool IncrementParseDepthAndCheck();
 
-  std::vector<std::unique_ptr<CXFA_FMExpression>> ParseTopExpression();
+  std::vector<std::unique_ptr<CXFA_FMExpression>> ParseExpressionList();
   std::unique_ptr<CXFA_FMExpression> ParseFunction();
   std::unique_ptr<CXFA_FMExpression> ParseExpression();
-  std::unique_ptr<CXFA_FMExpression> ParseVarExpression();
+  std::unique_ptr<CXFA_FMExpression> ParseDeclarationExpression();
   std::unique_ptr<CXFA_FMExpression> ParseExpExpression();
-  std::unique_ptr<CXFA_FMExpression> ParseBlockExpression();
   std::unique_ptr<CXFA_FMExpression> ParseIfExpression();
   std::unique_ptr<CXFA_FMExpression> ParseWhileExpression();
   std::unique_ptr<CXFA_FMExpression> ParseForExpression();
@@ -43,21 +42,23 @@
   std::unique_ptr<CXFA_FMExpression> ParseDoExpression();
   std::unique_ptr<CXFA_FMSimpleExpression> ParseParenExpression();
   std::unique_ptr<CXFA_FMSimpleExpression> ParseSimpleExpression();
-  std::unique_ptr<CXFA_FMSimpleExpression> ParseSubassignmentInForExpression();
   std::unique_ptr<CXFA_FMSimpleExpression> ParseLogicalOrExpression();
   std::unique_ptr<CXFA_FMSimpleExpression> ParseLogicalAndExpression();
   std::unique_ptr<CXFA_FMSimpleExpression> ParseEqualityExpression();
   std::unique_ptr<CXFA_FMSimpleExpression> ParseRelationalExpression();
-  std::unique_ptr<CXFA_FMSimpleExpression> ParseAddtiveExpression();
+  std::unique_ptr<CXFA_FMSimpleExpression> ParseAdditiveExpression();
   std::unique_ptr<CXFA_FMSimpleExpression> ParseMultiplicativeExpression();
   std::unique_ptr<CXFA_FMSimpleExpression> ParseUnaryExpression();
   std::unique_ptr<CXFA_FMSimpleExpression> ParsePrimaryExpression();
   std::unique_ptr<CXFA_FMSimpleExpression> ParsePostExpression(
       std::unique_ptr<CXFA_FMSimpleExpression> e);
+  std::unique_ptr<std::vector<std::unique_ptr<CXFA_FMSimpleExpression>>>
+  ParseArgumentList();
   std::unique_ptr<CXFA_FMSimpleExpression> ParseIndexExpression();
+  std::unique_ptr<CXFA_FMSimpleExpression> ParseLiteral();
 
   std::unique_ptr<CXFA_FMLexer> m_lexer;
-  std::unique_ptr<CXFA_FMToken> m_token;
+  CXFA_FMToken m_token;
   bool m_error;
   unsigned long m_parse_depth;
   unsigned long m_max_parse_depth;
diff --git a/xfa/fxfa/fm2js/cxfa_fmparser_unittest.cpp b/xfa/fxfa/fm2js/cxfa_fmparser_unittest.cpp
index 8582649..4c5aa46 100644
--- a/xfa/fxfa/fm2js/cxfa_fmparser_unittest.cpp
+++ b/xfa/fxfa/fm2js/cxfa_fmparser_unittest.cpp
@@ -8,109 +8,131 @@
 
 #include "core/fxcrt/cfx_widetextbuf.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "testing/test_support.h"
 #include "third_party/base/ptr_util.h"
 #include "xfa/fxfa/fm2js/cxfa_fmtojavascriptdepth.h"
 
 TEST(CXFA_FMParserTest, Empty) {
   auto parser = pdfium::MakeUnique<CXFA_FMParser>(L"");
-  std::unique_ptr<CXFA_FMFunctionDefinition> ast = parser->Parse();
-  ASSERT(ast != nullptr);
+  std::unique_ptr<CXFA_FMAST> ast = parser->Parse();
+  ASSERT_TRUE(ast);
   EXPECT_FALSE(parser->HasError());
 
   CXFA_FMToJavaScriptDepth::Reset();
   CFX_WideTextBuf buf;
-  EXPECT_TRUE(ast->ToJavaScript(buf));
+  EXPECT_TRUE(ast->ToJavaScript(&buf));
   // TODO(dsinclair): This is a little weird .....
-  EXPECT_EQ(L"// comments only", buf.AsStringView());
+  EXPECT_STREQ(L"// comments only", buf.MakeString().c_str());
 }
 
 TEST(CXFA_FMParserTest, CommentOnlyIsError) {
   auto parser = pdfium::MakeUnique<CXFA_FMParser>(L"; Just comment");
-  std::unique_ptr<CXFA_FMFunctionDefinition> ast = parser->Parse();
-  ASSERT(ast != nullptr);
+  std::unique_ptr<CXFA_FMAST> ast = parser->Parse();
+  ASSERT_TRUE(ast);
   // TODO(dsinclair): This isn't allowed per the spec.
   EXPECT_FALSE(parser->HasError());
   // EXPECT_TRUE(parser->HasError());
 
   CXFA_FMToJavaScriptDepth::Reset();
   CFX_WideTextBuf buf;
-  EXPECT_TRUE(ast->ToJavaScript(buf));
-  EXPECT_EQ(L"// comments only", buf.AsStringView());
+  EXPECT_TRUE(ast->ToJavaScript(&buf));
+  EXPECT_STREQ(L"// comments only", buf.MakeString().c_str());
 }
 
 TEST(CXFA_FMParserTest, CommentThenValue) {
   const wchar_t ret[] =
-      L"(\nfunction ()\n{\n"
-      L"var pfm_ret = null;\n"
-      L"pfm_ret = 12;\n"
-      L"return pfm_rt.get_val(pfm_ret);\n"
-      L"}\n).call(this);\n";
+      LR"***((function() {
+let pfm_method_runner = function(obj, cb) {
+  if (pfm_rt.is_ary(obj)) {
+    let pfm_method_return = null;
+    for (var idx = obj.length -1; idx > 1; idx--) {
+      pfm_method_return = cb(obj[idx]);
+    }
+    return pfm_method_return;
+  }
+  return cb(obj);
+};
+var pfm_ret = null;
+pfm_ret = 12;
+return pfm_rt.get_val(pfm_ret);
+}).call(this);)***";
 
   auto parser = pdfium::MakeUnique<CXFA_FMParser>(L"; Just comment\n12");
-  std::unique_ptr<CXFA_FMFunctionDefinition> ast = parser->Parse();
-  ASSERT(ast != nullptr);
+  std::unique_ptr<CXFA_FMAST> ast = parser->Parse();
+  ASSERT_TRUE(ast);
   EXPECT_FALSE(parser->HasError());
 
   CXFA_FMToJavaScriptDepth::Reset();
   CFX_WideTextBuf buf;
-  EXPECT_TRUE(ast->ToJavaScript(buf));
-  EXPECT_EQ(ret, buf.AsStringView());
+  EXPECT_TRUE(ast->ToJavaScript(&buf));
+  EXPECT_STREQ(ret, buf.MakeString().c_str());
 }
 
 TEST(CXFA_FMParserTest, Parse) {
   const wchar_t input[] =
-      L"$ = Avg (-3, 5, -6, 12, -13);\n"
-      L"$ = Avg (Table2..Row[*].Cell1);\n"
-      L"\n"
-      L"if ($ ne -1)then\n"
-      L"  border.fill.color.value = \"255,64,64\";\n"
-      L"else\n"
-      L"  border.fill.color.value = \"20,170,13\";\n"
-      L"endif\n"
-      L"\n"
-      L"$";
+      LR"***($ = Avg (-3, 5, -6, 12, -13);
+$ = Avg (Table2..Row[*].Cell1);
+if ($ ne -1)then
+  border.fill.color.value = "255,64,64";
+elseif ($ ne -2) then
+  border.fill.color.value = "128,128,128";
+else
+  border.fill.color.value = "20,170,13";
+endif
+$)***";
 
   const wchar_t ret[] =
-      L"(\nfunction ()\n{\n"
-      L"var pfm_ret = null;\n"
-      L"if (pfm_rt.is_obj(this))\n{\n"
-      L"pfm_rt.asgn_val_op(this, pfm_rt.Avg(pfm_rt.neg_op(3), 5, "
-      L"pfm_rt.neg_op(6), 12, pfm_rt.neg_op(13)));\n"
-      L"}\n"
-      L"if (pfm_rt.is_obj(this))\n{\n"
-      L"pfm_rt.asgn_val_op(this, pfm_rt.Avg(pfm_rt.dot_acc(pfm_rt.dotdot_acc("
-      L"Table2, \"Table2\", \"Row\", 1), \"\", \"Cell1\", 0, 0)));\n"
-      L"}\n"
-      L"if (pfm_rt.get_val(pfm_rt.neq_op(this, pfm_rt.neg_op(1))))\n{\n"
-      L"if (pfm_rt.is_obj(pfm_rt.dot_acc(pfm_rt.dot_acc(pfm_rt.dot_acc("
-      L"border, \"border\", \"fill\", 0, 0), \"\", \"color\", 0, 0), \"\", "
-      L"\"value\", 0, 0)))\n{\n"
-      L"pfm_rt.asgn_val_op(pfm_rt.dot_acc(pfm_rt.dot_acc("
-      L"pfm_rt.dot_acc(border, \"border\", \"fill\", 0, 0), \"\", "
-      L"\"color\", 0, 0), \"\", \"value\", 0, 0), \"255,64,64\");\n"
-      L"}\n"
-      L"}\nelse\n{\n"
-      L"if (pfm_rt.is_obj(pfm_rt.dot_acc(pfm_rt.dot_acc(pfm_rt.dot_acc("
-      L"border, \"border\", \"fill\", 0, 0), \"\", \"color\", 0, 0), \"\", "
-      L"\"value\", 0, 0)))\n{\n"
-      L"pfm_rt.asgn_val_op(pfm_rt.dot_acc(pfm_rt.dot_acc("
-      L"pfm_rt.dot_acc(border, \"border\", \"fill\", 0, 0), \"\", "
-      L"\"color\", 0, 0), \"\", \"value\", 0, 0), \"20,170,13\");\n"
-      L"}\n"
-      L"}\n"
-      L"pfm_ret = this;\n"
-      L"return pfm_rt.get_val(pfm_ret);\n"
-      L"}\n).call(this);\n";
+      LR"***((function() {
+let pfm_method_runner = function(obj, cb) {
+  if (pfm_rt.is_ary(obj)) {
+    let pfm_method_return = null;
+    for (var idx = obj.length -1; idx > 1; idx--) {
+      pfm_method_return = cb(obj[idx]);
+    }
+    return pfm_method_return;
+  }
+  return cb(obj);
+};
+var pfm_ret = null;
+if (pfm_rt.is_obj(this))
+{
+pfm_rt.asgn_val_op(this, pfm_rt.Avg(pfm_rt.neg_op(3), 5, pfm_rt.neg_op(6), 12, pfm_rt.neg_op(13)));
+}
+if (pfm_rt.is_obj(this))
+{
+pfm_rt.asgn_val_op(this, pfm_rt.Avg(pfm_rt.dot_acc(pfm_rt.dotdot_acc(Table2, "Table2", "Row", 1), "", "Cell1", 0, 0)));
+}
+if (pfm_rt.get_val(pfm_rt.neq_op(this, pfm_rt.neg_op(1))))
+{
+if (pfm_rt.is_obj(pfm_rt.dot_acc(pfm_rt.dot_acc(pfm_rt.dot_acc(border, "border", "fill", 0, 0), "", "color", 0, 0), "", "value", 0, 0)))
+{
+pfm_rt.asgn_val_op(pfm_rt.dot_acc(pfm_rt.dot_acc(pfm_rt.dot_acc(border, "border", "fill", 0, 0), "", "color", 0, 0), "", "value", 0, 0), "255,64,64");
+}
+}
+else if (pfm_rt.get_val(pfm_rt.neq_op(this, pfm_rt.neg_op(2))))
+{
+if (pfm_rt.is_obj(pfm_rt.dot_acc(pfm_rt.dot_acc(pfm_rt.dot_acc(border, "border", "fill", 0, 0), "", "color", 0, 0), "", "value", 0, 0)))
+{
+pfm_rt.asgn_val_op(pfm_rt.dot_acc(pfm_rt.dot_acc(pfm_rt.dot_acc(border, "border", "fill", 0, 0), "", "color", 0, 0), "", "value", 0, 0), "128,128,128");
+}
+}
+else {
+if (pfm_rt.is_obj(pfm_rt.dot_acc(pfm_rt.dot_acc(pfm_rt.dot_acc(border, "border", "fill", 0, 0), "", "color", 0, 0), "", "value", 0, 0)))
+{
+pfm_rt.asgn_val_op(pfm_rt.dot_acc(pfm_rt.dot_acc(pfm_rt.dot_acc(border, "border", "fill", 0, 0), "", "color", 0, 0), "", "value", 0, 0), "20,170,13");
+}
+}
+pfm_ret = this;
+return pfm_rt.get_val(pfm_ret);
+}).call(this);)***";
 
   auto parser = pdfium::MakeUnique<CXFA_FMParser>(input);
-  std::unique_ptr<CXFA_FMFunctionDefinition> ast = parser->Parse();
-  ASSERT(ast != nullptr);
+  std::unique_ptr<CXFA_FMAST> ast = parser->Parse();
+  ASSERT_TRUE(ast);
   EXPECT_FALSE(parser->HasError());
 
   CXFA_FMToJavaScriptDepth::Reset();
   CFX_WideTextBuf buf;
-  EXPECT_TRUE(ast->ToJavaScript(buf));
+  EXPECT_TRUE(ast->ToJavaScript(&buf));
   EXPECT_EQ(ret, buf.AsStringView());
 }
 
@@ -123,9 +145,372 @@
 
 TEST(CFXA_FMParserTest, chromium752201) {
   auto parser = pdfium::MakeUnique<CXFA_FMParser>(
-      L"fTep a\n"
-      L".#\n"
-      L"fo@ =[=l");
+      LR"***(fTep a
+.#
+fo@ =[=l)***");
   EXPECT_EQ(nullptr, parser->Parse());
   EXPECT_TRUE(parser->HasError());
 }
+
+TEST(CXFA_FMParserTest, MultipleAssignmentIsNotAllowed) {
+  auto parser = pdfium::MakeUnique<CXFA_FMParser>(L"(a=(b=t))=u");
+
+  std::unique_ptr<CXFA_FMAST> ast = parser->Parse();
+  ASSERT_TRUE(!ast);
+  EXPECT_TRUE(parser->HasError());
+}
+
+TEST(CXFA_FMParserTest, ParseFuncWithParams) {
+  const wchar_t input[] =
+      LR"***(func MyFunction(param1, param2) do
+  param1 * param2
+endfunc)***";
+
+  const wchar_t ret[] =
+      LR"***((function() {
+let pfm_method_runner = function(obj, cb) {
+  if (pfm_rt.is_ary(obj)) {
+    let pfm_method_return = null;
+    for (var idx = obj.length -1; idx > 1; idx--) {
+      pfm_method_return = cb(obj[idx]);
+    }
+    return pfm_method_return;
+  }
+  return cb(obj);
+};
+var pfm_ret = null;
+function MyFunction(param1, param2) {
+var pfm_ret = null;
+pfm_ret = pfm_rt.mul_op(param1, param2);
+return pfm_ret;
+}
+return pfm_rt.get_val(pfm_ret);
+}).call(this);)***";
+
+  auto parser = pdfium::MakeUnique<CXFA_FMParser>(input);
+  std::unique_ptr<CXFA_FMAST> ast = parser->Parse();
+  ASSERT_TRUE(ast);
+  EXPECT_FALSE(parser->HasError());
+
+  CXFA_FMToJavaScriptDepth::Reset();
+  CFX_WideTextBuf buf;
+  EXPECT_TRUE(ast->ToJavaScript(&buf));
+  EXPECT_STREQ(ret, buf.MakeString().c_str());
+}
+
+TEST(CXFA_FMParserTest, ParseFuncWithoutParams) {
+  const wchar_t input[] =
+      LR"***(func MyFunction() do
+  42
+endfunc)***";
+
+  const wchar_t ret[] =
+      LR"***((function() {
+let pfm_method_runner = function(obj, cb) {
+  if (pfm_rt.is_ary(obj)) {
+    let pfm_method_return = null;
+    for (var idx = obj.length -1; idx > 1; idx--) {
+      pfm_method_return = cb(obj[idx]);
+    }
+    return pfm_method_return;
+  }
+  return cb(obj);
+};
+var pfm_ret = null;
+function MyFunction() {
+var pfm_ret = null;
+pfm_ret = 42;
+return pfm_ret;
+}
+return pfm_rt.get_val(pfm_ret);
+}).call(this);)***";
+
+  auto parser = pdfium::MakeUnique<CXFA_FMParser>(input);
+  std::unique_ptr<CXFA_FMAST> ast = parser->Parse();
+  ASSERT_TRUE(ast);
+  EXPECT_FALSE(parser->HasError());
+
+  CXFA_FMToJavaScriptDepth::Reset();
+  CFX_WideTextBuf buf;
+  EXPECT_TRUE(ast->ToJavaScript(&buf));
+  EXPECT_STREQ(ret, buf.MakeString().c_str());
+}
+
+TEST(CXFA_FMParserTest, ParseFuncWithBadParamsList) {
+  const wchar_t input[] =
+      LR"***(func MyFunction(param1,) do
+  param1 * param2
+endfunc)***";
+
+  auto parser = pdfium::MakeUnique<CXFA_FMParser>(input);
+  std::unique_ptr<CXFA_FMAST> ast = parser->Parse();
+  ASSERT_TRUE(ast == nullptr);
+  EXPECT_TRUE(parser->HasError());
+}
+
+TEST(CXFA_FMParserTest, ParseBadIfExpression) {
+  const wchar_t input[] = L"if ( then";
+
+  auto parser = pdfium::MakeUnique<CXFA_FMParser>(input);
+  std::unique_ptr<CXFA_FMAST> ast = parser->Parse();
+  ASSERT_TRUE(ast == nullptr);
+  EXPECT_TRUE(parser->HasError());
+}
+
+TEST(CXFA_FMParserTest, ParseBadElseIfExpression) {
+  const wchar_t input[] =
+      LR"***(if ($ ne -1) then"
+elseif( then)***";
+
+  auto parser = pdfium::MakeUnique<CXFA_FMParser>(input);
+  std::unique_ptr<CXFA_FMAST> ast = parser->Parse();
+  ASSERT_TRUE(ast == nullptr);
+  EXPECT_TRUE(parser->HasError());
+}
+
+TEST(CXFA_FMParserTest, ParseDepthWithWideTree) {
+  const wchar_t input[] = L"a <> b <> c <> d <> e <> f <> g <> h <> i <> j";
+
+  {
+    auto parser = pdfium::MakeUnique<CXFA_FMParser>(input);
+    std::unique_ptr<CXFA_FMAST> ast = parser->Parse();
+    ASSERT_TRUE(ast);
+    EXPECT_TRUE(!parser->HasError());
+  }
+
+  {
+    auto parser = pdfium::MakeUnique<CXFA_FMParser>(input);
+    parser->SetMaxParseDepthForTest(5);
+    std::unique_ptr<CXFA_FMAST> ast = parser->Parse();
+    ASSERT_TRUE(ast == nullptr);
+    EXPECT_TRUE(parser->HasError());
+  }
+}
+
+TEST(CXFA_FMParserTest, ParseCallSmall) {
+  const wchar_t input[] = L"i.f(O)";
+  const wchar_t ret[] =
+      LR"***((function() {
+let pfm_method_runner = function(obj, cb) {
+  if (pfm_rt.is_ary(obj)) {
+    let pfm_method_return = null;
+    for (var idx = obj.length -1; idx > 1; idx--) {
+      pfm_method_return = cb(obj[idx]);
+    }
+    return pfm_method_return;
+  }
+  return cb(obj);
+};
+var pfm_ret = null;
+pfm_ret = pfm_rt.get_val((function() {
+  return pfm_method_runner(i, function(obj) {
+    return obj.f(pfm_rt.get_val(O));
+  });
+}).call(this));
+return pfm_rt.get_val(pfm_ret);
+}).call(this);)***";
+
+  auto parser = pdfium::MakeUnique<CXFA_FMParser>(input);
+  std::unique_ptr<CXFA_FMAST> ast = parser->Parse();
+  EXPECT_FALSE(parser->HasError());
+
+  CXFA_FMToJavaScriptDepth::Reset();
+  CFX_WideTextBuf buf;
+  EXPECT_TRUE(ast->ToJavaScript(&buf));
+  EXPECT_STREQ(ret, buf.MakeString().c_str());
+}
+
+TEST(CXFA_FMParserTest, ParseCallBig) {
+  const wchar_t input[] = L"i.f(O.e(O.e(O)))";
+  const wchar_t ret[] =
+      LR"***((function() {
+let pfm_method_runner = function(obj, cb) {
+  if (pfm_rt.is_ary(obj)) {
+    let pfm_method_return = null;
+    for (var idx = obj.length -1; idx > 1; idx--) {
+      pfm_method_return = cb(obj[idx]);
+    }
+    return pfm_method_return;
+  }
+  return cb(obj);
+};
+var pfm_ret = null;
+pfm_ret = pfm_rt.get_val((function() {
+  return pfm_method_runner(i, function(obj) {
+    return obj.f(pfm_rt.get_val((function() {
+  return pfm_method_runner(O, function(obj) {
+    return obj.e(pfm_rt.get_val((function() {
+  return pfm_method_runner(O, function(obj) {
+    return obj.e(pfm_rt.get_val(O));
+  });
+}).call(this)));
+  });
+}).call(this)));
+  });
+}).call(this));
+return pfm_rt.get_val(pfm_ret);
+}).call(this);)***";
+
+  auto parser = pdfium::MakeUnique<CXFA_FMParser>(input);
+  std::unique_ptr<CXFA_FMAST> ast = parser->Parse();
+  EXPECT_FALSE(parser->HasError());
+
+  CXFA_FMToJavaScriptDepth::Reset();
+  CFX_WideTextBuf buf;
+  EXPECT_TRUE(ast->ToJavaScript(&buf));
+  EXPECT_STREQ(ret, buf.MakeString().c_str());
+}
+
+TEST(CXFA_FMParserTest, ParseVar) {
+  const wchar_t input[] = LR"(var s = "")";
+  const wchar_t ret[] =
+      LR"***((function() {
+let pfm_method_runner = function(obj, cb) {
+  if (pfm_rt.is_ary(obj)) {
+    let pfm_method_return = null;
+    for (var idx = obj.length -1; idx > 1; idx--) {
+      pfm_method_return = cb(obj[idx]);
+    }
+    return pfm_method_return;
+  }
+  return cb(obj);
+};
+var pfm_ret = null;
+var s = "";
+s = pfm_rt.var_filter(s);
+pfm_ret = s;
+return pfm_rt.get_val(pfm_ret);
+}).call(this);)***";
+
+  auto parser = pdfium::MakeUnique<CXFA_FMParser>(input);
+  std::unique_ptr<CXFA_FMAST> ast = parser->Parse();
+  EXPECT_FALSE(parser->HasError());
+
+  CXFA_FMToJavaScriptDepth::Reset();
+  CFX_WideTextBuf buf;
+  EXPECT_TRUE(ast->ToJavaScript(&buf));
+  EXPECT_STREQ(ret, buf.MakeString().c_str());
+}
+
+TEST(CXFA_FMParserTest, ParseFunctionCallNoArguments) {
+  const wchar_t input[] = L"P.x()";
+  const wchar_t ret[] =
+      LR"***((function() {
+let pfm_method_runner = function(obj, cb) {
+  if (pfm_rt.is_ary(obj)) {
+    let pfm_method_return = null;
+    for (var idx = obj.length -1; idx > 1; idx--) {
+      pfm_method_return = cb(obj[idx]);
+    }
+    return pfm_method_return;
+  }
+  return cb(obj);
+};
+var pfm_ret = null;
+pfm_ret = pfm_rt.get_val((function() {
+  return pfm_method_runner(P, function(obj) {
+    return obj.x();
+  });
+}).call(this));
+return pfm_rt.get_val(pfm_ret);
+}).call(this);)***";
+
+  auto parser = pdfium::MakeUnique<CXFA_FMParser>(input);
+  std::unique_ptr<CXFA_FMAST> ast = parser->Parse();
+  EXPECT_FALSE(parser->HasError());
+  CXFA_FMToJavaScriptDepth::Reset();
+  CFX_WideTextBuf buf;
+  EXPECT_TRUE(ast->ToJavaScript(&buf));
+  EXPECT_STREQ(ret, buf.MakeString().c_str());
+}
+
+TEST(CXFA_FMParserTest, ParseFunctionCallSingleArgument) {
+  const wchar_t input[] = L"P.x(foo)";
+  const wchar_t ret[] =
+      LR"***((function() {
+let pfm_method_runner = function(obj, cb) {
+  if (pfm_rt.is_ary(obj)) {
+    let pfm_method_return = null;
+    for (var idx = obj.length -1; idx > 1; idx--) {
+      pfm_method_return = cb(obj[idx]);
+    }
+    return pfm_method_return;
+  }
+  return cb(obj);
+};
+var pfm_ret = null;
+pfm_ret = pfm_rt.get_val((function() {
+  return pfm_method_runner(P, function(obj) {
+    return obj.x(pfm_rt.get_jsobj(foo));
+  });
+}).call(this));
+return pfm_rt.get_val(pfm_ret);
+}).call(this);)***";
+
+  auto parser = pdfium::MakeUnique<CXFA_FMParser>(input);
+  std::unique_ptr<CXFA_FMAST> ast = parser->Parse();
+  EXPECT_FALSE(parser->HasError());
+  CXFA_FMToJavaScriptDepth::Reset();
+  CFX_WideTextBuf buf;
+  EXPECT_TRUE(ast->ToJavaScript(&buf));
+  EXPECT_STREQ(ret, buf.MakeString().c_str());
+}
+
+TEST(CXFA_FMParserTest, ParseFunctionCallMultipleArguments) {
+  const wchar_t input[] = L"P.x(foo, bar, baz)";
+  const wchar_t ret[] =
+      LR"***((function() {
+let pfm_method_runner = function(obj, cb) {
+  if (pfm_rt.is_ary(obj)) {
+    let pfm_method_return = null;
+    for (var idx = obj.length -1; idx > 1; idx--) {
+      pfm_method_return = cb(obj[idx]);
+    }
+    return pfm_method_return;
+  }
+  return cb(obj);
+};
+var pfm_ret = null;
+pfm_ret = pfm_rt.get_val((function() {
+  return pfm_method_runner(P, function(obj) {
+    return obj.x(pfm_rt.get_jsobj(foo), pfm_rt.get_val(bar), pfm_rt.get_val(baz));
+  });
+}).call(this));
+return pfm_rt.get_val(pfm_ret);
+}).call(this);)***";
+
+  auto parser = pdfium::MakeUnique<CXFA_FMParser>(input);
+  std::unique_ptr<CXFA_FMAST> ast = parser->Parse();
+  EXPECT_FALSE(parser->HasError());
+  CXFA_FMToJavaScriptDepth::Reset();
+  CFX_WideTextBuf buf;
+  EXPECT_TRUE(ast->ToJavaScript(&buf));
+  EXPECT_STREQ(ret, buf.MakeString().c_str());
+}
+
+TEST(CXFA_FMParserTest, ParseFunctionCallMissingCommas) {
+  const wchar_t input[] = L"P.x(!foo!bar!baz)";
+
+  auto parser = pdfium::MakeUnique<CXFA_FMParser>(input);
+  std::unique_ptr<CXFA_FMAST> ast = parser->Parse();
+  ASSERT_TRUE(ast == nullptr);
+  EXPECT_TRUE(parser->HasError());
+}
+
+TEST(CXFA_FMParserTest, ParseFunctionCallTrailingComma) {
+  const wchar_t input[] = L"P.x(foo,bar,baz,)";
+
+  auto parser = pdfium::MakeUnique<CXFA_FMParser>(input);
+  std::unique_ptr<CXFA_FMAST> ast = parser->Parse();
+  ASSERT_TRUE(ast == nullptr);
+  EXPECT_TRUE(parser->HasError());
+}
+
+TEST(CXFA_FMParserTest, ParseFunctionCallExtraComma) {
+  const wchar_t input[] = L"P.x(foo,bar,,baz)";
+
+  auto parser = pdfium::MakeUnique<CXFA_FMParser>(input);
+  std::unique_ptr<CXFA_FMAST> ast = parser->Parse();
+  ASSERT_TRUE(ast == nullptr);
+  EXPECT_TRUE(parser->HasError());
+}
diff --git a/xfa/fxfa/fm2js/cxfa_fmsimpleexpression.cpp b/xfa/fxfa/fm2js/cxfa_fmsimpleexpression.cpp
index 373ba91..e94f55a 100644
--- a/xfa/fxfa/fm2js/cxfa_fmsimpleexpression.cpp
+++ b/xfa/fxfa/fm2js/cxfa_fmsimpleexpression.cpp
@@ -7,7 +7,6 @@
 #include "xfa/fxfa/fm2js/cxfa_fmsimpleexpression.h"
 
 #include <algorithm>
-#include <iostream>
 #include <utility>
 
 #include "core/fxcrt/autorestorer.h"
@@ -18,19 +17,6 @@
 
 namespace {
 
-// Indexed by XFA_FM_SimpleExpressionType
-const wchar_t* const gs_lpStrExpFuncName[] = {
-    L"pfm_rt.asgn_val_op", L"pfm_rt.log_or_op",  L"pfm_rt.log_and_op",
-    L"pfm_rt.eq_op",       L"pfm_rt.neq_op",     L"pfm_rt.lt_op",
-    L"pfm_rt.le_op",       L"pfm_rt.gt_op",      L"pfm_rt.ge_op",
-    L"pfm_rt.plus_op",     L"pfm_rt.minus_op",   L"pfm_rt.mul_op",
-    L"pfm_rt.div_op",      L"pfm_rt.pos_op",     L"pfm_rt.neg_op",
-    L"pfm_rt.log_not_op",  L"pfm_rt.",           L"pfm_rt.dot_acc",
-    L"pfm_rt.dotdot_acc",  L"pfm_rt.concat_obj", L"pfm_rt.is_obj",
-    L"pfm_rt.is_ary",      L"pfm_rt.get_val",    L"pfm_rt.get_jsobj",
-    L"pfm_rt.var_filter",
-};
-
 const wchar_t* const g_BuiltInFuncs[] = {
     L"Abs",          L"Apr",       L"At",       L"Avg",
     L"Ceil",         L"Choose",    L"Concat",   L"Count",
@@ -84,498 +70,331 @@
 
 }  // namespace
 
-WideStringView XFA_FM_EXPTypeToString(
-    XFA_FM_SimpleExpressionType simpleExpType) {
-  return gs_lpStrExpFuncName[simpleExpType];
-}
-
-CXFA_FMSimpleExpression::CXFA_FMSimpleExpression(uint32_t line, XFA_FM_TOKEN op)
-    : m_line(line), m_op(op) {}
-
-bool CXFA_FMSimpleExpression::ToJavaScript(CFX_WideTextBuf& javascript) {
-  CXFA_FMToJavaScriptDepth depthManager;
-  return !CXFA_IsTooBig(javascript) && depthManager.IsWithinMaxDepth();
-}
-
-bool CXFA_FMSimpleExpression::ToImpliedReturnJS(CFX_WideTextBuf& javascript) {
-  CXFA_FMToJavaScriptDepth depthManager;
-  return !CXFA_IsTooBig(javascript) && depthManager.IsWithinMaxDepth();
-}
+CXFA_FMSimpleExpression::CXFA_FMSimpleExpression(XFA_FM_TOKEN op) : m_op(op) {}
 
 XFA_FM_TOKEN CXFA_FMSimpleExpression::GetOperatorToken() const {
   return m_op;
 }
 
-CXFA_FMNullExpression::CXFA_FMNullExpression(uint32_t line)
-    : CXFA_FMSimpleExpression(line, TOKnull) {}
+CXFA_FMNullExpression::CXFA_FMNullExpression()
+    : CXFA_FMSimpleExpression(TOKnull) {}
 
-bool CXFA_FMNullExpression::ToJavaScript(CFX_WideTextBuf& javascript) {
+bool CXFA_FMNullExpression::ToJavaScript(CFX_WideTextBuf* js, ReturnType type) {
   CXFA_FMToJavaScriptDepth depthManager;
-  if (CXFA_IsTooBig(javascript) || !depthManager.IsWithinMaxDepth())
+  if (CXFA_IsTooBig(js) || !depthManager.IsWithinMaxDepth())
     return false;
 
-  javascript << L"null";
-  return !CXFA_IsTooBig(javascript);
+  *js << "null";
+  return !CXFA_IsTooBig(js);
 }
 
-CXFA_FMNumberExpression::CXFA_FMNumberExpression(uint32_t line,
-                                                 WideStringView wsNumber)
-    : CXFA_FMSimpleExpression(line, TOKnumber), m_wsNumber(wsNumber) {}
+CXFA_FMNumberExpression::CXFA_FMNumberExpression(WideStringView wsNumber)
+    : CXFA_FMSimpleExpression(TOKnumber), m_wsNumber(wsNumber) {}
 
-CXFA_FMNumberExpression::~CXFA_FMNumberExpression() {}
+CXFA_FMNumberExpression::~CXFA_FMNumberExpression() = default;
 
-bool CXFA_FMNumberExpression::ToJavaScript(CFX_WideTextBuf& javascript) {
+bool CXFA_FMNumberExpression::ToJavaScript(CFX_WideTextBuf* js,
+                                           ReturnType type) {
   CXFA_FMToJavaScriptDepth depthManager;
-  if (CXFA_IsTooBig(javascript) || !depthManager.IsWithinMaxDepth())
+  if (CXFA_IsTooBig(js) || !depthManager.IsWithinMaxDepth())
     return false;
 
-  javascript << m_wsNumber;
-  return !CXFA_IsTooBig(javascript);
+  *js << m_wsNumber;
+  return !CXFA_IsTooBig(js);
 }
 
-CXFA_FMStringExpression::CXFA_FMStringExpression(uint32_t line,
-                                                 WideStringView wsString)
-    : CXFA_FMSimpleExpression(line, TOKstring), m_wsString(wsString) {}
+CXFA_FMStringExpression::CXFA_FMStringExpression(WideStringView wsString)
+    : CXFA_FMSimpleExpression(TOKstring), m_wsString(wsString) {}
 
-CXFA_FMStringExpression::~CXFA_FMStringExpression() {}
+CXFA_FMStringExpression::~CXFA_FMStringExpression() = default;
 
-bool CXFA_FMStringExpression::ToJavaScript(CFX_WideTextBuf& javascript) {
+bool CXFA_FMStringExpression::ToJavaScript(CFX_WideTextBuf* js,
+                                           ReturnType type) {
   CXFA_FMToJavaScriptDepth depthManager;
-  if (CXFA_IsTooBig(javascript) || !depthManager.IsWithinMaxDepth())
+  if (CXFA_IsTooBig(js) || !depthManager.IsWithinMaxDepth())
     return false;
 
   WideString tempStr(m_wsString);
   if (tempStr.GetLength() <= 2) {
-    javascript << tempStr;
-    return !CXFA_IsTooBig(javascript);
+    *js << tempStr;
+    return !CXFA_IsTooBig(js);
   }
-  javascript.AppendChar(L'\"');
+
+  *js << "\"";
   for (size_t i = 1; i < tempStr.GetLength() - 1; i++) {
     wchar_t oneChar = tempStr[i];
     switch (oneChar) {
       case L'\"':
-        i++;
-        javascript << L"\\\"";
+        ++i;
+        *js << "\\\"";
         break;
       case 0x0d:
         break;
       case 0x0a:
-        javascript << L"\\n";
+        *js << "\\n";
         break;
       default:
-        javascript.AppendChar(oneChar);
+        js->AppendChar(oneChar);
         break;
     }
   }
-  javascript.AppendChar(L'\"');
-  return !CXFA_IsTooBig(javascript);
+  *js << "\"";
+  return !CXFA_IsTooBig(js);
 }
 
 CXFA_FMIdentifierExpression::CXFA_FMIdentifierExpression(
-    uint32_t line,
     WideStringView wsIdentifier)
-    : CXFA_FMSimpleExpression(line, TOKidentifier),
-      m_wsIdentifier(wsIdentifier) {}
+    : CXFA_FMSimpleExpression(TOKidentifier), m_wsIdentifier(wsIdentifier) {}
 
-CXFA_FMIdentifierExpression::~CXFA_FMIdentifierExpression() {}
+CXFA_FMIdentifierExpression::~CXFA_FMIdentifierExpression() = default;
 
-bool CXFA_FMIdentifierExpression::ToJavaScript(CFX_WideTextBuf& javascript) {
+bool CXFA_FMIdentifierExpression::ToJavaScript(CFX_WideTextBuf* js,
+                                               ReturnType type) {
   CXFA_FMToJavaScriptDepth depthManager;
-  if (CXFA_IsTooBig(javascript) || !depthManager.IsWithinMaxDepth())
+  if (CXFA_IsTooBig(js) || !depthManager.IsWithinMaxDepth())
     return false;
 
-  WideString tempStr(m_wsIdentifier);
-  if (tempStr == L"$") {
-    tempStr = L"this";
-  } else if (tempStr == L"!") {
-    tempStr = L"xfa.datasets";
-  } else if (tempStr == L"$data") {
-    tempStr = L"xfa.datasets.data";
-  } else if (tempStr == L"$event") {
-    tempStr = L"xfa.event";
-  } else if (tempStr == L"$form") {
-    tempStr = L"xfa.form";
-  } else if (tempStr == L"$host") {
-    tempStr = L"xfa.host";
-  } else if (tempStr == L"$layout") {
-    tempStr = L"xfa.layout";
-  } else if (tempStr == L"$template") {
-    tempStr = L"xfa.template";
-  } else if (tempStr[0] == L'!') {
-    tempStr =
-        EXCLAMATION_IN_IDENTIFIER + tempStr.Right(tempStr.GetLength() - 1);
-  }
-  javascript << tempStr;
-  return !CXFA_IsTooBig(javascript);
-}
+  if (m_wsIdentifier.EqualsASCII("$"))
+    *js << "this";
+  else if (m_wsIdentifier.EqualsASCII("!"))
+    *js << "xfa.datasets";
+  else if (m_wsIdentifier.EqualsASCII("$data"))
+    *js << "xfa.datasets.data";
+  else if (m_wsIdentifier.EqualsASCII("$event"))
+    *js << "xfa.event";
+  else if (m_wsIdentifier.EqualsASCII("$form"))
+    *js << "xfa.form";
+  else if (m_wsIdentifier.EqualsASCII("$host"))
+    *js << "xfa.host";
+  else if (m_wsIdentifier.EqualsASCII("$layout"))
+    *js << "xfa.layout";
+  else if (m_wsIdentifier.EqualsASCII("$template"))
+    *js << "xfa.template";
+  else if (m_wsIdentifier[0] == L'!')
+    *js << "pfm__excl__" << m_wsIdentifier.Last(m_wsIdentifier.GetLength() - 1);
+  else
+    *js << m_wsIdentifier;
 
-CXFA_FMUnaryExpression::CXFA_FMUnaryExpression(
-    uint32_t line,
-    XFA_FM_TOKEN op,
-    std::unique_ptr<CXFA_FMSimpleExpression> pExp)
-    : CXFA_FMSimpleExpression(line, op), m_pExp(std::move(pExp)) {}
-
-CXFA_FMUnaryExpression::~CXFA_FMUnaryExpression() {}
-
-bool CXFA_FMUnaryExpression::ToJavaScript(CFX_WideTextBuf& javascript) {
-  CXFA_FMToJavaScriptDepth depthManager;
-  return !CXFA_IsTooBig(javascript) && depthManager.IsWithinMaxDepth();
-}
-
-CXFA_FMBinExpression::CXFA_FMBinExpression(
-    uint32_t line,
-    XFA_FM_TOKEN op,
-    std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
-    std::unique_ptr<CXFA_FMSimpleExpression> pExp2)
-    : CXFA_FMSimpleExpression(line, op),
-      m_pExp1(std::move(pExp1)),
-      m_pExp2(std::move(pExp2)) {}
-
-CXFA_FMBinExpression::~CXFA_FMBinExpression() {}
-
-bool CXFA_FMBinExpression::ToJavaScript(CFX_WideTextBuf& javascript) {
-  CXFA_FMToJavaScriptDepth depthManager;
-  return !CXFA_IsTooBig(javascript) && depthManager.IsWithinMaxDepth();
+  return !CXFA_IsTooBig(js);
 }
 
 CXFA_FMAssignExpression::CXFA_FMAssignExpression(
-    uint32_t line,
     XFA_FM_TOKEN op,
     std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
     std::unique_ptr<CXFA_FMSimpleExpression> pExp2)
-    : CXFA_FMBinExpression(line, op, std::move(pExp1), std::move(pExp2)) {}
+    : CXFA_FMSimpleExpression(op),
+      m_pExp1(std::move(pExp1)),
+      m_pExp2(std::move(pExp2)) {}
 
-bool CXFA_FMAssignExpression::ToJavaScript(CFX_WideTextBuf& javascript) {
+CXFA_FMAssignExpression::~CXFA_FMAssignExpression() = default;
+
+bool CXFA_FMAssignExpression::ToJavaScript(CFX_WideTextBuf* js,
+                                           ReturnType type) {
   CXFA_FMToJavaScriptDepth depthManager;
-  if (CXFA_IsTooBig(javascript) || !depthManager.IsWithinMaxDepth())
+  if (CXFA_IsTooBig(js) || !depthManager.IsWithinMaxDepth())
     return false;
 
-  javascript << L"if (";
-  javascript << gs_lpStrExpFuncName[ISFMOBJECT];
-  javascript << L"(";
   CFX_WideTextBuf tempExp1;
-  if (!m_pExp1->ToJavaScript(tempExp1))
+  if (!m_pExp1->ToJavaScript(&tempExp1, ReturnType::kInfered))
     return false;
-  javascript << tempExp1;
-  javascript << L"))\n{\n";
-  javascript << gs_lpStrExpFuncName[ASSIGN];
-  javascript << L"(";
-  javascript << tempExp1;
-  javascript << L", ";
+
+  *js << "if (pfm_rt.is_obj(" << tempExp1 << "))\n{\n";
+  if (type == ReturnType::kImplied)
+    *js << "pfm_ret = ";
 
   CFX_WideTextBuf tempExp2;
-  if (!m_pExp2->ToJavaScript(tempExp2))
+  if (!m_pExp2->ToJavaScript(&tempExp2, ReturnType::kInfered))
     return false;
-  javascript << tempExp2;
-  javascript << L");\n}\n";
+
+  *js << "pfm_rt.asgn_val_op(" << tempExp1 << ", " << tempExp2 << ");\n}\n";
+
   if (m_pExp1->GetOperatorToken() == TOKidentifier &&
-      tempExp1.AsStringView() != L"this") {
-    javascript << L"else\n{\n";
-    javascript << tempExp1;
-    javascript << L" = ";
-    javascript << gs_lpStrExpFuncName[ASSIGN];
-    javascript << L"(";
-    javascript << tempExp1;
-    javascript << L", ";
-    javascript << tempExp2;
-    javascript << L");\n}\n";
+      !tempExp1.AsStringView().EqualsASCII("this")) {
+    *js << "else\n{\n";
+    if (type == ReturnType::kImplied)
+      *js << "pfm_ret = ";
+
+    *js << tempExp1 << " = pfm_rt.asgn_val_op";
+    *js << "(" << tempExp1 << ", " << tempExp2 << ");\n";
+    *js << "}\n";
   }
-  return !CXFA_IsTooBig(javascript);
+  return !CXFA_IsTooBig(js);
 }
 
-bool CXFA_FMAssignExpression::ToImpliedReturnJS(CFX_WideTextBuf& javascript) {
+CXFA_FMBinExpression::CXFA_FMBinExpression(
+    const WideString& opName,
+    XFA_FM_TOKEN op,
+    std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
+    std::unique_ptr<CXFA_FMSimpleExpression> pExp2)
+    : CXFA_FMSimpleExpression(op),
+      m_OpName(opName),
+      m_pExp1(std::move(pExp1)),
+      m_pExp2(std::move(pExp2)) {}
+
+CXFA_FMBinExpression::~CXFA_FMBinExpression() = default;
+
+bool CXFA_FMBinExpression::ToJavaScript(CFX_WideTextBuf* js, ReturnType type) {
   CXFA_FMToJavaScriptDepth depthManager;
-  if (CXFA_IsTooBig(javascript) || !depthManager.IsWithinMaxDepth())
+  if (CXFA_IsTooBig(js) || !depthManager.IsWithinMaxDepth())
     return false;
 
-  javascript << L"if (";
-  javascript << gs_lpStrExpFuncName[ISFMOBJECT];
-  javascript << L"(";
-  CFX_WideTextBuf tempExp1;
-  if (!m_pExp1->ToJavaScript(tempExp1))
+  *js << "pfm_rt." << m_OpName << "(";
+  if (!m_pExp1->ToJavaScript(js, ReturnType::kInfered))
     return false;
-  javascript << tempExp1;
-  javascript << L"))\n{\n";
-  javascript << RUNTIMEFUNCTIONRETURNVALUE;
-  javascript << L" = ";
-  javascript << gs_lpStrExpFuncName[ASSIGN];
-  javascript << L"(";
-  javascript << tempExp1;
-  javascript << L", ";
-
-  CFX_WideTextBuf tempExp2;
-  if (!m_pExp2->ToJavaScript(tempExp2))
+  *js << ", ";
+  if (!m_pExp2->ToJavaScript(js, ReturnType::kInfered))
     return false;
-  javascript << tempExp2;
-  javascript << L");\n}\n";
-  if (m_pExp1->GetOperatorToken() == TOKidentifier &&
-      tempExp1.AsStringView() != L"this") {
-    javascript << L"else\n{\n";
-    javascript << RUNTIMEFUNCTIONRETURNVALUE;
-    javascript << L" = ";
-    javascript << tempExp1;
-    javascript << L" = ";
-    javascript << gs_lpStrExpFuncName[ASSIGN];
-    javascript << L"(";
-    javascript << tempExp1;
-    javascript << L", ";
-    javascript << tempExp2;
-    javascript << L");\n}\n";
-  }
-  return !CXFA_IsTooBig(javascript);
+  *js << ")";
+  return !CXFA_IsTooBig(js);
 }
 
 CXFA_FMLogicalOrExpression::CXFA_FMLogicalOrExpression(
-    uint32_t line,
     XFA_FM_TOKEN op,
     std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
     std::unique_ptr<CXFA_FMSimpleExpression> pExp2)
-    : CXFA_FMBinExpression(line, op, std::move(pExp1), std::move(pExp2)) {}
-
-bool CXFA_FMLogicalOrExpression::ToJavaScript(CFX_WideTextBuf& javascript) {
-  CXFA_FMToJavaScriptDepth depthManager;
-  if (CXFA_IsTooBig(javascript) || !depthManager.IsWithinMaxDepth())
-    return false;
-
-  javascript << gs_lpStrExpFuncName[LOGICALOR];
-  javascript << L"(";
-  if (!m_pExp1->ToJavaScript(javascript))
-    return false;
-  javascript << L", ";
-  if (!m_pExp2->ToJavaScript(javascript))
-    return false;
-  javascript << L")";
-  return !CXFA_IsTooBig(javascript);
-}
+    : CXFA_FMBinExpression(L"log_or_op",
+                           op,
+                           std::move(pExp1),
+                           std::move(pExp2)) {}
 
 CXFA_FMLogicalAndExpression::CXFA_FMLogicalAndExpression(
-    uint32_t line,
     XFA_FM_TOKEN op,
     std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
     std::unique_ptr<CXFA_FMSimpleExpression> pExp2)
-    : CXFA_FMBinExpression(line, op, std::move(pExp1), std::move(pExp2)) {}
+    : CXFA_FMBinExpression(L"log_and_op",
+                           op,
+                           std::move(pExp1),
+                           std::move(pExp2)) {}
 
-bool CXFA_FMLogicalAndExpression::ToJavaScript(CFX_WideTextBuf& javascript) {
-  CXFA_FMToJavaScriptDepth depthManager;
-  if (CXFA_IsTooBig(javascript) || !depthManager.IsWithinMaxDepth())
-    return false;
-
-  javascript << gs_lpStrExpFuncName[LOGICALAND];
-  javascript << L"(";
-  if (!m_pExp1->ToJavaScript(javascript))
-    return false;
-  javascript << L", ";
-  if (!m_pExp2->ToJavaScript(javascript))
-    return false;
-  javascript << L")";
-  return !CXFA_IsTooBig(javascript);
-}
-
-CXFA_FMEqualityExpression::CXFA_FMEqualityExpression(
-    uint32_t line,
+CXFA_FMEqualExpression::CXFA_FMEqualExpression(
     XFA_FM_TOKEN op,
     std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
     std::unique_ptr<CXFA_FMSimpleExpression> pExp2)
-    : CXFA_FMBinExpression(line, op, std::move(pExp1), std::move(pExp2)) {}
+    : CXFA_FMBinExpression(L"eq_op",
+                           op,
+                           std::move(pExp1),
+                           std::move(pExp2)) {}
 
-bool CXFA_FMEqualityExpression::ToJavaScript(CFX_WideTextBuf& javascript) {
-  CXFA_FMToJavaScriptDepth depthManager;
-  if (CXFA_IsTooBig(javascript) || !depthManager.IsWithinMaxDepth())
-    return false;
-
-  switch (m_op) {
-    case TOKeq:
-    case TOKkseq:
-      javascript << gs_lpStrExpFuncName[EQUALITY];
-      break;
-    case TOKne:
-    case TOKksne:
-      javascript << gs_lpStrExpFuncName[NOTEQUALITY];
-      break;
-    default:
-      NOTREACHED();
-      break;
-  }
-  javascript << L"(";
-  if (!m_pExp1->ToJavaScript(javascript))
-    return false;
-  javascript << L", ";
-  if (!m_pExp2->ToJavaScript(javascript))
-    return false;
-  javascript << L")";
-  return !CXFA_IsTooBig(javascript);
-}
-
-CXFA_FMRelationalExpression::CXFA_FMRelationalExpression(
-    uint32_t line,
+CXFA_FMNotEqualExpression::CXFA_FMNotEqualExpression(
     XFA_FM_TOKEN op,
     std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
     std::unique_ptr<CXFA_FMSimpleExpression> pExp2)
-    : CXFA_FMBinExpression(line, op, std::move(pExp1), std::move(pExp2)) {}
+    : CXFA_FMBinExpression(L"neq_op",
+                           op,
+                           std::move(pExp1),
+                           std::move(pExp2)) {}
 
-bool CXFA_FMRelationalExpression::ToJavaScript(CFX_WideTextBuf& javascript) {
-  CXFA_FMToJavaScriptDepth depthManager;
-  if (CXFA_IsTooBig(javascript) || !depthManager.IsWithinMaxDepth())
-    return false;
-
-  switch (m_op) {
-    case TOKlt:
-    case TOKkslt:
-      javascript << gs_lpStrExpFuncName[LESS];
-      break;
-    case TOKgt:
-    case TOKksgt:
-      javascript << gs_lpStrExpFuncName[GREATER];
-      break;
-    case TOKle:
-    case TOKksle:
-      javascript << gs_lpStrExpFuncName[LESSEQUAL];
-      break;
-    case TOKge:
-    case TOKksge:
-      javascript << gs_lpStrExpFuncName[GREATEREQUAL];
-      break;
-    default:
-      NOTREACHED();
-      break;
-  }
-  javascript << L"(";
-  if (!m_pExp1->ToJavaScript(javascript))
-    return false;
-  javascript << L", ";
-  if (!m_pExp2->ToJavaScript(javascript))
-    return false;
-  javascript << L")";
-  return !CXFA_IsTooBig(javascript);
-}
-
-CXFA_FMAdditiveExpression::CXFA_FMAdditiveExpression(
-    uint32_t line,
+CXFA_FMGtExpression::CXFA_FMGtExpression(
     XFA_FM_TOKEN op,
     std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
     std::unique_ptr<CXFA_FMSimpleExpression> pExp2)
-    : CXFA_FMBinExpression(line, op, std::move(pExp1), std::move(pExp2)) {}
+    : CXFA_FMBinExpression(L"gt_op",
+                           op,
+                           std::move(pExp1),
+                           std::move(pExp2)) {}
 
-bool CXFA_FMAdditiveExpression::ToJavaScript(CFX_WideTextBuf& javascript) {
-  CXFA_FMToJavaScriptDepth depthManager;
-  if (CXFA_IsTooBig(javascript) || !depthManager.IsWithinMaxDepth())
-    return false;
-
-  switch (m_op) {
-    case TOKplus:
-      javascript << gs_lpStrExpFuncName[PLUS];
-      break;
-    case TOKminus:
-      javascript << gs_lpStrExpFuncName[MINUS];
-      break;
-    default:
-      NOTREACHED();
-      break;
-  }
-  javascript << L"(";
-  if (!m_pExp1->ToJavaScript(javascript))
-    return false;
-  javascript << L", ";
-  if (!m_pExp2->ToJavaScript(javascript))
-    return false;
-  javascript << L")";
-  return !CXFA_IsTooBig(javascript);
-}
-
-CXFA_FMMultiplicativeExpression::CXFA_FMMultiplicativeExpression(
-    uint32_t line,
+CXFA_FMGeExpression::CXFA_FMGeExpression(
     XFA_FM_TOKEN op,
     std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
     std::unique_ptr<CXFA_FMSimpleExpression> pExp2)
-    : CXFA_FMBinExpression(line, op, std::move(pExp1), std::move(pExp2)) {}
+    : CXFA_FMBinExpression(L"ge_op",
+                           op,
+                           std::move(pExp1),
+                           std::move(pExp2)) {}
 
-bool CXFA_FMMultiplicativeExpression::ToJavaScript(
-    CFX_WideTextBuf& javascript) {
+CXFA_FMLtExpression::CXFA_FMLtExpression(
+    XFA_FM_TOKEN op,
+    std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
+    std::unique_ptr<CXFA_FMSimpleExpression> pExp2)
+    : CXFA_FMBinExpression(L"lt_op",
+                           op,
+                           std::move(pExp1),
+                           std::move(pExp2)) {}
+
+CXFA_FMLeExpression::CXFA_FMLeExpression(
+    XFA_FM_TOKEN op,
+    std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
+    std::unique_ptr<CXFA_FMSimpleExpression> pExp2)
+    : CXFA_FMBinExpression(L"le_op",
+                           op,
+                           std::move(pExp1),
+                           std::move(pExp2)) {}
+
+CXFA_FMPlusExpression::CXFA_FMPlusExpression(
+    XFA_FM_TOKEN op,
+    std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
+    std::unique_ptr<CXFA_FMSimpleExpression> pExp2)
+    : CXFA_FMBinExpression(L"plus_op",
+                           op,
+                           std::move(pExp1),
+                           std::move(pExp2)) {}
+
+CXFA_FMMinusExpression::CXFA_FMMinusExpression(
+    XFA_FM_TOKEN op,
+    std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
+    std::unique_ptr<CXFA_FMSimpleExpression> pExp2)
+    : CXFA_FMBinExpression(L"minus_op",
+                           op,
+                           std::move(pExp1),
+                           std::move(pExp2)) {}
+
+CXFA_FMMulExpression::CXFA_FMMulExpression(
+    XFA_FM_TOKEN op,
+    std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
+    std::unique_ptr<CXFA_FMSimpleExpression> pExp2)
+    : CXFA_FMBinExpression(L"mul_op",
+                           op,
+                           std::move(pExp1),
+                           std::move(pExp2)) {}
+
+CXFA_FMDivExpression::CXFA_FMDivExpression(
+    XFA_FM_TOKEN op,
+    std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
+    std::unique_ptr<CXFA_FMSimpleExpression> pExp2)
+    : CXFA_FMBinExpression(L"div_op",
+                           op,
+                           std::move(pExp1),
+                           std::move(pExp2)) {}
+
+CXFA_FMUnaryExpression::CXFA_FMUnaryExpression(
+    const WideString& opName,
+    XFA_FM_TOKEN op,
+    std::unique_ptr<CXFA_FMSimpleExpression> pExp)
+    : CXFA_FMSimpleExpression(op), m_OpName(opName), m_pExp(std::move(pExp)) {}
+
+CXFA_FMUnaryExpression::~CXFA_FMUnaryExpression() = default;
+
+bool CXFA_FMUnaryExpression::ToJavaScript(CFX_WideTextBuf* js,
+                                          ReturnType type) {
   CXFA_FMToJavaScriptDepth depthManager;
-  if (CXFA_IsTooBig(javascript) || !depthManager.IsWithinMaxDepth())
+  if (CXFA_IsTooBig(js) || !depthManager.IsWithinMaxDepth())
     return false;
 
-  switch (m_op) {
-    case TOKmul:
-      javascript << gs_lpStrExpFuncName[MULTIPLE];
-      break;
-    case TOKdiv:
-      javascript << gs_lpStrExpFuncName[DIVIDE];
-      break;
-    default:
-      NOTREACHED();
-      break;
-  }
-  javascript << L"(";
-  if (!m_pExp1->ToJavaScript(javascript))
+  *js << "pfm_rt." << m_OpName.c_str() << "(";
+  if (!m_pExp->ToJavaScript(js, ReturnType::kInfered))
     return false;
-  javascript << L", ";
-  if (!m_pExp2->ToJavaScript(javascript))
-    return false;
-  javascript << L")";
-  return !CXFA_IsTooBig(javascript);
+  *js << ")";
+  return !CXFA_IsTooBig(js);
 }
 
 CXFA_FMPosExpression::CXFA_FMPosExpression(
-    uint32_t line,
     std::unique_ptr<CXFA_FMSimpleExpression> pExp)
-    : CXFA_FMUnaryExpression(line, TOKplus, std::move(pExp)) {}
-
-bool CXFA_FMPosExpression::ToJavaScript(CFX_WideTextBuf& javascript) {
-  CXFA_FMToJavaScriptDepth depthManager;
-  if (CXFA_IsTooBig(javascript) || !depthManager.IsWithinMaxDepth())
-    return false;
-
-  javascript << gs_lpStrExpFuncName[POSITIVE];
-  javascript << L"(";
-  if (!m_pExp->ToJavaScript(javascript))
-    return false;
-  javascript << L")";
-  return !CXFA_IsTooBig(javascript);
-}
+    : CXFA_FMUnaryExpression(L"pos_op", TOKplus, std::move(pExp)) {}
 
 CXFA_FMNegExpression::CXFA_FMNegExpression(
-    uint32_t line,
     std::unique_ptr<CXFA_FMSimpleExpression> pExp)
-    : CXFA_FMUnaryExpression(line, TOKminus, std::move(pExp)) {}
-
-bool CXFA_FMNegExpression::ToJavaScript(CFX_WideTextBuf& javascript) {
-  CXFA_FMToJavaScriptDepth depthManager;
-  if (CXFA_IsTooBig(javascript) || !depthManager.IsWithinMaxDepth())
-    return false;
-
-  javascript << gs_lpStrExpFuncName[NEGATIVE];
-  javascript << L"(";
-  if (!m_pExp->ToJavaScript(javascript))
-    return false;
-  javascript << L")";
-  return !CXFA_IsTooBig(javascript);
-}
+    : CXFA_FMUnaryExpression(L"neg_op", TOKminus, std::move(pExp)) {}
 
 CXFA_FMNotExpression::CXFA_FMNotExpression(
-    uint32_t line,
     std::unique_ptr<CXFA_FMSimpleExpression> pExp)
-    : CXFA_FMUnaryExpression(line, TOKksnot, std::move(pExp)) {}
-
-bool CXFA_FMNotExpression::ToJavaScript(CFX_WideTextBuf& javascript) {
-  CXFA_FMToJavaScriptDepth depthManager;
-  if (CXFA_IsTooBig(javascript) || !depthManager.IsWithinMaxDepth())
-    return false;
-
-  javascript << gs_lpStrExpFuncName[NOT];
-  javascript << L"(";
-  if (!m_pExp->ToJavaScript(javascript))
-    return false;
-  javascript << L")";
-  return !CXFA_IsTooBig(javascript);
-}
+    : CXFA_FMUnaryExpression(L"log_not_op", TOKksnot, std::move(pExp)) {}
 
 CXFA_FMCallExpression::CXFA_FMCallExpression(
-    uint32_t line,
     std::unique_ptr<CXFA_FMSimpleExpression> pExp,
     std::vector<std::unique_ptr<CXFA_FMSimpleExpression>>&& pArguments,
     bool bIsSomMethod)
-    : CXFA_FMUnaryExpression(line, TOKcall, std::move(pExp)),
+    : CXFA_FMSimpleExpression(TOKcall),
+      m_pExp(std::move(pExp)),
       m_bIsSomMethod(bIsSomMethod),
       m_Arguments(std::move(pArguments)) {}
 
@@ -585,12 +404,12 @@
   if (funcName->GetLength() > g_BuiltInFuncsMaxLen)
     return false;
 
-  auto cmpFunc = [](const wchar_t* iter, const WideString& val) -> bool {
-    return val.CompareNoCase(iter) > 0;
-  };
   WideString str = funcName->MakeString();
   const wchar_t* const* pMatchResult = std::lower_bound(
-      std::begin(g_BuiltInFuncs), std::end(g_BuiltInFuncs), str, cmpFunc);
+      std::begin(g_BuiltInFuncs), std::end(g_BuiltInFuncs), str,
+      [](const wchar_t* iter, const WideString& val) -> bool {
+        return val.CompareNoCase(iter) > 0;
+      });
   if (pMatchResult != std::end(g_BuiltInFuncs) &&
       !str.CompareNoCase(*pMatchResult)) {
     funcName->Clear();
@@ -602,12 +421,11 @@
 
 uint32_t CXFA_FMCallExpression::IsMethodWithObjParam(
     const WideString& methodName) {
-  auto cmpFunc = [](const XFA_FMSOMMethod iter, const WideString& val) {
-    return val.Compare(iter.m_wsSomMethodName) > 0;
-  };
-  const XFA_FMSOMMethod* result =
-      std::lower_bound(std::begin(gs_FMSomMethods), std::end(gs_FMSomMethods),
-                       methodName, cmpFunc);
+  const XFA_FMSOMMethod* result = std::lower_bound(
+      std::begin(gs_FMSomMethods), std::end(gs_FMSomMethods), methodName,
+      [](const XFA_FMSOMMethod iter, const WideString& val) {
+        return val.Compare(iter.m_wsSomMethodName) > 0;
+      });
   if (result != std::end(gs_FMSomMethods) &&
       !methodName.Compare(result->m_wsSomMethodName)) {
     return result->m_dParameters;
@@ -615,280 +433,260 @@
   return 0;
 }
 
-bool CXFA_FMCallExpression::ToJavaScript(CFX_WideTextBuf& javascript) {
+bool CXFA_FMCallExpression::ToJavaScript(CFX_WideTextBuf* js, ReturnType type) {
   CXFA_FMToJavaScriptDepth depthManager;
-  if (CXFA_IsTooBig(javascript) || !depthManager.IsWithinMaxDepth())
+  if (CXFA_IsTooBig(js) || !depthManager.IsWithinMaxDepth())
     return false;
 
   CFX_WideTextBuf funcName;
-  if (!m_pExp->ToJavaScript(funcName))
+  if (!m_pExp->ToJavaScript(&funcName, ReturnType::kInfered))
     return false;
+
   if (m_bIsSomMethod) {
-    javascript << funcName;
-    javascript << L"(";
+    *js << funcName << "(";
     uint32_t methodPara = IsMethodWithObjParam(funcName.MakeString());
     if (methodPara > 0) {
       for (size_t i = 0; i < m_Arguments.size(); ++i) {
         // Currently none of our expressions use objects for a parameter over
         // the 6th. Make sure we don't overflow the shift when doing this
         // check. If we ever need more the 32 object params we can revisit.
-        if (i < 32 && (methodPara & (0x01 << i)) > 0) {
-          javascript << gs_lpStrExpFuncName[GETFMJSOBJ];
-        } else {
-          javascript << gs_lpStrExpFuncName[GETFMVALUE];
-        }
-        javascript << L"(";
-        const auto& expr = m_Arguments[i];
-        if (!expr->ToJavaScript(javascript))
+        *js << "pfm_rt.get_";
+        if (i < 32 && (methodPara & (0x01 << i)) > 0)
+          *js << "jsobj";
+        else
+          *js << "val";
+
+        *js << "(";
+        if (!m_Arguments[i]->ToJavaScript(js, ReturnType::kInfered))
           return false;
-        javascript << L")";
-        if (i + 1 < m_Arguments.size()) {
-          javascript << L", ";
-        }
+        *js << ")";
+        if (i + 1 < m_Arguments.size())
+          *js << ", ";
       }
     } else {
       for (const auto& expr : m_Arguments) {
-        javascript << gs_lpStrExpFuncName[GETFMVALUE];
-        javascript << L"(";
-        if (!expr->ToJavaScript(javascript))
+        *js << "pfm_rt.get_val(";
+        if (!expr->ToJavaScript(js, ReturnType::kInfered))
           return false;
-        javascript << L")";
+        *js << ")";
         if (expr != m_Arguments.back())
-          javascript << L", ";
+          *js << ", ";
       }
     }
-    javascript << L")";
+    *js << ")";
+    return !CXFA_IsTooBig(js);
+  }
+
+  bool isEvalFunc = false;
+  bool isExistsFunc = false;
+  if (!IsBuiltInFunc(&funcName)) {
+    // If a function is not a SomMethod or a built-in then the input was
+    // invalid, so failing. The scanner/lexer should catch this, but currently
+    // doesn't. This failure will bubble up to the top-level and cause the
+    // transpile to fail.
+    return false;
+  }
+
+  if (funcName.AsStringView().EqualsASCII("Eval")) {
+    isEvalFunc = true;
+    *js << "eval.call(this, pfm_rt.Translate";
   } else {
-    bool isEvalFunc = false;
-    bool isExistsFunc = false;
-    if (IsBuiltInFunc(&funcName)) {
-      if (funcName.AsStringView() == L"Eval") {
-        isEvalFunc = true;
-        javascript << L"eval.call(this, ";
-        javascript << gs_lpStrExpFuncName[CALL];
-        javascript << L"Translate";
-      } else if (funcName.AsStringView() == L"Exists") {
-        isExistsFunc = true;
-        javascript << gs_lpStrExpFuncName[CALL];
-        javascript << funcName;
-      } else {
-        javascript << gs_lpStrExpFuncName[CALL];
-        javascript << funcName;
-      }
+    if (funcName.AsStringView().EqualsASCII("Exists"))
+      isExistsFunc = true;
+
+    *js << "pfm_rt." << funcName;
+  }
+
+  *js << "(";
+  if (isExistsFunc) {
+    *js << "\n(\nfunction ()\n{\ntry\n{\n";
+    if (!m_Arguments.empty()) {
+      *js << "return ";
+      if (!m_Arguments[0]->ToJavaScript(js, ReturnType::kInfered))
+        return false;
+      *js << ";\n}\n";
     } else {
-      // If a function is not a SomMethod or a built-in then the input was
-      // invalid, so failing. The scanner/lexer should catch this, but currently
-      // doesn't. This failure will bubble up to the top-level and cause the
-      // transpile to fail.
-      return false;
+      *js << "return 0;\n}\n";
     }
-    javascript << L"(";
-    if (isExistsFunc) {
-      javascript << L"\n(\nfunction ()\n{\ntry\n{\n";
-      if (!m_Arguments.empty()) {
-        const auto& expr = m_Arguments[0];
-        javascript << L"return ";
-        if (!expr->ToJavaScript(javascript))
-          return false;
-        javascript << L";\n}\n";
-      } else {
-        javascript << L"return 0;\n}\n";
-      }
-      javascript << L"catch(accessExceptions)\n";
-      javascript << L"{\nreturn 0;\n}\n}\n).call(this)\n";
-    } else {
-      for (const auto& expr : m_Arguments) {
-        if (!expr->ToJavaScript(javascript))
-          return false;
-        if (expr != m_Arguments.back())
-          javascript << L", ";
-      }
-    }
-    javascript << L")";
-    if (isEvalFunc) {
-      javascript << L")";
+    *js << "catch(accessExceptions)\n";
+    *js << "{\nreturn 0;\n}\n}\n).call(this)\n";
+  } else {
+    for (const auto& expr : m_Arguments) {
+      if (!expr->ToJavaScript(js, ReturnType::kInfered))
+        return false;
+      if (expr != m_Arguments.back())
+        *js << ", ";
     }
   }
-  return !CXFA_IsTooBig(javascript);
+  *js << ")";
+  if (isEvalFunc)
+    *js << ")";
+
+  return !CXFA_IsTooBig(js);
 }
 
 CXFA_FMDotAccessorExpression::CXFA_FMDotAccessorExpression(
-    uint32_t line,
     std::unique_ptr<CXFA_FMSimpleExpression> pAccessor,
     XFA_FM_TOKEN op,
     WideStringView wsIdentifier,
     std::unique_ptr<CXFA_FMSimpleExpression> pIndexExp)
-    : CXFA_FMBinExpression(line,
-                           op,
-                           std::move(pAccessor),
-                           std::move(pIndexExp)),
-      m_wsIdentifier(wsIdentifier) {}
+    : CXFA_FMSimpleExpression(op),
+      m_wsIdentifier(wsIdentifier),
+      m_pExp1(std::move(pAccessor)),
+      m_pExp2(std::move(pIndexExp)) {}
 
-CXFA_FMDotAccessorExpression::~CXFA_FMDotAccessorExpression() {}
+CXFA_FMDotAccessorExpression::~CXFA_FMDotAccessorExpression() = default;
 
-bool CXFA_FMDotAccessorExpression::ToJavaScript(CFX_WideTextBuf& javascript) {
+bool CXFA_FMDotAccessorExpression::ToJavaScript(CFX_WideTextBuf* js,
+                                                ReturnType type) {
   CXFA_FMToJavaScriptDepth depthManager;
-  if (CXFA_IsTooBig(javascript) || !depthManager.IsWithinMaxDepth())
+  if (CXFA_IsTooBig(js) || !depthManager.IsWithinMaxDepth())
     return false;
 
-  javascript << gs_lpStrExpFuncName[DOT];
-  javascript << L"(";
+  *js << "pfm_rt.dot_acc(";
+
   CFX_WideTextBuf tempExp1;
   if (m_pExp1) {
-    if (!m_pExp1->ToJavaScript(tempExp1))
+    if (!m_pExp1->ToJavaScript(&tempExp1, ReturnType::kInfered))
       return false;
-    javascript << tempExp1;
+
+    *js << tempExp1;
   } else {
-    javascript << L"null";
+    *js << "null";
   }
-  javascript << L", ";
-  javascript << L"\"";
+  *js << ", \"";
 
   if (m_pExp1 && m_pExp1->GetOperatorToken() == TOKidentifier)
-    javascript << tempExp1;
-  javascript << L"\", ";
-  if (m_op == TOKdotscream) {
-    javascript << L"\"#";
-    javascript << m_wsIdentifier;
-    javascript << L"\", ";
-  } else if (m_op == TOKdotstar) {
-    javascript << L"\"*\", ";
-  } else if (m_op == TOKcall) {
-    javascript << L"\"\", ";
-  } else {
-    javascript << L"\"";
-    javascript << m_wsIdentifier;
-    javascript << L"\", ";
-  }
-  if (!m_pExp2->ToJavaScript(javascript))
+    *js << tempExp1;
+
+  *js << "\", ";
+  if (m_op == TOKdotscream)
+    *js << "\"#" << m_wsIdentifier << "\", ";
+  else if (m_op == TOKdotstar)
+    *js << "\"*\", ";
+  else if (m_op == TOKcall)
+    *js << "\"\", ";
+  else
+    *js << "\"" << m_wsIdentifier << "\", ";
+
+  if (!m_pExp2->ToJavaScript(js, ReturnType::kInfered))
     return false;
-  javascript << L")";
-  return !CXFA_IsTooBig(javascript);
+
+  *js << ")";
+  return !CXFA_IsTooBig(js);
 }
 
 CXFA_FMIndexExpression::CXFA_FMIndexExpression(
-    uint32_t line,
     XFA_FM_AccessorIndex accessorIndex,
     std::unique_ptr<CXFA_FMSimpleExpression> pIndexExp,
     bool bIsStarIndex)
-    : CXFA_FMUnaryExpression(line, TOKlbracket, std::move(pIndexExp)),
+    : CXFA_FMSimpleExpression(TOKlbracket),
+      m_pExp(std::move(pIndexExp)),
       m_accessorIndex(accessorIndex),
       m_bIsStarIndex(bIsStarIndex) {}
 
-bool CXFA_FMIndexExpression::ToJavaScript(CFX_WideTextBuf& javascript) {
+CXFA_FMIndexExpression::~CXFA_FMIndexExpression() = default;
+
+bool CXFA_FMIndexExpression::ToJavaScript(CFX_WideTextBuf* js,
+                                          ReturnType type) {
   CXFA_FMToJavaScriptDepth depthManager;
-  if (CXFA_IsTooBig(javascript) || !depthManager.IsWithinMaxDepth())
+  if (CXFA_IsTooBig(js) || !depthManager.IsWithinMaxDepth())
     return false;
 
   switch (m_accessorIndex) {
     case ACCESSOR_NO_INDEX:
-      javascript << L"0";
+      *js << "0";
       break;
     case ACCESSOR_NO_RELATIVEINDEX:
-      javascript << L"1";
+      *js << "1";
       break;
     case ACCESSOR_POSITIVE_INDEX:
-      javascript << L"2";
+      *js << "2";
       break;
     case ACCESSOR_NEGATIVE_INDEX:
-      javascript << L"3";
+      *js << "3";
       break;
     default:
-      javascript << L"0";
+      *js << "0";
   }
-  if (!m_bIsStarIndex) {
-    javascript << L", ";
-    if (m_pExp) {
-      if (!m_pExp->ToJavaScript(javascript))
-        return false;
-    } else {
-      javascript << L"0";
-    }
+  if (m_bIsStarIndex)
+    return !CXFA_IsTooBig(js);
+
+  *js << ", ";
+  if (m_pExp) {
+    if (!m_pExp->ToJavaScript(js, ReturnType::kInfered))
+      return false;
+  } else {
+    *js << "0";
   }
-  return !CXFA_IsTooBig(javascript);
+  return !CXFA_IsTooBig(js);
 }
 
 CXFA_FMDotDotAccessorExpression::CXFA_FMDotDotAccessorExpression(
-    uint32_t line,
     std::unique_ptr<CXFA_FMSimpleExpression> pAccessor,
     XFA_FM_TOKEN op,
     WideStringView wsIdentifier,
     std::unique_ptr<CXFA_FMSimpleExpression> pIndexExp)
-    : CXFA_FMBinExpression(line,
-                           op,
-                           std::move(pAccessor),
-                           std::move(pIndexExp)),
-      m_wsIdentifier(wsIdentifier) {}
+    : CXFA_FMSimpleExpression(op),
+      m_wsIdentifier(wsIdentifier),
+      m_pExp1(std::move(pAccessor)),
+      m_pExp2(std::move(pIndexExp)) {}
 
-CXFA_FMDotDotAccessorExpression::~CXFA_FMDotDotAccessorExpression() {}
+CXFA_FMDotDotAccessorExpression::~CXFA_FMDotDotAccessorExpression() = default;
 
-bool CXFA_FMDotDotAccessorExpression::ToJavaScript(
-    CFX_WideTextBuf& javascript) {
+bool CXFA_FMDotDotAccessorExpression::ToJavaScript(CFX_WideTextBuf* js,
+                                                   ReturnType type) {
   CXFA_FMToJavaScriptDepth depthManager;
-  if (CXFA_IsTooBig(javascript) || !depthManager.IsWithinMaxDepth())
+  if (CXFA_IsTooBig(js) || !depthManager.IsWithinMaxDepth())
     return false;
 
-  javascript << gs_lpStrExpFuncName[DOTDOT];
-  javascript << L"(";
-  CFX_WideTextBuf tempExp1;
-  if (!m_pExp1->ToJavaScript(tempExp1))
+  *js << "pfm_rt.dotdot_acc(";
+  if (!m_pExp1->ToJavaScript(js, ReturnType::kInfered))
     return false;
-  javascript << tempExp1;
-  javascript << L", ";
-  javascript << L"\"";
+  *js << ", "
+      << "\"";
+  if (m_pExp1->GetOperatorToken() == TOKidentifier) {
+    if (!m_pExp1->ToJavaScript(js, ReturnType::kInfered))
+      return false;
+  }
 
-  if (m_pExp1->GetOperatorToken() == TOKidentifier)
-    javascript << tempExp1;
-  javascript << L"\", ";
-  javascript << L"\"";
-  javascript << m_wsIdentifier;
-  javascript << L"\", ";
-  if (!m_pExp2->ToJavaScript(javascript))
+  *js << "\", \"" << m_wsIdentifier << "\", ";
+  if (!m_pExp2->ToJavaScript(js, ReturnType::kInfered))
     return false;
-  javascript << L")";
-  return !CXFA_IsTooBig(javascript);
+  *js << ")";
+  return !CXFA_IsTooBig(js);
 }
 
 CXFA_FMMethodCallExpression::CXFA_FMMethodCallExpression(
-    uint32_t line,
     std::unique_ptr<CXFA_FMSimpleExpression> pAccessorExp1,
     std::unique_ptr<CXFA_FMSimpleExpression> pCallExp)
-    : CXFA_FMBinExpression(line,
-                           TOKdot,
-                           std::move(pAccessorExp1),
-                           std::move(pCallExp)) {}
+    : CXFA_FMSimpleExpression(TOKdot),
+      m_pExp1(std::move(pAccessorExp1)),
+      m_pExp2(std::move(pCallExp)) {}
 
-bool CXFA_FMMethodCallExpression::ToJavaScript(CFX_WideTextBuf& javascript) {
+CXFA_FMMethodCallExpression::~CXFA_FMMethodCallExpression() = default;
+
+bool CXFA_FMMethodCallExpression::ToJavaScript(CFX_WideTextBuf* js,
+                                               ReturnType type) {
   CXFA_FMToJavaScriptDepth depthManager;
-  if (CXFA_IsTooBig(javascript) || !depthManager.IsWithinMaxDepth())
+  if (CXFA_IsTooBig(js) || !depthManager.IsWithinMaxDepth())
     return false;
 
-  javascript << L"(\nfunction ()\n{\n";
-  javascript << L"var method_return_value = null;\n";
-  javascript << L"var accessor_object = ";
-  if (!m_pExp1->ToJavaScript(javascript))
+  CFX_WideTextBuf buf;
+  if (!m_pExp1->ToJavaScript(&buf, ReturnType::kInfered))
     return false;
-  javascript << L";\n";
-  javascript << L"if (";
-  javascript << gs_lpStrExpFuncName[ISFMARRAY];
-  javascript << L"(accessor_object))\n{\n";
-  javascript << L"for(var index = accessor_object.length - 1; index > 1; "
-                L"index--)\n{\n";
-  javascript << L"method_return_value = accessor_object[index].";
 
-  CFX_WideTextBuf tempExp2;
-  if (!m_pExp2->ToJavaScript(tempExp2))
+  *js << "(function() {\n";
+  *js << "  return pfm_method_runner(" << buf << ", function(obj) {\n";
+  *js << "    return obj.";
+  if (!m_pExp2->ToJavaScript(js, ReturnType::kInfered))
     return false;
-  javascript << tempExp2;
-  javascript << L";\n}\n}\n";
-  javascript << L"else\n{\nmethod_return_value = accessor_object.";
-  javascript << tempExp2;
-  javascript << L";\n}\n";
-  javascript << L"return method_return_value;\n";
-  javascript << L"}\n).call(this)";
-  return !CXFA_IsTooBig(javascript);
+  *js << ";\n";
+  *js << "  });\n";
+  *js << "}).call(this)";
+  return !CXFA_IsTooBig(js);
 }
 
-bool CXFA_IsTooBig(const CFX_WideTextBuf& javascript) {
-  return javascript.GetSize() >= 256 * 1024 * 1024;
+bool CXFA_IsTooBig(const CFX_WideTextBuf* js) {
+  return js->GetSize() >= 256 * 1024 * 1024;
 }
diff --git a/xfa/fxfa/fm2js/cxfa_fmsimpleexpression.h b/xfa/fxfa/fm2js/cxfa_fmsimpleexpression.h
index 440b154..ae8f38e 100644
--- a/xfa/fxfa/fm2js/cxfa_fmsimpleexpression.h
+++ b/xfa/fxfa/fm2js/cxfa_fmsimpleexpression.h
@@ -12,42 +12,6 @@
 
 #include "xfa/fxfa/fm2js/cxfa_fmlexer.h"
 
-#define RUNTIMEFUNCTIONRETURNVALUE L"pfm_ret"
-#define EXCLAMATION_IN_IDENTIFIER L"pfm__excl__"
-
-enum XFA_FM_SimpleExpressionType {
-  ASSIGN,
-  LOGICALOR,
-  LOGICALAND,
-  EQUALITY,
-  NOTEQUALITY,
-  LESS,
-  LESSEQUAL,
-  GREATER,
-  GREATEREQUAL,
-  PLUS,
-  MINUS,
-  MULTIPLE,
-  DIVIDE,
-  POSITIVE,
-  NEGATIVE,
-  NOT,
-  CALL,
-  DOT,
-  DOTDOT,
-  CONCATFMOBJECT,
-  ISFMOBJECT,
-  ISFMARRAY,
-  GETFMVALUE,
-  GETFMJSOBJ,
-  VARFILTER
-};
-
-class CFX_WideTextBuf;
-
-WideStringView XFA_FM_EXPTypeToString(
-    XFA_FM_SimpleExpressionType simpleExpType);
-
 enum XFA_FM_AccessorIndex {
   ACCESSOR_NO_INDEX,
   ACCESSOR_NO_RELATIVEINDEX,
@@ -55,185 +19,229 @@
   ACCESSOR_NEGATIVE_INDEX
 };
 
+enum class ReturnType { kImplied, kInfered };
+
+class CFX_WideTextBuf;
+
 class CXFA_FMSimpleExpression {
  public:
-  CXFA_FMSimpleExpression(uint32_t line, XFA_FM_TOKEN op);
-  virtual ~CXFA_FMSimpleExpression() {}
-  virtual bool ToJavaScript(CFX_WideTextBuf& javascript);
-  virtual bool ToImpliedReturnJS(CFX_WideTextBuf& javascript);
+  virtual ~CXFA_FMSimpleExpression() = default;
+  virtual bool ToJavaScript(CFX_WideTextBuf* js, ReturnType type) = 0;
 
   XFA_FM_TOKEN GetOperatorToken() const;
 
  protected:
-  uint32_t m_line;
+  explicit CXFA_FMSimpleExpression(XFA_FM_TOKEN op);
+
   const XFA_FM_TOKEN m_op;
 };
 
-class CXFA_FMNullExpression : public CXFA_FMSimpleExpression {
+class CXFA_FMNullExpression final : public CXFA_FMSimpleExpression {
  public:
-  explicit CXFA_FMNullExpression(uint32_t line);
+  CXFA_FMNullExpression();
   ~CXFA_FMNullExpression() override {}
-  bool ToJavaScript(CFX_WideTextBuf& javascript) override;
+
+  bool ToJavaScript(CFX_WideTextBuf* js, ReturnType type) override;
 };
 
-class CXFA_FMNumberExpression : public CXFA_FMSimpleExpression {
+class CXFA_FMNumberExpression final : public CXFA_FMSimpleExpression {
  public:
-  CXFA_FMNumberExpression(uint32_t line, WideStringView wsNumber);
+  explicit CXFA_FMNumberExpression(WideStringView wsNumber);
   ~CXFA_FMNumberExpression() override;
-  bool ToJavaScript(CFX_WideTextBuf& javascript) override;
+
+  bool ToJavaScript(CFX_WideTextBuf* js, ReturnType type) override;
 
  private:
   WideStringView m_wsNumber;
 };
 
-class CXFA_FMStringExpression : public CXFA_FMSimpleExpression {
+class CXFA_FMStringExpression final : public CXFA_FMSimpleExpression {
  public:
-  CXFA_FMStringExpression(uint32_t line, WideStringView wsString);
+  explicit CXFA_FMStringExpression(WideStringView wsString);
   ~CXFA_FMStringExpression() override;
-  bool ToJavaScript(CFX_WideTextBuf& javascript) override;
+
+  bool ToJavaScript(CFX_WideTextBuf* js, ReturnType type) override;
 
  private:
   WideStringView m_wsString;
 };
 
-class CXFA_FMIdentifierExpression : public CXFA_FMSimpleExpression {
+class CXFA_FMIdentifierExpression final : public CXFA_FMSimpleExpression {
  public:
-  CXFA_FMIdentifierExpression(uint32_t line, WideStringView wsIdentifier);
+  explicit CXFA_FMIdentifierExpression(WideStringView wsIdentifier);
   ~CXFA_FMIdentifierExpression() override;
-  bool ToJavaScript(CFX_WideTextBuf& javascript) override;
+
+  bool ToJavaScript(CFX_WideTextBuf* js, ReturnType type) override;
 
  private:
   WideStringView m_wsIdentifier;
 };
 
-class CXFA_FMUnaryExpression : public CXFA_FMSimpleExpression {
+class CXFA_FMAssignExpression final : public CXFA_FMSimpleExpression {
  public:
-  CXFA_FMUnaryExpression(uint32_t line,
-                         XFA_FM_TOKEN op,
-                         std::unique_ptr<CXFA_FMSimpleExpression> pExp);
-  ~CXFA_FMUnaryExpression() override;
+  CXFA_FMAssignExpression(XFA_FM_TOKEN op,
+                          std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
+                          std::unique_ptr<CXFA_FMSimpleExpression> pExp2);
+  ~CXFA_FMAssignExpression() override;
 
-  bool ToJavaScript(CFX_WideTextBuf& javascript) override;
+  bool ToJavaScript(CFX_WideTextBuf* js, ReturnType type) override;
 
- protected:
-  std::unique_ptr<CXFA_FMSimpleExpression> m_pExp;
-};
-
-class CXFA_FMBinExpression : public CXFA_FMSimpleExpression {
- public:
-  CXFA_FMBinExpression(uint32_t line,
-                       XFA_FM_TOKEN op,
-                       std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
-                       std::unique_ptr<CXFA_FMSimpleExpression> pExp2);
-  ~CXFA_FMBinExpression() override;
-
-  bool ToJavaScript(CFX_WideTextBuf& javascript) override;
-
- protected:
+ private:
   std::unique_ptr<CXFA_FMSimpleExpression> m_pExp1;
   std::unique_ptr<CXFA_FMSimpleExpression> m_pExp2;
 };
 
-class CXFA_FMAssignExpression : public CXFA_FMBinExpression {
+class CXFA_FMBinExpression : public CXFA_FMSimpleExpression {
  public:
-  CXFA_FMAssignExpression(uint32_t line,
-                          XFA_FM_TOKEN op,
-                          std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
-                          std::unique_ptr<CXFA_FMSimpleExpression> pExp2);
-  ~CXFA_FMAssignExpression() override {}
-  bool ToJavaScript(CFX_WideTextBuf& javascript) override;
-  bool ToImpliedReturnJS(CFX_WideTextBuf& javascript) override;
+  ~CXFA_FMBinExpression() override;
+
+  bool ToJavaScript(CFX_WideTextBuf* js, ReturnType type) override;
+
+ protected:
+  CXFA_FMBinExpression(const WideString& opName,
+                       XFA_FM_TOKEN op,
+                       std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
+                       std::unique_ptr<CXFA_FMSimpleExpression> pExp2);
+
+ private:
+  WideString m_OpName;
+  std::unique_ptr<CXFA_FMSimpleExpression> m_pExp1;
+  std::unique_ptr<CXFA_FMSimpleExpression> m_pExp2;
 };
 
-class CXFA_FMLogicalOrExpression : public CXFA_FMBinExpression {
+class CXFA_FMLogicalOrExpression final : public CXFA_FMBinExpression {
  public:
-  CXFA_FMLogicalOrExpression(uint32_t line,
-                             XFA_FM_TOKEN op,
+  CXFA_FMLogicalOrExpression(XFA_FM_TOKEN op,
                              std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
                              std::unique_ptr<CXFA_FMSimpleExpression> pExp2);
   ~CXFA_FMLogicalOrExpression() override {}
-  bool ToJavaScript(CFX_WideTextBuf& javascript) override;
 };
 
-class CXFA_FMLogicalAndExpression : public CXFA_FMBinExpression {
+class CXFA_FMLogicalAndExpression final : public CXFA_FMBinExpression {
  public:
-  CXFA_FMLogicalAndExpression(uint32_t line,
-                              XFA_FM_TOKEN op,
+  CXFA_FMLogicalAndExpression(XFA_FM_TOKEN op,
                               std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
                               std::unique_ptr<CXFA_FMSimpleExpression> pExp2);
   ~CXFA_FMLogicalAndExpression() override {}
-  bool ToJavaScript(CFX_WideTextBuf& javascript) override;
 };
 
-class CXFA_FMEqualityExpression : public CXFA_FMBinExpression {
+class CXFA_FMEqualExpression final : public CXFA_FMBinExpression {
  public:
-  CXFA_FMEqualityExpression(uint32_t line,
-                            XFA_FM_TOKEN op,
+  CXFA_FMEqualExpression(XFA_FM_TOKEN op,
+                         std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
+                         std::unique_ptr<CXFA_FMSimpleExpression> pExp2);
+  ~CXFA_FMEqualExpression() override {}
+};
+
+class CXFA_FMNotEqualExpression final : public CXFA_FMBinExpression {
+ public:
+  CXFA_FMNotEqualExpression(XFA_FM_TOKEN op,
                             std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
                             std::unique_ptr<CXFA_FMSimpleExpression> pExp2);
-  ~CXFA_FMEqualityExpression() override {}
-  bool ToJavaScript(CFX_WideTextBuf& javascript) override;
+  ~CXFA_FMNotEqualExpression() override {}
 };
 
-class CXFA_FMRelationalExpression : public CXFA_FMBinExpression {
+class CXFA_FMGtExpression final : public CXFA_FMBinExpression {
  public:
-  CXFA_FMRelationalExpression(uint32_t line,
-                              XFA_FM_TOKEN op,
-                              std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
-                              std::unique_ptr<CXFA_FMSimpleExpression> pExp2);
-  ~CXFA_FMRelationalExpression() override {}
-  bool ToJavaScript(CFX_WideTextBuf& javascript) override;
+  CXFA_FMGtExpression(XFA_FM_TOKEN op,
+                      std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
+                      std::unique_ptr<CXFA_FMSimpleExpression> pExp2);
+  ~CXFA_FMGtExpression() override {}
 };
 
-class CXFA_FMAdditiveExpression : public CXFA_FMBinExpression {
+class CXFA_FMGeExpression final : public CXFA_FMBinExpression {
  public:
-  CXFA_FMAdditiveExpression(uint32_t line,
-                            XFA_FM_TOKEN op,
-                            std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
-                            std::unique_ptr<CXFA_FMSimpleExpression> pExp2);
-  ~CXFA_FMAdditiveExpression() override {}
-  bool ToJavaScript(CFX_WideTextBuf& javascript) override;
+  CXFA_FMGeExpression(XFA_FM_TOKEN op,
+                      std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
+                      std::unique_ptr<CXFA_FMSimpleExpression> pExp2);
+  ~CXFA_FMGeExpression() override {}
 };
 
-class CXFA_FMMultiplicativeExpression : public CXFA_FMBinExpression {
+class CXFA_FMLtExpression final : public CXFA_FMBinExpression {
  public:
-  CXFA_FMMultiplicativeExpression(
-      uint32_t line,
-      XFA_FM_TOKEN op,
-      std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
-      std::unique_ptr<CXFA_FMSimpleExpression> pExp2);
-  ~CXFA_FMMultiplicativeExpression() override {}
-  bool ToJavaScript(CFX_WideTextBuf& javascript) override;
+  CXFA_FMLtExpression(XFA_FM_TOKEN op,
+                      std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
+                      std::unique_ptr<CXFA_FMSimpleExpression> pExp2);
+  ~CXFA_FMLtExpression() override {}
 };
 
-class CXFA_FMPosExpression : public CXFA_FMUnaryExpression {
+class CXFA_FMLeExpression final : public CXFA_FMBinExpression {
  public:
-  CXFA_FMPosExpression(uint32_t line,
-                       std::unique_ptr<CXFA_FMSimpleExpression> pExp);
+  CXFA_FMLeExpression(XFA_FM_TOKEN op,
+                      std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
+                      std::unique_ptr<CXFA_FMSimpleExpression> pExp2);
+  ~CXFA_FMLeExpression() override {}
+};
+
+class CXFA_FMPlusExpression final : public CXFA_FMBinExpression {
+ public:
+  CXFA_FMPlusExpression(XFA_FM_TOKEN op,
+                        std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
+                        std::unique_ptr<CXFA_FMSimpleExpression> pExp2);
+  ~CXFA_FMPlusExpression() override {}
+};
+
+class CXFA_FMMinusExpression final : public CXFA_FMBinExpression {
+ public:
+  CXFA_FMMinusExpression(XFA_FM_TOKEN op,
+                         std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
+                         std::unique_ptr<CXFA_FMSimpleExpression> pExp2);
+  ~CXFA_FMMinusExpression() override {}
+};
+
+class CXFA_FMMulExpression final : public CXFA_FMBinExpression {
+ public:
+  CXFA_FMMulExpression(XFA_FM_TOKEN op,
+                       std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
+                       std::unique_ptr<CXFA_FMSimpleExpression> pExp2);
+  ~CXFA_FMMulExpression() override {}
+};
+
+class CXFA_FMDivExpression final : public CXFA_FMBinExpression {
+ public:
+  CXFA_FMDivExpression(XFA_FM_TOKEN op,
+                       std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
+                       std::unique_ptr<CXFA_FMSimpleExpression> pExp2);
+  ~CXFA_FMDivExpression() override {}
+};
+
+class CXFA_FMUnaryExpression : public CXFA_FMSimpleExpression {
+ public:
+  ~CXFA_FMUnaryExpression() override;
+
+  bool ToJavaScript(CFX_WideTextBuf* js, ReturnType type) override;
+
+ protected:
+  CXFA_FMUnaryExpression(const WideString& opName,
+                         XFA_FM_TOKEN op,
+                         std::unique_ptr<CXFA_FMSimpleExpression> pExp);
+
+ private:
+  WideString m_OpName;
+  std::unique_ptr<CXFA_FMSimpleExpression> m_pExp;
+};
+
+class CXFA_FMPosExpression final : public CXFA_FMUnaryExpression {
+ public:
+  explicit CXFA_FMPosExpression(std::unique_ptr<CXFA_FMSimpleExpression> pExp);
   ~CXFA_FMPosExpression() override {}
-  bool ToJavaScript(CFX_WideTextBuf& javascript) override;
 };
 
-class CXFA_FMNegExpression : public CXFA_FMUnaryExpression {
+class CXFA_FMNegExpression final : public CXFA_FMUnaryExpression {
  public:
-  CXFA_FMNegExpression(uint32_t line,
-                       std::unique_ptr<CXFA_FMSimpleExpression> pExp);
+  explicit CXFA_FMNegExpression(std::unique_ptr<CXFA_FMSimpleExpression> pExp);
   ~CXFA_FMNegExpression() override {}
-  bool ToJavaScript(CFX_WideTextBuf& javascript) override;
 };
 
-class CXFA_FMNotExpression : public CXFA_FMUnaryExpression {
+class CXFA_FMNotExpression final : public CXFA_FMUnaryExpression {
  public:
-  CXFA_FMNotExpression(uint32_t line,
-                       std::unique_ptr<CXFA_FMSimpleExpression> pExp);
+  explicit CXFA_FMNotExpression(std::unique_ptr<CXFA_FMSimpleExpression> pExp);
   ~CXFA_FMNotExpression() override {}
-  bool ToJavaScript(CFX_WideTextBuf& javascript) override;
 };
 
-class CXFA_FMCallExpression : public CXFA_FMUnaryExpression {
+class CXFA_FMCallExpression final : public CXFA_FMSimpleExpression {
  public:
   CXFA_FMCallExpression(
-      uint32_t line,
       std::unique_ptr<CXFA_FMSimpleExpression> pExp,
       std::vector<std::unique_ptr<CXFA_FMSimpleExpression>>&& pArguments,
       bool bIsSomMethod);
@@ -241,68 +249,77 @@
 
   bool IsBuiltInFunc(CFX_WideTextBuf* funcName);
   uint32_t IsMethodWithObjParam(const WideString& methodName);
-  bool ToJavaScript(CFX_WideTextBuf& javascript) override;
+  bool ToJavaScript(CFX_WideTextBuf* js, ReturnType type) override;
 
  private:
+  std::unique_ptr<CXFA_FMSimpleExpression> m_pExp;
   bool m_bIsSomMethod;
   std::vector<std::unique_ptr<CXFA_FMSimpleExpression>> m_Arguments;
 };
 
-class CXFA_FMDotAccessorExpression : public CXFA_FMBinExpression {
+class CXFA_FMDotAccessorExpression final : public CXFA_FMSimpleExpression {
  public:
   CXFA_FMDotAccessorExpression(
-      uint32_t line,
       std::unique_ptr<CXFA_FMSimpleExpression> pAccessor,
       XFA_FM_TOKEN op,
       WideStringView wsIdentifier,
       std::unique_ptr<CXFA_FMSimpleExpression> pIndexExp);
   ~CXFA_FMDotAccessorExpression() override;
-  bool ToJavaScript(CFX_WideTextBuf& javascript) override;
+
+  bool ToJavaScript(CFX_WideTextBuf* js, ReturnType type) override;
 
  private:
   WideStringView m_wsIdentifier;
+  std::unique_ptr<CXFA_FMSimpleExpression> m_pExp1;
+  std::unique_ptr<CXFA_FMSimpleExpression> m_pExp2;
 };
 
-class CXFA_FMIndexExpression : public CXFA_FMUnaryExpression {
+class CXFA_FMIndexExpression final : public CXFA_FMSimpleExpression {
  public:
-  CXFA_FMIndexExpression(uint32_t line,
-                         XFA_FM_AccessorIndex accessorIndex,
+  CXFA_FMIndexExpression(XFA_FM_AccessorIndex accessorIndex,
                          std::unique_ptr<CXFA_FMSimpleExpression> pIndexExp,
                          bool bIsStarIndex);
-  ~CXFA_FMIndexExpression() override {}
-  bool ToJavaScript(CFX_WideTextBuf& javascript) override;
+  ~CXFA_FMIndexExpression() override;
+
+  bool ToJavaScript(CFX_WideTextBuf* js, ReturnType type) override;
 
  private:
+  std::unique_ptr<CXFA_FMSimpleExpression> m_pExp;
   XFA_FM_AccessorIndex m_accessorIndex;
   bool m_bIsStarIndex;
 };
 
-class CXFA_FMDotDotAccessorExpression : public CXFA_FMBinExpression {
+class CXFA_FMDotDotAccessorExpression final : public CXFA_FMSimpleExpression {
  public:
   CXFA_FMDotDotAccessorExpression(
-      uint32_t line,
       std::unique_ptr<CXFA_FMSimpleExpression> pAccessor,
       XFA_FM_TOKEN op,
       WideStringView wsIdentifier,
       std::unique_ptr<CXFA_FMSimpleExpression> pIndexExp);
   ~CXFA_FMDotDotAccessorExpression() override;
 
-  bool ToJavaScript(CFX_WideTextBuf& javascript) override;
+  bool ToJavaScript(CFX_WideTextBuf* js, ReturnType type) override;
 
  private:
   WideStringView m_wsIdentifier;
+  std::unique_ptr<CXFA_FMSimpleExpression> m_pExp1;
+  std::unique_ptr<CXFA_FMSimpleExpression> m_pExp2;
 };
 
-class CXFA_FMMethodCallExpression : public CXFA_FMBinExpression {
+class CXFA_FMMethodCallExpression final : public CXFA_FMSimpleExpression {
  public:
   CXFA_FMMethodCallExpression(
-      uint32_t line,
       std::unique_ptr<CXFA_FMSimpleExpression> pAccessorExp1,
       std::unique_ptr<CXFA_FMSimpleExpression> pCallExp);
-  ~CXFA_FMMethodCallExpression() override {}
-  bool ToJavaScript(CFX_WideTextBuf& javascript) override;
+  ~CXFA_FMMethodCallExpression() override;
+
+  bool ToJavaScript(CFX_WideTextBuf* js, ReturnType type) override;
+
+ private:
+  std::unique_ptr<CXFA_FMSimpleExpression> m_pExp1;
+  std::unique_ptr<CXFA_FMSimpleExpression> m_pExp2;
 };
 
-bool CXFA_IsTooBig(const CFX_WideTextBuf& javascript);
+bool CXFA_IsTooBig(const CFX_WideTextBuf* js);
 
 #endif  // XFA_FXFA_FM2JS_CXFA_FMSIMPLEEXPRESSION_H_
diff --git a/xfa/fxfa/fm2js/cxfa_fmsimpleexpression_unittest.cpp b/xfa/fxfa/fm2js/cxfa_fmsimpleexpression_unittest.cpp
index 96ccb71..198087c 100644
--- a/xfa/fxfa/fm2js/cxfa_fmsimpleexpression_unittest.cpp
+++ b/xfa/fxfa/fm2js/cxfa_fmsimpleexpression_unittest.cpp
@@ -10,23 +10,23 @@
 #include "core/fxcrt/cfx_widetextbuf.h"
 #include "core/fxcrt/fx_string.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "testing/test_support.h"
 #include "third_party/base/ptr_util.h"
 #include "xfa/fxfa/fm2js/cxfa_fmlexer.h"
 #include "xfa/fxfa/fm2js/cxfa_fmtojavascriptdepth.h"
 
 TEST(FMCallExpressionTest, more_than_32_arguments) {
   // Use sign as it has 3 object parameters at positions 0, 5, and 6.
-  auto exp = pdfium::MakeUnique<CXFA_FMIdentifierExpression>(0, L"sign");
+  auto exp = pdfium::MakeUnique<CXFA_FMIdentifierExpression>(L"sign");
 
   std::vector<std::unique_ptr<CXFA_FMSimpleExpression>> args;
   for (size_t i = 0; i < 50; i++)
-    args.push_back(pdfium::MakeUnique<CXFA_FMSimpleExpression>(0, TOKnan));
+    args.push_back(pdfium::MakeUnique<CXFA_FMNullExpression>());
 
   CXFA_FMToJavaScriptDepth::Reset();
-  CXFA_FMCallExpression callExp(0, std::move(exp), std::move(args), true);
+  CXFA_FMCallExpression callExp(std::move(exp), std::move(args), true);
+
   CFX_WideTextBuf js;
-  callExp.ToJavaScript(js);
+  callExp.ToJavaScript(&js, ReturnType::kInfered);
 
   // Generate the result javascript string.
   WideString result = L"sign(";
@@ -37,9 +37,9 @@
     result += L"pfm_rt.get_";
     // Object positions for sign() method.
     if (i == 0 || i == 5 || i == 6)
-      result += L"jsobj()";
+      result += L"jsobj(null)";
     else
-      result += L"val()";
+      result += L"val(null)";
   }
   result += L")";
 
@@ -49,21 +49,23 @@
 TEST(FMStringExpressionTest, Empty) {
   CXFA_FMToJavaScriptDepth::Reset();
   CFX_WideTextBuf accumulator;
-  CXFA_FMStringExpression(1, WideStringView()).ToJavaScript(accumulator);
+  CXFA_FMStringExpression(L"").ToJavaScript(&accumulator, ReturnType::kInfered);
   EXPECT_EQ(L"", accumulator.AsStringView());
 }
 
 TEST(FMStringExpressionTest, Short) {
   CXFA_FMToJavaScriptDepth::Reset();
   CFX_WideTextBuf accumulator;
-  CXFA_FMStringExpression(1, L"a").ToJavaScript(accumulator);
+  CXFA_FMStringExpression(L"a").ToJavaScript(&accumulator,
+                                             ReturnType::kInfered);
   EXPECT_EQ(L"a", accumulator.AsStringView());
 }
 
 TEST(FMStringExpressionTest, Medium) {
   CXFA_FMToJavaScriptDepth::Reset();
   CFX_WideTextBuf accumulator;
-  CXFA_FMStringExpression(1, L".abcd.").ToJavaScript(accumulator);
+  CXFA_FMStringExpression(L".abcd.").ToJavaScript(&accumulator,
+                                                  ReturnType::kInfered);
   EXPECT_EQ(L"\"abcd\"", accumulator.AsStringView());
 }
 
@@ -71,14 +73,15 @@
   CXFA_FMToJavaScriptDepth::Reset();
   CFX_WideTextBuf accumulator;
   std::vector<WideStringView::UnsignedType> vec(140000, L'A');
-  CXFA_FMStringExpression(1, WideStringView(vec)).ToJavaScript(accumulator);
+  CXFA_FMStringExpression(WideStringView(vec))
+      .ToJavaScript(&accumulator, ReturnType::kInfered);
   EXPECT_EQ(140000u, accumulator.GetLength());
 }
 
 TEST(FMStringExpressionTest, Quoted) {
   CXFA_FMToJavaScriptDepth::Reset();
   CFX_WideTextBuf accumulator;
-  CXFA_FMStringExpression(1, L".Simon says \"\"run\"\".")
-      .ToJavaScript(accumulator);
+  CXFA_FMStringExpression(L".Simon says \"\"run\"\".")
+      .ToJavaScript(&accumulator, ReturnType::kInfered);
   EXPECT_EQ(L"\"Simon says \\\"run\\\"\"", accumulator.AsStringView());
 }
diff --git a/xfa/fxfa/fm2js/cxfa_fmtojavascriptdepth.cpp b/xfa/fxfa/fm2js/cxfa_fmtojavascriptdepth.cpp
index 6312ba6..023516b 100644
--- a/xfa/fxfa/fm2js/cxfa_fmtojavascriptdepth.cpp
+++ b/xfa/fxfa/fm2js/cxfa_fmtojavascriptdepth.cpp
@@ -4,17 +4,7 @@
 
 #include "xfa/fxfa/fm2js/cxfa_fmtojavascriptdepth.h"
 
-namespace {
-
-// Arbitarily picked by looking at how deep a translation got before hitting
-// the getting fuzzer memory limits. Should be larger then |kMaxParseDepth| in
-// cxfa_fmparser.cpp.
-const unsigned int kMaxDepth = 5000;
-
-}  // namespace
-
 unsigned long CXFA_FMToJavaScriptDepth::depth_ = 0;
-unsigned long CXFA_FMToJavaScriptDepth::max_depth_ = kMaxDepth;
 
 void CXFA_FMToJavaScriptDepth::Reset() {
   depth_ = 0;
diff --git a/xfa/fxfa/fm2js/cxfa_fmtojavascriptdepth.h b/xfa/fxfa/fm2js/cxfa_fmtojavascriptdepth.h
index 14f87a6..f4cd1be 100644
--- a/xfa/fxfa/fm2js/cxfa_fmtojavascriptdepth.h
+++ b/xfa/fxfa/fm2js/cxfa_fmtojavascriptdepth.h
@@ -10,13 +10,17 @@
   CXFA_FMToJavaScriptDepth() { depth_++; }
   ~CXFA_FMToJavaScriptDepth() { depth_--; }
 
-  bool IsWithinMaxDepth() const { return depth_ <= max_depth_; }
+  bool IsWithinMaxDepth() const { return depth_ <= kMaxDepth; }
 
   static void Reset();
 
  private:
+  // Arbitarily picked by looking at how deep a translation got before hitting
+  // the getting fuzzer memory limits. Should be larger then |kMaxParseDepth| in
+  // cxfa_fmparser.cpp.
+  const unsigned long kMaxDepth = 5000;
+
   static unsigned long depth_;
-  static unsigned long max_depth_;
 };
 
 #endif  // XFA_FXFA_FM2JS_CXFA_FMTOJAVASCRIPTDEPTH_H_
diff --git a/xfa/fxfa/fxfa.h b/xfa/fxfa/fxfa.h
index d42cd1b..2028cd3 100644
--- a/xfa/fxfa/fxfa.h
+++ b/xfa/fxfa/fxfa.h
@@ -7,30 +7,47 @@
 #ifndef XFA_FXFA_FXFA_H_
 #define XFA_FXFA_FXFA_H_
 
-#include <vector>
+#include <memory>
 
+#include "core/fxcrt/cfx_timer.h"
+#include "core/fxcrt/fx_coordinates.h"
 #include "core/fxcrt/retain_ptr.h"
-#include "xfa/fxfa/cxfa_widgetacc.h"
+#include "core/fxge/fx_dib.h"
 #include "xfa/fxfa/fxfa_basic.h"
 
+class CXFA_FFDoc;
 class CXFA_FFPageView;
+class CXFA_FFWidget;
 class CXFA_Submit;
-class CXFA_WidgetAcc;
-class IFWL_AdapterTimerMgr;
 class IFX_SeekableReadStream;
+class IJS_Runtime;
 
-#define XFA_MBICON_Error 0
-#define XFA_MBICON_Warning 1
-#define XFA_MBICON_Question 2
-#define XFA_MBICON_Status 3
-#define XFA_MB_OK 0
-#define XFA_MB_OKCancel 1
-#define XFA_MB_YesNo 2
-#define XFA_MB_YesNoCancel 3
-#define XFA_IDOK 1
-#define XFA_IDCancel 2
-#define XFA_IDNo 3
-#define XFA_IDYes 4
+// Note, values must match fpdf_formfill.h JSPLATFORM_ALERT_BUTTON_* flags.
+enum class AlertButton {
+  kDefault = 0,
+  kOK = 0,
+  kOKCancel = 1,
+  kYesNo = 2,
+  kYesNoCancel = 3,
+};
+
+// Note, values must match fpdf_formfill.h JSPLATFORM_ALERT_ICON_* flags.
+enum class AlertIcon {
+  kDefault = 0,
+  kError = 0,
+  kWarning = 1,
+  kQuestion = 2,
+  kStatus = 3,
+  kAsterisk = 4,
+};
+
+// Note, values must match fpdf_formfill.h JSPLATFORM_ALERT_RETURN_* flags.
+enum class AlertReturn {
+  kOK = 1,
+  kCancel = 2,
+  kNo = 3,
+  kYes = 4,
+};
 
 // Note, values must match fpdf_formfill.h FORMTYPE_* flags.
 enum class FormType {
@@ -40,29 +57,23 @@
   kXFAForeground = 3,
 };
 
-#define XFA_PARSESTATUS_StatusErr -3
-#define XFA_PARSESTATUS_StreamErr -2
-#define XFA_PARSESTATUS_SyntaxErr -1
-#define XFA_PARSESTATUS_Ready 0
-#define XFA_PARSESTATUS_Done 100
-
 #define XFA_PRINTOPT_ShowDialog 0x00000001
 #define XFA_PRINTOPT_CanCancel 0x00000002
 #define XFA_PRINTOPT_ShrinkPage 0x00000004
 #define XFA_PRINTOPT_AsImage 0x00000008
 #define XFA_PRINTOPT_ReverseOrder 0x00000010
 #define XFA_PRINTOPT_PrintAnnot 0x00000020
+
 #define XFA_PAGEVIEWEVENT_PostAdded 1
 #define XFA_PAGEVIEWEVENT_PostRemoved 3
 #define XFA_PAGEVIEWEVENT_StopLayout 4
 
-#define XFA_EVENTERROR_Success 1
-#define XFA_EVENTERROR_Error -1
-#define XFA_EVENTERROR_NotExist 0
-#define XFA_EVENTERROR_Disabled 2
-
-#define XFA_TRAVERSEWAY_Tranvalse 0x0001
-#define XFA_TRAVERSEWAY_Form 0x0002
+enum class XFA_EventError {
+  kError = -1,
+  kNotExist = 0,
+  kSuccess = 1,
+  kDisabled = 2,
+};
 
 enum XFA_WidgetStatus {
   XFA_WidgetStatus_None = 0,
@@ -71,42 +82,17 @@
   XFA_WidgetStatus_ButtonDown = 1 << 1,
   XFA_WidgetStatus_Disabled = 1 << 2,
   XFA_WidgetStatus_Focused = 1 << 3,
-  XFA_WidgetStatus_Highlight = 1 << 4,
-  XFA_WidgetStatus_Printable = 1 << 5,
-  XFA_WidgetStatus_RectCached = 1 << 6,
-  XFA_WidgetStatus_TextEditValueChanged = 1 << 7,
-  XFA_WidgetStatus_Viewable = 1 << 8,
-  XFA_WidgetStatus_Visible = 1 << 9
-};
-
-enum XFA_WIDGETTYPE {
-  XFA_WIDGETTYPE_Barcode,
-  XFA_WIDGETTYPE_PushButton,
-  XFA_WIDGETTYPE_CheckButton,
-  XFA_WIDGETTYPE_RadioButton,
-  XFA_WIDGETTYPE_DatetimeEdit,
-  XFA_WIDGETTYPE_DecimalField,
-  XFA_WIDGETTYPE_NumericField,
-  XFA_WIDGETTYPE_Signature,
-  XFA_WIDGETTYPE_TextEdit,
-  XFA_WIDGETTYPE_DropdownList,
-  XFA_WIDGETTYPE_ListBox,
-  XFA_WIDGETTYPE_ImageField,
-  XFA_WIDGETTYPE_PasswordEdit,
-  XFA_WIDGETTYPE_Arc,
-  XFA_WIDGETTYPE_Rectangle,
-  XFA_WIDGETTYPE_Image,
-  XFA_WIDGETTYPE_Line,
-  XFA_WIDGETTYPE_Text,
-  XFA_WIDGETTYPE_ExcludeGroup,
-  XFA_WIDGETTYPE_Subform,
-  XFA_WIDGETTYPE_Unknown,
+  XFA_WidgetStatus_Printable = 1 << 4,
+  XFA_WidgetStatus_RectCached = 1 << 5,
+  XFA_WidgetStatus_TextEditValueChanged = 1 << 6,
+  XFA_WidgetStatus_Viewable = 1 << 7,
+  XFA_WidgetStatus_Visible = 1 << 8
 };
 
 // Probably should be called IXFA_AppDelegate.
 class IXFA_AppProvider {
  public:
-  virtual ~IXFA_AppProvider() {}
+  virtual ~IXFA_AppProvider() = default;
 
   /**
    * Returns the language of the running host application. Such as zh_CN
@@ -145,9 +131,9 @@
    * user, refer to XFA_ID.
    */
   virtual int32_t MsgBox(const WideString& wsMessage,
-                         const WideString& wsTitle = L"",
-                         uint32_t dwIconType = 0,
-                         uint32_t dwButtonType = 0) = 0;
+                         const WideString& wsTitle,
+                         uint32_t dwIconType,
+                         uint32_t dwButtonType) = 0;
 
   /**
    * Get a response from the user.
@@ -158,9 +144,9 @@
    * @return A string containing the user's response.
    */
   virtual WideString Response(const WideString& wsQuestion,
-                              const WideString& wsTitle = L"",
-                              const WideString& wsDefaultAnswer = L"",
-                              bool bMask = true) = 0;
+                              const WideString& wsTitle,
+                              const WideString& wsDefaultAnswer,
+                              bool bMask) = 0;
 
   /**
    * Download something from somewhere.
@@ -204,31 +190,33 @@
                              const WideString& wsData,
                              const WideString& wsEncode) = 0;
 
-  virtual IFWL_AdapterTimerMgr* GetTimerMgr() = 0;
+  virtual TimerHandlerIface* GetTimerHandler() const = 0;
 };
 
 class IXFA_DocEnvironment {
  public:
-  virtual ~IXFA_DocEnvironment() {}
+  virtual ~IXFA_DocEnvironment() = default;
 
   virtual void SetChangeMark(CXFA_FFDoc* hDoc) = 0;
   virtual void InvalidateRect(CXFA_FFPageView* pPageView,
                               const CFX_RectF& rt) = 0;
+  // Show or hide caret.
   virtual void DisplayCaret(CXFA_FFWidget* hWidget,
                             bool bVisible,
                             const CFX_RectF* pRtAnchor) = 0;
+
   virtual bool GetPopupPos(CXFA_FFWidget* hWidget,
                            float fMinPopup,
                            float fMaxPopup,
                            const CFX_RectF& rtAnchor,
-                           CFX_RectF& rtPopup) = 0;
-  virtual bool PopupMenu(CXFA_FFWidget* hWidget, CFX_PointF ptPopup) = 0;
-  virtual void PageViewEvent(CXFA_FFPageView* pPageView, uint32_t dwFlags) = 0;
-  virtual void WidgetPostAdd(CXFA_FFWidget* hWidget,
-                             CXFA_WidgetAcc* pWidgetAcc) = 0;
-  virtual void WidgetPreRemove(CXFA_FFWidget* hWidget,
-                               CXFA_WidgetAcc* pWidgetAcc) = 0;
+                           CFX_RectF* pPopupRect) = 0;
+  virtual bool PopupMenu(CXFA_FFWidget* hWidget, const CFX_PointF& ptPopup) = 0;
 
+  // Specify dwFlags XFA_PAGEVIEWEVENT_Added, XFA_PAGEVIEWEVENT_Removing
+  virtual void PageViewEvent(CXFA_FFPageView* pPageView, uint32_t dwFlags) = 0;
+
+  virtual void WidgetPostAdd(CXFA_FFWidget* hWidget) = 0;
+  virtual void WidgetPreRemove(CXFA_FFWidget* hWidget) = 0;
   virtual int32_t CountPages(CXFA_FFDoc* hDoc) = 0;
   virtual int32_t GetCurrentPage(CXFA_FFDoc* hDoc) = 0;
   virtual void SetCurrentPage(CXFA_FFDoc* hDoc, int32_t iCurPage) = 0;
@@ -248,22 +236,19 @@
                      int32_t nEndPage,
                      uint32_t dwOptions) = 0;
   virtual FX_ARGB GetHighlightColor(CXFA_FFDoc* hDoc) = 0;
-
-  virtual bool Submit(CXFA_FFDoc* hDoc, CXFA_Submit* submit) = 0;
-  virtual bool GetGlobalProperty(CXFA_FFDoc* hDoc,
-                                 const ByteStringView& szPropName,
-                                 CFXJSE_Value* pValue) = 0;
-  virtual bool SetGlobalProperty(CXFA_FFDoc* hDoc,
-                                 const ByteStringView& szPropName,
-                                 CFXJSE_Value* pValue) = 0;
+  virtual IJS_Runtime* GetIJSRuntime(CXFA_FFDoc* hDoc) const = 0;
   virtual RetainPtr<IFX_SeekableReadStream> OpenLinkedFile(
       CXFA_FFDoc* hDoc,
       const WideString& wsLink) = 0;
+
+#ifdef PDF_XFA_ELEMENT_SUBMIT_ENABLED
+  virtual bool Submit(CXFA_FFDoc* hDoc, CXFA_Submit* submit) = 0;
+#endif  // PDF_XFA_ELEMENT_SUBMIT_ENABLED
 };
 
 class IXFA_WidgetIterator {
  public:
-  virtual ~IXFA_WidgetIterator() {}
+  virtual ~IXFA_WidgetIterator() = default;
 
   virtual void Reset() = 0;
   virtual CXFA_FFWidget* MoveToFirst() = 0;
diff --git a/xfa/fxfa/fxfa_basic.h b/xfa/fxfa/fxfa_basic.h
index 96b483d..333a61d 100644
--- a/xfa/fxfa/fxfa_basic.h
+++ b/xfa/fxfa/fxfa_basic.h
@@ -7,11 +7,11 @@
 #ifndef XFA_FXFA_FXFA_BASIC_H_
 #define XFA_FXFA_FXFA_BASIC_H_
 
-#include "fxjs/fxjse.h"
+#include <stdint.h>
 
-class CJX_Object;
 class CXFA_Measurement;
 enum class XFA_ObjectType;
+struct XFA_SCRIPTATTRIBUTEINFO;
 
 enum XFA_HashCode : uint32_t {
   XFA_HASHCODE_None = 0,
@@ -46,21 +46,10 @@
 };
 
 enum class XFA_PacketType : uint8_t {
-  User,
-  SourceSet,
-  Pdf,
-  Xdc,
-  Xdp,
-  Xmpmeta,
-  Xfdf,
-  Config,
-  LocaleSet,
-  Stylesheet,
-  Template,
-  Signature,
-  Datasets,
-  Form,
-  ConnectionSet,
+#undef PCKT____
+#define PCKT____(a, b, c, d, e, f) c,
+#include "xfa/fxfa/parser/packets.inc"
+#undef PCKT____
 };
 
 enum XFA_XDPPACKET {
@@ -95,837 +84,27 @@
   XFA_XDPPACKET_FLAGS_SUPPORTMANY = 16,
 };
 
-enum class XFA_AttributeEnum : uint32_t {
-  Asterisk,
-  Slash,
-  Backslash,
-  On,
-  Tb,
-  Up,
-  MetaData,
-  Delegate,
-  PostSubmit,
-  Name,
-  Cross,
-  Next,
-  None,
-  ShortEdge,
-  Checksum_1mod10_1mod11,
-  Height,
-  CrossDiagonal,
-  All,
-  Any,
-  ToRight,
-  MatchTemplate,
-  Dpl,
-  Invisible,
-  Fit,
-  Width,
-  PreSubmit,
-  Ipl,
-  FlateCompress,
-  Med,
-  Odd,
-  Off,
-  Pdf,
-  Row,
-  Top,
-  Xdp,
-  Xfd,
-  Xml,
-  Zip,
-  Zpl,
-  Visible,
-  Exclude,
-  MouseEnter,
-  Pair,
-  Filter,
-  MoveLast,
-  ExportAndImport,
-  Push,
-  Portrait,
-  Default,
-  StoredProc,
-  StayBOF,
-  StayEOF,
-  PostPrint,
-  UsCarrier,
-  Right,
-  PreOpen,
-  Actual,
-  Rest,
-  TopCenter,
-  StandardSymbol,
-  Initialize,
-  JustifyAll,
-  Normal,
-  Landscape,
-  NonInteractive,
-  MouseExit,
-  Minus,
-  DiagonalLeft,
-  SimplexPaginated,
-  Document,
-  Warning,
-  Auto,
-  Below,
-  BottomLeft,
-  BottomCenter,
-  Tcpl,
-  Text,
-  Grouping,
-  SecureSymbol,
-  PreExecute,
-  DocClose,
-  Keyset,
-  Vertical,
-  PreSave,
-  PreSign,
-  Bottom,
-  ToTop,
-  Verify,
-  First,
-  ContentArea,
-  Solid,
-  Pessimistic,
-  DuplexPaginated,
-  Round,
-  Remerge,
-  Ordered,
-  Percent,
-  Even,
-  Exit,
-  ToolTip,
-  OrderedOccurrence,
-  ReadOnly,
-  Currency,
-  Concat,
-  Thai,
-  Embossed,
-  Formdata,
-  Greek,
-  Decimal,
-  Select,
-  LongEdge,
-  Protected,
-  BottomRight,
-  Zero,
-  ForwardOnly,
-  DocReady,
-  Hidden,
-  Include,
-  Dashed,
-  MultiSelect,
-  Inactive,
-  Embed,
-  Static,
-  OnEntry,
-  Cyrillic,
-  NonBlank,
-  TopRight,
-  Hebrew,
-  TopLeft,
-  Center,
-  MoveFirst,
-  Diamond,
-  PageOdd,
-  Checksum_1mod10,
-  Korean,
-  AboveEmbedded,
-  ZipCompress,
-  Numeric,
-  Circle,
-  ToBottom,
-  Inverted,
-  Update,
-  Isoname,
-  Server,
-  Position,
-  MiddleCenter,
-  Optional,
-  UsePrinterSetting,
-  Outline,
-  IndexChange,
-  Change,
-  PageArea,
-  Once,
-  Only,
-  Open,
-  Caption,
-  Raised,
-  Justify,
-  RefAndDescendants,
-  Short,
-  PageFront,
-  Monospace,
-  Middle,
-  PrePrint,
-  Always,
-  Unknown,
-  ToLeft,
-  Above,
-  DashDot,
-  Gregorian,
-  Roman,
-  MouseDown,
-  Symbol,
-  PageEven,
-  Sign,
-  AddNew,
-  Star,
-  Optimistic,
-  Rl_tb,
-  MiddleRight,
-  Maintain,
-  Package,
-  SimplifiedChinese,
-  ToCenter,
-  Back,
-  Unspecified,
-  BatchOptimistic,
-  Bold,
-  Both,
-  Butt,
-  Client,
-  Checksum_2mod10,
-  ImageOnly,
-  Horizontal,
-  Dotted,
-  UserControl,
-  DiagonalRight,
-  ConsumeData,
-  Check,
-  Data,
-  Down,
-  SansSerif,
-  Inline,
-  TraditionalChinese,
-  Warn,
-  RefOnly,
-  InteractiveForms,
-  Word,
-  Unordered,
-  Required,
-  ImportOnly,
-  BelowEmbedded,
-  Japanese,
-  Full,
-  Rl_row,
-  Vietnamese,
-  EastEuropeanRoman,
-  MouseUp,
-  ExportOnly,
-  Clear,
-  Click,
-  Base64,
-  Close,
-  Host,
-  Global,
-  Blank,
-  Table,
-  Import,
-  Custom,
-  MiddleLeft,
-  PostExecute,
-  Radix,
-  PostOpen,
-  Enter,
-  Ignore,
-  Lr_tb,
-  Fantasy,
-  Italic,
-  Author,
-  ToEdge,
-  Choice,
-  Disabled,
-  CrossHatch,
-  DataRef,
-  DashDotDot,
-  Square,
-  Dynamic,
-  Manual,
-  Etched,
-  ValidationState,
-  Cursive,
-  Last,
-  Left,
-  Link,
-  Long,
-  InternationalCarrier,
-  PDF1_3,
-  PDF1_6,
-  Serif,
-  PostSave,
-  Ready,
-  PostSign,
-  Arabic,
-  Error,
-  Urlencoded,
-  Lowered
+enum class XFA_AttributeValue : uint16_t {
+#undef VALUE____
+#define VALUE____(a, b, c) c,
+#include "xfa/fxfa/parser/attribute_values.inc"
+#undef VALUE____
 };
 
-enum class XFA_Attribute : uint8_t {
-  H = 0,
-  W,
-  X,
-  Y,
-  Id,
-  To,
-  LineThrough,
-  HAlign,
-  Typeface,
-  BeforeTarget,
-  Name,
-  Next,
-  DataRowCount,
-  Break,
-  VScrollPolicy,
-  FontHorizontalScale,
-  TextIndent,
-  Context,
-  TrayOut,
-  Cap,
-  Max,
-  Min,
-  Ref,
-  Rid,
-  Url,
-  Use,
-  LeftInset,
-  Widows,
-  Level,
-  BottomInset,
-  OverflowTarget,
-  AllowMacro,
-  PagePosition,
-  ColumnWidths,
-  OverflowLeader,
-  Action,
-  NonRepudiation,
-  Rate,
-  AllowRichText,
-  Role,
-  OverflowTrailer,
-  Operation,
-  Timeout,
-  TopInset,
-  Access,
-  CommandType,
-  Format,
-  DataPrep,
-  WidgetData,
-  Abbr,
-  MarginRight,
-  DataDescription,
-  EncipherOnly,
-  KerningMode,
-  Rotate,
-  WordCharacterCount,
-  Type,
-  Reserve,
-  TextLocation,
-  Priority,
-  Underline,
-  ModuleWidth,
-  Hyphenate,
-  Listen,
-  Delimiter,
-  ContentType,
-  StartNew,
-  EofAction,
-  AllowNeutral,
-  Connection,
-  BaselineShift,
-  OverlinePeriod,
-  FracDigits,
-  Orientation,
-  TimeStamp,
-  PrintCheckDigit,
-  MarginLeft,
-  Stroke,
-  ModuleHeight,
-  TransferEncoding,
-  Usage,
-  Presence,
-  RadixOffset,
-  Preserve,
-  AliasNode,
-  MultiLine,
-  Version,
-  StartChar,
-  ScriptTest,
-  StartAngle,
-  CursorType,
-  DigitalSignature,
-  CodeType,
-  Output,
-  BookendTrailer,
-  ImagingBBox,
-  ExcludeInitialCap,
-  Force,
-  CrlSign,
-  Previous,
-  PushCharacterCount,
-  NullTest,
-  RunAt,
-  SpaceBelow,
-  SweepAngle,
-  NumberOfCells,
-  LetterSpacing,
-  LockType,
-  PasswordChar,
-  VAlign,
-  SourceBelow,
-  Inverted,
-  Mark,
-  MaxH,
-  MaxW,
-  Truncate,
-  MinH,
-  MinW,
-  Initial,
-  Mode,
-  Layout,
-  Server,
-  EmbedPDF,
-  OddOrEven,
-  TabDefault,
-  Contains,
-  RightInset,
-  MaxChars,
-  Open,
-  Relation,
-  WideNarrowRatio,
-  Relevant,
-  SignatureType,
-  LineThroughPeriod,
-  Shape,
-  TabStops,
-  OutputBelow,
-  Short,
-  FontVerticalScale,
-  Thickness,
-  CommitOn,
-  RemainCharacterCount,
-  KeyAgreement,
-  ErrorCorrectionLevel,
-  UpsMode,
-  MergeMode,
-  Circular,
-  PsName,
-  Trailer,
-  UnicodeRange,
-  ExecuteType,
-  DuplexImposition,
-  TrayIn,
-  BindingNode,
-  BofAction,
-  Save,
-  TargetType,
-  KeyEncipherment,
-  CredentialServerPolicy,
-  Size,
-  InitialNumber,
-  Slope,
-  CSpace,
-  ColSpan,
-  Binding,
-  Checksum,
-  CharEncoding,
-  Bind,
-  TextEntry,
-  Archive,
-  Uuid,
-  Posture,
-  After,
-  Orphans,
-  QualifiedName,
-  Usehref,
-  Locale,
-  Weight,
-  UnderlinePeriod,
-  Data,
-  Desc,
-  Numbered,
-  DataColumnCount,
-  Overline,
-  UrlPolicy,
-  AnchorType,
-  LabelRef,
-  BookendLeader,
-  MaxLength,
-  AccessKey,
-  CursorLocation,
-  DelayedOpen,
-  Target,
-  DataEncipherment,
-  AfterTarget,
-  Leader,
-  Picker,
-  From,
-  BaseProfile,
-  Aspect,
-  RowColumnRatio,
-  LineHeight,
-  Highlight,
-  ValueRef,
-  MaxEntries,
-  DataLength,
-  Activity,
-  Input,
-  Value,
-  BlankOrNotBlank,
-  AddRevocationInfo,
-  GenericFamily,
-  Hand,
-  Href,
-  TextEncoding,
-  LeadDigits,
-  Permissions,
-  SpaceAbove,
-  CodeBase,
-  Stock,
-  IsNull,
-  RestoreState,
-  ExcludeAllCaps,
-  FormatTest,
-  HScrollPolicy,
-  Join,
-  KeyCertSign,
-  Radius,
-  SourceAbove,
-  Override,
-  ClassId,
-  Disable,
-  Scope,
-  Match,
-  Placement,
-  Before,
-  WritingScript,
-  EndChar,
-  Lock,
-  Long,
-  Intact,
-  XdpContent,
-  DecipherOnly,
-  Unknown = 255,
-};
-
-enum class XFA_Element : int32_t {
+enum class XFA_Attribute : int16_t {
   Unknown = -1,
+#undef ATTR____
+#define ATTR____(a, b, c, d) c,
+#include "xfa/fxfa/parser/attributes.inc"
+#undef ATTR____
+};
 
-  Ps,
-  To,
-  Ui,
-  RecordSet,
-  SubsetBelow,
-  SubformSet,
-  AdobeExtensionLevel,
-  Typeface,
-  Break,
-  FontInfo,
-  NumberPattern,
-  DynamicRender,
-  PrintScaling,
-  CheckButton,
-  DatePatterns,
-  SourceSet,
-  Amd,
-  Arc,
-  Day,
-  Era,
-  Jog,
-  Log,
-  Map,
-  Mdp,
-  BreakBefore,
-  Oid,
-  Pcl,
-  Pdf,
-  Ref,
-  Uri,
-  Xdc,
-  Xdp,
-  Xfa,
-  Xsl,
-  Zpl,
-  Cache,
-  Margin,
-  KeyUsage,
-  Exclude,
-  ChoiceList,
-  Level,
-  LabelPrinter,
-  CalendarSymbols,
-  Para,
-  Part,
-  Pdfa,
-  Filter,
-  Present,
-  Pagination,
-  Encoding,
-  Event,
-  Whitespace,
-  DefaultUi,
-  DataModel,
-  Barcode,
-  TimePattern,
-  BatchOutput,
-  Enforce,
-  CurrencySymbols,
-  AddSilentPrint,
-  Rename,
-  Operation,
-  Typefaces,
-  SubjectDNs,
-  Issuers,
-  SignaturePseudoModel,
-  WsdlConnection,
-  Debug,
-  Delta,
-  EraNames,
-  ModifyAnnots,
-  StartNode,
-  Button,
-  Format,
-  Border,
-  Area,
-  Hyphenation,
-  Text,
-  Time,
-  Type,
-  Overprint,
-  Certificates,
-  EncryptionMethods,
-  SetProperty,
-  PrinterName,
-  StartPage,
-  PageOffset,
-  DateTime,
-  Comb,
-  Pattern,
-  IfEmpty,
-  SuppressBanner,
-  OutputBin,
-  Field,
-  Agent,
-  OutputXSL,
-  AdjustData,
-  AutoSave,
-  ContentArea,
-  EventPseudoModel,
-  WsdlAddress,
-  Solid,
-  DateTimeSymbols,
-  EncryptionLevel,
-  Edge,
-  Stipple,
-  Attributes,
-  VersionControl,
-  Meridiem,
-  ExclGroup,
-  ToolTip,
-  Compress,
-  Reason,
-  Execute,
-  ContentCopy,
-  DateTimeEdit,
-  Config,
-  Image,
-  SharpxHTML,
-  NumberOfCopies,
-  BehaviorOverride,
-  TimeStamp,
-  Month,
-  ViewerPreferences,
-  ScriptModel,
-  Decimal,
-  Subform,
-  Select,
-  Window,
-  LocaleSet,
-  Handler,
-  HostPseudoModel,
-  Presence,
-  Record,
-  Embed,
-  Version,
-  Command,
-  Copies,
-  Staple,
-  SubmitFormat,
-  Boolean,
-  Message,
-  Output,
-  PsMap,
-  ExcludeNS,
-  Assist,
-  Picture,
-  Traversal,
-  SilentPrint,
-  WebClient,
-  LayoutPseudoModel,
-  Producer,
-  Corner,
-  MsgId,
-  Color,
-  Keep,
-  Query,
-  Insert,
-  ImageEdit,
-  Validate,
-  DigestMethods,
-  NumberPatterns,
-  PageSet,
-  Integer,
-  SoapAddress,
-  Equate,
-  FormFieldFilling,
-  PageRange,
-  Update,
-  ConnectString,
-  Mode,
-  Layout,
-  Sharpxml,
-  XsdConnection,
-  Traverse,
-  Encodings,
-  Template,
-  Acrobat,
-  ValidationMessaging,
-  Signing,
-  DataWindow,
-  Script,
-  AddViewerPreferences,
-  AlwaysEmbed,
-  PasswordEdit,
-  NumericEdit,
-  EncryptionMethod,
-  Change,
-  PageArea,
-  SubmitUrl,
-  Oids,
-  Signature,
-  ADBE_JSConsole,
-  Caption,
-  Relevant,
-  FlipLabel,
-  ExData,
-  DayNames,
-  SoapAction,
-  DefaultTypeface,
-  Manifest,
-  Overflow,
-  Linear,
-  CurrencySymbol,
-  Delete,
-  Deltas,
-  DigestMethod,
-  InstanceManager,
-  EquateRange,
-  Medium,
-  TextEdit,
-  TemplateCache,
-  CompressObjectStream,
-  DataValue,
-  AccessibleContent,
-  TreeList,
-  IncludeXDPContent,
-  XmlConnection,
-  ValidateApprovalSignatures,
-  SignData,
-  Packets,
-  DatePattern,
-  DuplexOption,
-  Base,
-  Bind,
-  Compression,
-  User,
-  Rectangle,
-  EffectiveOutputPolicy,
-  ADBE_JSDebugger,
-  Acrobat7,
-  Interactive,
-  Locale,
-  CurrentPage,
-  Data,
-  Date,
-  Desc,
-  Encrypt,
-  Draw,
-  Encryption,
-  MeridiemNames,
-  Messaging,
-  Speak,
-  DataGroup,
-  Common,
-  Sharptext,
-  PaginationOverride,
-  Reasons,
-  SignatureProperties,
-  Threshold,
-  AppearanceFilter,
-  Fill,
-  Font,
-  Form,
-  MediumInfo,
-  Certificate,
-  Password,
-  RunScripts,
-  Trace,
-  Float,
-  RenderPolicy,
-  LogPseudoModel,
-  Destination,
-  Value,
-  Bookend,
-  ExObject,
-  OpenAction,
-  NeverEmbed,
-  BindItems,
-  Calculate,
-  Print,
-  Extras,
-  Proto,
-  DSigData,
-  Creator,
-  Connect,
-  Permissions,
-  ConnectionSet,
-  Submit,
-  Range,
-  Linearized,
-  Packet,
-  RootElement,
-  PlaintextMetadata,
-  NumberSymbols,
-  PrintHighQuality,
-  Driver,
-  IncrementalLoad,
-  SubjectDN,
-  CompressLogicalStructure,
-  IncrementalMerge,
-  Radial,
-  Variables,
-  TimePatterns,
-  EffectiveInputPolicy,
-  NameAttr,
-  Conformance,
-  Transform,
-  LockDocument,
-  BreakAfter,
-  Line,
-  List,
-  Source,
-  Occur,
-  PickTrayByPDFSize,
-  MonthNames,
-  Severity,
-  GroupParent,
-  DocumentAssembly,
-  NumberSymbol,
-  Tagged,
-  Items
+enum class XFA_Element : int16_t {
+  Unknown = -1,
+#undef ELEM____
+#define ELEM____(a, b, c, d) c,
+#include "xfa/fxfa/parser/elements.inc"
+#undef ELEM____
 };
 
 enum class XFA_AttributeType : uint8_t {
@@ -936,21 +115,9 @@
   Measure,
 };
 
-struct XFA_SCRIPTHIERARCHY {
-  uint16_t wAttributeStart;
-  uint16_t wAttributeCount;
-  int16_t wParentIndex;
-};
-
 #define XFA_PROPERTYFLAG_OneOf 0x01
 #define XFA_PROPERTYFLAG_DefaultOneOf 0x02
 
-struct XFA_AttributeEnumInfo {
-  uint32_t uHash;
-  const wchar_t* pName;
-  XFA_AttributeEnum eName;
-};
-
 enum class XFA_Unit : uint8_t {
   Percent = 0,
   Em,
@@ -964,20 +131,9 @@
   Unknown = 255,
 };
 
-typedef void (CJX_Object::*XFA_ATTRIBUTE_CALLBACK)(CFXJSE_Value* pValue,
-                                                   bool bSetting,
-                                                   XFA_Attribute eAttribute);
 enum class XFA_ScriptType : uint8_t {
   Basic,
   Object,
 };
 
-struct XFA_SCRIPTATTRIBUTEINFO {
-  uint32_t uHash;
-  const wchar_t* pName;
-  XFA_ATTRIBUTE_CALLBACK callback;
-  XFA_Attribute attribute;
-  XFA_ScriptType eValueType;
-};
-
 #endif  // XFA_FXFA_FXFA_BASIC_H_
diff --git a/xfa/fxfa/fxfa_basic_unittest.cpp b/xfa/fxfa/fxfa_basic_unittest.cpp
new file mode 100644
index 0000000..5f77708
--- /dev/null
+++ b/xfa/fxfa/fxfa_basic_unittest.cpp
@@ -0,0 +1,54 @@
+// Copyright 2018 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/fxfa_basic.h"
+
+#include "core/fxcrt/bytestring.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+void HashTestCase(uint32_t hash, const char* str, uint32_t* so_far) {
+  if (hash != 0xffffffffu) {
+    EXPECT_EQ(hash, FX_HashCode_GetAsIfW(str, false)) << str;
+    EXPECT_LT(*so_far, hash) << hash;
+  } else {
+    EXPECT_NE(hash, FX_HashCode_GetAsIfW(str, false)) << str;
+  }
+  *so_far = hash;
+}
+
+}  // namespace
+
+TEST(FXFABasic, PacketHashTest) {
+  uint32_t so_far = 0;
+#undef PCKT____
+#define PCKT____(a, b, c, d, e, f) HashTestCase(a, b, &so_far);
+#include "xfa/fxfa/parser/packets.inc"
+#undef PCKT____
+}
+
+TEST(FXFABasic, AttributeHashTest) {
+  uint32_t so_far = 0;
+#undef ATTR____
+#define ATTR____(a, b, c, d) HashTestCase(a, b, &so_far);
+#include "xfa/fxfa/parser/attributes.inc"
+#undef ATTR____
+}
+
+TEST(FXFABasic, ValueHashTest) {
+  uint32_t so_far = 0;
+#undef VALUE____
+#define VALUE____(a, b, c) HashTestCase(a, b, &so_far);
+#include "xfa/fxfa/parser/attribute_values.inc"
+#undef VALUE____
+}
+
+TEST(FXFABasic, ElementHashTest) {
+  uint32_t so_far = 0;
+#undef ELEM____
+#define ELEM____(a, b, c, d) HashTestCase(a, b, &so_far);
+#include "xfa/fxfa/parser/elements.inc"
+#undef ELEM____
+}
diff --git a/xfa/fxfa/layout/BUILD.gn b/xfa/fxfa/layout/BUILD.gn
new file mode 100644
index 0000000..6c9295f
--- /dev/null
+++ b/xfa/fxfa/layout/BUILD.gn
@@ -0,0 +1,42 @@
+# Copyright 2019 The 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.
+
+import("../../../pdfium.gni")
+import("../../../testing/test.gni")
+
+assert(pdf_enable_xfa)
+
+source_set("layout") {
+  sources = [
+    "cxfa_contentlayoutitem.cpp",
+    "cxfa_contentlayoutitem.h",
+    "cxfa_contentlayoutprocessor.cpp",
+    "cxfa_contentlayoutprocessor.h",
+    "cxfa_layoutitem.cpp",
+    "cxfa_layoutitem.h",
+    "cxfa_layoutprocessor.cpp",
+    "cxfa_layoutprocessor.h",
+    "cxfa_traversestrategy_layoutitem.h",
+    "cxfa_viewlayoutitem.cpp",
+    "cxfa_viewlayoutitem.h",
+    "cxfa_viewlayoutprocessor.cpp",
+    "cxfa_viewlayoutprocessor.h",
+  ]
+  deps = [
+    "../../../core/fxcrt",
+    "../../../fxjs",
+    "../parser",
+  ]
+  allow_circular_includes_from = [ "../../../fxjs" ]
+  configs += [
+    "../../../:pdfium_core_config",
+    "../../:xfa_warnings",
+  ]
+  visibility = [ "../../../*" ]
+}
+
+pdfium_embeddertest_source_set("embeddertests") {
+  sources = [ "cxfa_layoutitem_embeddertest.cpp" ]
+  pdfium_root_dir = "../../../"
+}
diff --git a/xfa/fxfa/layout/cxfa_contentlayoutitem.cpp b/xfa/fxfa/layout/cxfa_contentlayoutitem.cpp
new file mode 100644
index 0000000..250cd57
--- /dev/null
+++ b/xfa/fxfa/layout/cxfa_contentlayoutitem.cpp
@@ -0,0 +1,109 @@
+// Copyright 2016 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
+
+#include "xfa/fxfa/layout/cxfa_contentlayoutitem.h"
+
+#include <utility>
+
+#include "fxjs/xfa/cjx_object.h"
+#include "xfa/fxfa/cxfa_ffwidget.h"
+#include "xfa/fxfa/parser/cxfa_margin.h"
+#include "xfa/fxfa/parser/cxfa_node.h"
+
+CXFA_ContentLayoutItem::CXFA_ContentLayoutItem(
+    CXFA_Node* pNode,
+    std::unique_ptr<CXFA_FFWidget> pWidget)
+    : CXFA_LayoutItem(pNode, kContentItem), m_pFFWidget(std::move(pWidget)) {
+  if (m_pFFWidget)
+    m_pFFWidget->SetLayoutItem(this);
+}
+
+CXFA_ContentLayoutItem::~CXFA_ContentLayoutItem() {
+  if (m_pFFWidget)
+    m_pFFWidget->SetLayoutItem(nullptr);
+
+  RemoveSelf();
+}
+
+CXFA_ContentLayoutItem* CXFA_ContentLayoutItem::GetFirst() {
+  CXFA_ContentLayoutItem* pCurNode = this;
+  while (auto* pPrev = pCurNode->GetPrev())
+    pCurNode = pPrev;
+
+  return pCurNode;
+}
+
+CXFA_ContentLayoutItem* CXFA_ContentLayoutItem::GetLast() {
+  CXFA_ContentLayoutItem* pCurNode = this;
+  while (auto* pNext = pCurNode->GetNext())
+    pCurNode = pNext;
+
+  return pCurNode;
+}
+
+void CXFA_ContentLayoutItem::InsertAfter(CXFA_ContentLayoutItem* pItem) {
+  CHECK_NE(this, pItem);
+  pItem->RemoveSelf();
+  pItem->m_pNext = m_pNext;
+  pItem->m_pPrev = this;
+  m_pNext = pItem;
+  if (pItem->m_pNext)
+    pItem->m_pNext->m_pPrev = pItem;
+}
+
+void CXFA_ContentLayoutItem::RemoveSelf() {
+  if (m_pNext)
+    m_pNext->m_pPrev = m_pPrev;
+  if (m_pPrev)
+    m_pPrev->m_pNext = m_pNext;
+}
+
+CFX_RectF CXFA_ContentLayoutItem::GetRect(bool bRelative) const {
+  CFX_PointF sPos = m_sPos;
+  CFX_SizeF sSize = m_sSize;
+  if (bRelative)
+    return CFX_RectF(sPos, sSize);
+
+  for (CXFA_LayoutItem* pLayoutItem = GetParent(); pLayoutItem;
+       pLayoutItem = pLayoutItem->GetParent()) {
+    if (CXFA_ContentLayoutItem* pContent = pLayoutItem->AsContentLayoutItem()) {
+      sPos += pContent->m_sPos;
+      CXFA_Margin* pMarginNode =
+          pContent->GetFormNode()->GetFirstChildByClass<CXFA_Margin>(
+              XFA_Element::Margin);
+      if (pMarginNode) {
+        sPos += CFX_PointF(pMarginNode->JSObject()->GetMeasureInUnit(
+                               XFA_Attribute::LeftInset, XFA_Unit::Pt),
+                           pMarginNode->JSObject()->GetMeasureInUnit(
+                               XFA_Attribute::TopInset, XFA_Unit::Pt));
+      }
+      continue;
+    }
+
+    if (pLayoutItem->GetFormNode()->GetElementType() ==
+        XFA_Element::ContentArea) {
+      sPos +=
+          CFX_PointF(pLayoutItem->GetFormNode()->JSObject()->GetMeasureInUnit(
+                         XFA_Attribute::X, XFA_Unit::Pt),
+                     pLayoutItem->GetFormNode()->JSObject()->GetMeasureInUnit(
+                         XFA_Attribute::Y, XFA_Unit::Pt));
+      break;
+    }
+    if (pLayoutItem->GetFormNode()->GetElementType() == XFA_Element::PageArea)
+      break;
+  }
+  return CFX_RectF(sPos, sSize);
+}
+
+size_t CXFA_ContentLayoutItem::GetIndex() const {
+  size_t szIndex = 0;
+  const CXFA_ContentLayoutItem* pCurNode = this;
+  while (auto* pPrev = pCurNode->GetPrev()) {
+    pCurNode = pPrev;
+    ++szIndex;
+  }
+  return szIndex;
+}
diff --git a/xfa/fxfa/layout/cxfa_contentlayoutitem.h b/xfa/fxfa/layout/cxfa_contentlayoutitem.h
new file mode 100644
index 0000000..063f9a3
--- /dev/null
+++ b/xfa/fxfa/layout/cxfa_contentlayoutitem.h
@@ -0,0 +1,61 @@
+// Copyright 2016 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_LAYOUT_CXFA_CONTENTLAYOUTITEM_H_
+#define XFA_FXFA_LAYOUT_CXFA_CONTENTLAYOUTITEM_H_
+
+#include <memory>
+
+#include "core/fxcrt/retain_ptr.h"
+#include "core/fxcrt/unowned_ptr.h"
+#include "xfa/fxfa/layout/cxfa_layoutitem.h"
+
+class CXFA_FFWidget;
+
+class CXFA_ContentLayoutItem : public CXFA_LayoutItem {
+ public:
+  template <typename T, typename... Args>
+  friend RetainPtr<T> pdfium::MakeRetain(Args&&... args);
+
+  ~CXFA_ContentLayoutItem() override;
+
+  CXFA_FFWidget* GetFFWidget() { return m_pFFWidget.get(); }
+
+  CXFA_ContentLayoutItem* GetFirst();
+  CXFA_ContentLayoutItem* GetLast();
+  CXFA_ContentLayoutItem* GetPrev() const { return m_pPrev.Get(); }
+  CXFA_ContentLayoutItem* GetNext() const { return m_pNext.Get(); }
+  void InsertAfter(CXFA_ContentLayoutItem* pNext);
+
+  CFX_RectF GetRect(bool bRelative) const;
+  size_t GetIndex() const;
+
+  void SetStatusBits(uint32_t val) { m_dwStatus |= val; }
+  void ClearStatusBits(uint32_t val) { m_dwStatus &= ~val; }
+
+  // TRUE if all (not any) bits set in |val| are set in |m_dwStatus|.
+  bool TestStatusBits(uint32_t val) const { return (m_dwStatus & val) == val; }
+
+  CFX_PointF m_sPos;
+  CFX_SizeF m_sSize;
+
+ private:
+  CXFA_ContentLayoutItem(CXFA_Node* pNode,
+                         std::unique_ptr<CXFA_FFWidget> pFFWidget);
+
+  void RemoveSelf();
+
+  mutable uint32_t m_dwStatus = 0;
+  UnownedPtr<CXFA_ContentLayoutItem> m_pPrev;
+  UnownedPtr<CXFA_ContentLayoutItem> m_pNext;
+  std::unique_ptr<CXFA_FFWidget> const m_pFFWidget;
+};
+
+inline CXFA_FFWidget* GetFFWidget(CXFA_ContentLayoutItem* item) {
+  return item ? item->GetFFWidget() : nullptr;
+}
+
+#endif  // XFA_FXFA_LAYOUT_CXFA_CONTENTLAYOUTITEM_H_
diff --git a/xfa/fxfa/layout/cxfa_contentlayoutprocessor.cpp b/xfa/fxfa/layout/cxfa_contentlayoutprocessor.cpp
new file mode 100644
index 0000000..833ab99
--- /dev/null
+++ b/xfa/fxfa/layout/cxfa_contentlayoutprocessor.cpp
@@ -0,0 +1,2812 @@
+// Copyright 2014 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
+
+#include "xfa/fxfa/layout/cxfa_contentlayoutprocessor.h"
+
+#include <algorithm>
+#include <memory>
+#include <utility>
+#include <vector>
+
+#include "fxjs/xfa/cjx_object.h"
+#include "third_party/base/compiler_specific.h"
+#include "third_party/base/logging.h"
+#include "third_party/base/ptr_util.h"
+#include "third_party/base/stl_util.h"
+#include "xfa/fxfa/cxfa_ffdoc.h"
+#include "xfa/fxfa/cxfa_ffnotify.h"
+#include "xfa/fxfa/cxfa_ffwidget.h"
+#include "xfa/fxfa/layout/cxfa_contentlayoutitem.h"
+#include "xfa/fxfa/layout/cxfa_layoutprocessor.h"
+#include "xfa/fxfa/layout/cxfa_viewlayoutitem.h"
+#include "xfa/fxfa/layout/cxfa_viewlayoutprocessor.h"
+#include "xfa/fxfa/parser/cxfa_document.h"
+#include "xfa/fxfa/parser/cxfa_keep.h"
+#include "xfa/fxfa/parser/cxfa_localemgr.h"
+#include "xfa/fxfa/parser/cxfa_margin.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_occur.h"
+#include "xfa/fxfa/parser/cxfa_para.h"
+#include "xfa/fxfa/parser/cxfa_traversestrategy_xfanode.h"
+#include "xfa/fxfa/parser/xfa_utils.h"
+
+namespace {
+
+std::vector<WideString> SeparateStringOnSpace(
+    pdfium::span<const wchar_t> spStr) {
+  std::vector<WideString> ret;
+  if (spStr.empty())
+    return ret;
+
+  size_t nPos = 0;
+  size_t nToken = 0;
+  while (nPos < spStr.size()) {
+    if (spStr[nPos] == L' ') {
+      ret.emplace_back(WideStringView(spStr.subspan(nToken, nPos - nToken)));
+      nToken = nPos + 1;
+    }
+    nPos++;
+  }
+  ret.emplace_back(WideStringView(spStr.subspan(nToken, nPos - nToken)));
+  return ret;
+}
+
+void UpdateWidgetSize(CXFA_ContentLayoutItem* pLayoutItem,
+                      float* pWidth,
+                      float* pHeight) {
+  CXFA_Node* pNode = pLayoutItem->GetFormNode();
+  switch (pNode->GetElementType()) {
+    case XFA_Element::Subform:
+    case XFA_Element::Area:
+    case XFA_Element::ExclGroup:
+    case XFA_Element::SubformSet: {
+      if (*pWidth < -kXFALayoutPrecision)
+        *pWidth = pLayoutItem->m_sSize.width;
+      if (*pHeight < -kXFALayoutPrecision)
+        *pHeight = pLayoutItem->m_sSize.height;
+      break;
+    }
+    case XFA_Element::Draw:
+    case XFA_Element::Field: {
+      pNode->GetDocument()->GetNotify()->StartFieldDrawLayout(pNode, pWidth,
+                                                              pHeight);
+      break;
+    }
+    default:
+      NOTREACHED();
+  }
+}
+
+CFX_SizeF CalculateContainerSpecifiedSize(CXFA_Node* pFormNode,
+                                          bool* bContainerWidthAutoSize,
+                                          bool* bContainerHeightAutoSize) {
+  *bContainerWidthAutoSize = true;
+  *bContainerHeightAutoSize = true;
+
+  XFA_Element eType = pFormNode->GetElementType();
+
+  CFX_SizeF containerSize;
+  if (eType == XFA_Element::Subform || eType == XFA_Element::ExclGroup) {
+    Optional<CXFA_Measurement> wValue =
+        pFormNode->JSObject()->TryMeasure(XFA_Attribute::W, false);
+    if (wValue && wValue->GetValue() > kXFALayoutPrecision) {
+      containerSize.width = wValue->ToUnit(XFA_Unit::Pt);
+      *bContainerWidthAutoSize = false;
+    }
+
+    Optional<CXFA_Measurement> hValue =
+        pFormNode->JSObject()->TryMeasure(XFA_Attribute::H, false);
+    if (hValue && hValue->GetValue() > kXFALayoutPrecision) {
+      containerSize.height = hValue->ToUnit(XFA_Unit::Pt);
+      *bContainerHeightAutoSize = false;
+    }
+  }
+
+  if (*bContainerWidthAutoSize && eType == XFA_Element::Subform) {
+    Optional<CXFA_Measurement> maxW =
+        pFormNode->JSObject()->TryMeasure(XFA_Attribute::MaxW, false);
+    if (maxW && maxW->GetValue() > kXFALayoutPrecision) {
+      containerSize.width = maxW->ToUnit(XFA_Unit::Pt);
+      *bContainerWidthAutoSize = false;
+    }
+
+    Optional<CXFA_Measurement> maxH =
+        pFormNode->JSObject()->TryMeasure(XFA_Attribute::MaxH, false);
+    if (maxH && maxH->GetValue() > kXFALayoutPrecision) {
+      containerSize.height = maxH->ToUnit(XFA_Unit::Pt);
+      *bContainerHeightAutoSize = false;
+    }
+  }
+  return containerSize;
+}
+
+CFX_SizeF CalculateContainerComponentSizeFromContentSize(
+    CXFA_Node* pFormNode,
+    bool bContainerWidthAutoSize,
+    float fContentCalculatedWidth,
+    bool bContainerHeightAutoSize,
+    float fContentCalculatedHeight,
+    const CFX_SizeF& currentContainerSize) {
+  CFX_SizeF componentSize = currentContainerSize;
+  CXFA_Margin* pMarginNode =
+      pFormNode->GetFirstChildByClass<CXFA_Margin>(XFA_Element::Margin);
+  if (bContainerWidthAutoSize) {
+    componentSize.width = fContentCalculatedWidth;
+    if (pMarginNode) {
+      Optional<CXFA_Measurement> leftInset =
+          pMarginNode->JSObject()->TryMeasure(XFA_Attribute::LeftInset, false);
+      if (leftInset)
+        componentSize.width += leftInset->ToUnit(XFA_Unit::Pt);
+
+      Optional<CXFA_Measurement> rightInset =
+          pMarginNode->JSObject()->TryMeasure(XFA_Attribute::RightInset, false);
+      if (rightInset)
+        componentSize.width += rightInset->ToUnit(XFA_Unit::Pt);
+    }
+  }
+
+  if (bContainerHeightAutoSize) {
+    componentSize.height = fContentCalculatedHeight;
+    if (pMarginNode) {
+      Optional<CXFA_Measurement> topInset =
+          pMarginNode->JSObject()->TryMeasure(XFA_Attribute::TopInset, false);
+      if (topInset)
+        componentSize.height += topInset->ToUnit(XFA_Unit::Pt);
+
+      Optional<CXFA_Measurement> bottomInset =
+          pMarginNode->JSObject()->TryMeasure(XFA_Attribute::BottomInset,
+                                              false);
+      if (bottomInset)
+        componentSize.height += bottomInset->ToUnit(XFA_Unit::Pt);
+    }
+  }
+  return componentSize;
+}
+
+CFX_FloatRect GetMarginInset(const CXFA_Margin* pMargin) {
+  CFX_FloatRect inset;
+  if (!pMargin)
+    return inset;
+
+  inset.left = pMargin->JSObject()->GetMeasureInUnit(XFA_Attribute::LeftInset,
+                                                     XFA_Unit::Pt);
+  inset.top = pMargin->JSObject()->GetMeasureInUnit(XFA_Attribute::TopInset,
+                                                    XFA_Unit::Pt);
+  inset.right = pMargin->JSObject()->GetMeasureInUnit(XFA_Attribute::RightInset,
+                                                      XFA_Unit::Pt);
+  inset.bottom = pMargin->JSObject()->GetMeasureInUnit(
+      XFA_Attribute::BottomInset, XFA_Unit::Pt);
+  return inset;
+}
+
+void RelocateTableRowCells(const RetainPtr<CXFA_ContentLayoutItem>& pLayoutRow,
+                           const std::vector<float>& rgSpecifiedColumnWidths,
+                           XFA_AttributeValue eLayout) {
+  bool bContainerWidthAutoSize = true;
+  bool bContainerHeightAutoSize = true;
+  CFX_SizeF containerSize = CalculateContainerSpecifiedSize(
+      pLayoutRow->GetFormNode(), &bContainerWidthAutoSize,
+      &bContainerHeightAutoSize);
+  CXFA_Margin* pMargin =
+      pLayoutRow->GetFormNode()->GetFirstChildByClass<CXFA_Margin>(
+          XFA_Element::Margin);
+  CFX_FloatRect inset = GetMarginInset(pMargin);
+  float fContentWidthLimit =
+      bContainerWidthAutoSize ? FLT_MAX
+                              : containerSize.width - inset.left - inset.right;
+  float fContentCurrentHeight =
+      pLayoutRow->m_sSize.height - inset.top - inset.bottom;
+  float fContentCalculatedWidth = 0;
+  float fContentCalculatedHeight = 0;
+  float fCurrentColX = 0;
+  int32_t nCurrentColIdx = 0;
+  bool bMetWholeRowCell = false;
+
+  for (CXFA_LayoutItem* pIter = pLayoutRow->GetFirstChild(); pIter;
+       pIter = pIter->GetNextSibling()) {
+    CXFA_ContentLayoutItem* pLayoutChild = pIter->AsContentLayoutItem();
+    if (!pLayoutChild)
+      continue;
+
+    int32_t nOriginalColSpan =
+        pLayoutChild->GetFormNode()->JSObject()->GetInteger(
+            XFA_Attribute::ColSpan);
+    if (nOriginalColSpan <= 0 && nOriginalColSpan != -1)
+      continue;
+
+    int32_t nColSpan = nOriginalColSpan;
+    float fColSpanWidth = 0;
+    if (nColSpan == -1 ||
+        nCurrentColIdx + nColSpan >
+            pdfium::CollectionSize<int32_t>(rgSpecifiedColumnWidths)) {
+      nColSpan = pdfium::CollectionSize<int32_t>(rgSpecifiedColumnWidths) -
+                 nCurrentColIdx;
+    }
+    for (int32_t i = 0; i < nColSpan; i++)
+      fColSpanWidth += rgSpecifiedColumnWidths[nCurrentColIdx + i];
+
+    if (nColSpan != nOriginalColSpan) {
+      fColSpanWidth = bMetWholeRowCell ? 0
+                                       : std::max(fColSpanWidth,
+                                                  pLayoutChild->m_sSize.height);
+    }
+    if (nOriginalColSpan == -1)
+      bMetWholeRowCell = true;
+
+    pLayoutChild->m_sPos = CFX_PointF(fCurrentColX, 0);
+    pLayoutChild->m_sSize.width = fColSpanWidth;
+    if (!pLayoutChild->GetFormNode()->PresenceRequiresSpace())
+      continue;
+
+    fCurrentColX += fColSpanWidth;
+    nCurrentColIdx += nColSpan;
+    float fNewHeight = bContainerHeightAutoSize ? -1 : fContentCurrentHeight;
+    UpdateWidgetSize(pLayoutChild, &fColSpanWidth, &fNewHeight);
+    pLayoutChild->m_sSize.height = fNewHeight;
+    if (bContainerHeightAutoSize) {
+      fContentCalculatedHeight =
+          std::max(fContentCalculatedHeight, pLayoutChild->m_sSize.height);
+    }
+  }
+
+  if (bContainerHeightAutoSize) {
+    for (CXFA_LayoutItem* pIter = pLayoutRow->GetFirstChild(); pIter;
+         pIter = pIter->GetNextSibling()) {
+      CXFA_ContentLayoutItem* pLayoutChild = pIter->AsContentLayoutItem();
+      if (!pLayoutChild)
+        continue;
+
+      UpdateWidgetSize(pLayoutChild, &pLayoutChild->m_sSize.width,
+                       &fContentCalculatedHeight);
+      float fOldChildHeight = pLayoutChild->m_sSize.height;
+      pLayoutChild->m_sSize.height = fContentCalculatedHeight;
+      CXFA_Para* pParaNode =
+          pLayoutChild->GetFormNode()->GetFirstChildByClass<CXFA_Para>(
+              XFA_Element::Para);
+      if (pParaNode && pLayoutChild->GetFirstChild()) {
+        float fOffHeight = fContentCalculatedHeight - fOldChildHeight;
+        XFA_AttributeValue eVType =
+            pParaNode->JSObject()->GetEnum(XFA_Attribute::VAlign);
+        switch (eVType) {
+          case XFA_AttributeValue::Middle:
+            fOffHeight = fOffHeight / 2;
+            break;
+          case XFA_AttributeValue::Bottom:
+            break;
+          case XFA_AttributeValue::Top:
+          default:
+            fOffHeight = 0;
+            break;
+        }
+        if (fOffHeight > 0) {
+          for (CXFA_LayoutItem* pInnerIter = pLayoutChild->GetFirstChild();
+               pInnerIter; pInnerIter = pInnerIter->GetNextSibling()) {
+            CXFA_ContentLayoutItem* pInnerChild =
+                pInnerIter->AsContentLayoutItem();
+            if (!pInnerChild)
+              continue;
+
+            pInnerChild->m_sPos.y += fOffHeight;
+          }
+        }
+      }
+    }
+  }
+
+  if (bContainerWidthAutoSize) {
+    float fChildSuppliedWidth = fCurrentColX;
+    if (fContentWidthLimit < FLT_MAX &&
+        fContentWidthLimit > fChildSuppliedWidth) {
+      fChildSuppliedWidth = fContentWidthLimit;
+    }
+    fContentCalculatedWidth =
+        std::max(fContentCalculatedWidth, fChildSuppliedWidth);
+  } else {
+    fContentCalculatedWidth = containerSize.width - inset.left - inset.right;
+  }
+
+  if (pLayoutRow->GetFormNode()->JSObject()->GetEnum(XFA_Attribute::Layout) ==
+      XFA_AttributeValue::Rl_row) {
+    for (CXFA_LayoutItem* pIter = pLayoutRow->GetFirstChild(); pIter;
+         pIter = pIter->GetNextSibling()) {
+      CXFA_ContentLayoutItem* pLayoutChild = pIter->AsContentLayoutItem();
+      if (!pLayoutChild)
+        continue;
+
+      pLayoutChild->m_sPos.x = fContentCalculatedWidth -
+                               pLayoutChild->m_sPos.x -
+                               pLayoutChild->m_sSize.width;
+    }
+  }
+  pLayoutRow->m_sSize = CalculateContainerComponentSizeFromContentSize(
+      pLayoutRow->GetFormNode(), bContainerWidthAutoSize,
+      fContentCalculatedWidth, bContainerHeightAutoSize,
+      fContentCalculatedHeight, containerSize);
+}
+
+XFA_AttributeValue GetLayout(CXFA_Node* pFormNode, bool* bRootForceTb) {
+  *bRootForceTb = false;
+  Optional<XFA_AttributeValue> layoutMode =
+      pFormNode->JSObject()->TryEnum(XFA_Attribute::Layout, false);
+  if (layoutMode)
+    return *layoutMode;
+
+  CXFA_Node* pParentNode = pFormNode->GetParent();
+  if (pParentNode && pParentNode->GetElementType() == XFA_Element::Form) {
+    *bRootForceTb = true;
+    return XFA_AttributeValue::Tb;
+  }
+  return XFA_AttributeValue::Position;
+}
+
+bool ExistContainerKeep(CXFA_Node* pCurNode, bool bPreFind) {
+  if (!pCurNode || !pCurNode->PresenceRequiresSpace())
+    return false;
+
+  CXFA_Node* pPreContainer = bPreFind ? pCurNode->GetPrevContainerSibling()
+                                      : pCurNode->GetNextContainerSibling();
+  if (!pPreContainer)
+    return false;
+
+  CXFA_Keep* pKeep =
+      pCurNode->GetFirstChildByClass<CXFA_Keep>(XFA_Element::Keep);
+  if (pKeep) {
+    XFA_Attribute eKeepType = XFA_Attribute::Previous;
+    if (!bPreFind)
+      eKeepType = XFA_Attribute::Next;
+
+    Optional<XFA_AttributeValue> previous =
+        pKeep->JSObject()->TryEnum(eKeepType, false);
+    if (previous) {
+      if (*previous == XFA_AttributeValue::ContentArea ||
+          *previous == XFA_AttributeValue::PageArea) {
+        return true;
+      }
+    }
+  }
+
+  pKeep = pPreContainer->GetFirstChildByClass<CXFA_Keep>(XFA_Element::Keep);
+  if (!pKeep)
+    return false;
+
+  XFA_Attribute eKeepType = XFA_Attribute::Next;
+  if (!bPreFind)
+    eKeepType = XFA_Attribute::Previous;
+
+  Optional<XFA_AttributeValue> next =
+      pKeep->JSObject()->TryEnum(eKeepType, false);
+  if (!next)
+    return false;
+  if (*next == XFA_AttributeValue::ContentArea ||
+      *next == XFA_AttributeValue::PageArea) {
+    return true;
+  }
+  return false;
+}
+
+Optional<CXFA_ContentLayoutProcessor::Stage> FindBreakNode(
+    CXFA_Node* pContainerNode,
+    bool bBreakBefore,
+    CXFA_Node** pCurActionNode) {
+  for (CXFA_Node* pBreakNode = pContainerNode; pBreakNode;
+       pBreakNode = pBreakNode->GetNextSibling()) {
+    XFA_Attribute eAttributeType =
+        bBreakBefore ? XFA_Attribute::Before : XFA_Attribute::After;
+
+    switch (pBreakNode->GetElementType()) {
+      case XFA_Element::BreakBefore: {
+        if (!bBreakBefore)
+          break;
+
+        *pCurActionNode = pBreakNode;
+        return CXFA_ContentLayoutProcessor::Stage::kBreakBefore;
+      }
+      case XFA_Element::BreakAfter: {
+        if (bBreakBefore)
+          break;
+
+        *pCurActionNode = pBreakNode;
+        return CXFA_ContentLayoutProcessor::Stage::kBreakAfter;
+      }
+      case XFA_Element::Break:
+        if (pBreakNode->JSObject()->GetEnum(eAttributeType) ==
+            XFA_AttributeValue::Auto) {
+          break;
+        }
+
+        *pCurActionNode = pBreakNode;
+        return bBreakBefore ? CXFA_ContentLayoutProcessor::Stage::kBreakBefore
+                            : CXFA_ContentLayoutProcessor::Stage::kBreakAfter;
+      default:
+        break;
+    }
+  }
+  return {};
+}
+
+void DeleteLayoutGeneratedNode(CXFA_Node* pGenerateNode) {
+  CXFA_FFNotify* pNotify = pGenerateNode->GetDocument()->GetNotify();
+  auto* pDocLayout =
+      CXFA_LayoutProcessor::FromDocument(pGenerateNode->GetDocument());
+  CXFA_NodeIterator sIterator(pGenerateNode);
+  for (CXFA_Node* pNode = sIterator.GetCurrent(); pNode;
+       pNode = sIterator.MoveToNext()) {
+    RetainPtr<CXFA_ContentLayoutItem> pCurLayoutItem(
+        ToContentLayoutItem(pNode->JSObject()->GetLayoutItem()));
+    while (pCurLayoutItem) {
+      CXFA_ContentLayoutItem* pNextLayoutItem = pCurLayoutItem->GetNext();
+      pNotify->OnLayoutItemRemoving(pDocLayout, pCurLayoutItem.Get());
+      pCurLayoutItem.Reset(pNextLayoutItem);
+    }
+  }
+  pGenerateNode->GetParent()->RemoveChildAndNotify(pGenerateNode, true);
+}
+
+uint8_t HAlignEnumToInt(XFA_AttributeValue eHAlign) {
+  switch (eHAlign) {
+    case XFA_AttributeValue::Center:
+      return 1;
+    case XFA_AttributeValue::Right:
+      return 2;
+    case XFA_AttributeValue::Left:
+    default:
+      return 0;
+  }
+}
+
+bool FindLayoutItemSplitPos(CXFA_ContentLayoutItem* pLayoutItem,
+                            float fCurVerticalOffset,
+                            float* fProposedSplitPos,
+                            bool* bAppChange,
+                            bool bCalculateMargin) {
+  CXFA_Node* pFormNode = pLayoutItem->GetFormNode();
+  if (*fProposedSplitPos <= fCurVerticalOffset + kXFALayoutPrecision ||
+      *fProposedSplitPos > fCurVerticalOffset + pLayoutItem->m_sSize.height -
+                               kXFALayoutPrecision) {
+    return false;
+  }
+
+  switch (pFormNode->GetIntact()) {
+    case XFA_AttributeValue::None: {
+      bool bAnyChanged = false;
+      CXFA_Document* pDocument = pFormNode->GetDocument();
+      CXFA_FFNotify* pNotify = pDocument->GetNotify();
+      float fCurTopMargin = 0, fCurBottomMargin = 0;
+      CXFA_Margin* pMarginNode =
+          pFormNode->GetFirstChildByClass<CXFA_Margin>(XFA_Element::Margin);
+      if (pMarginNode && bCalculateMargin) {
+        fCurTopMargin = pMarginNode->JSObject()->GetMeasureInUnit(
+            XFA_Attribute::TopInset, XFA_Unit::Pt);
+        fCurBottomMargin = pMarginNode->JSObject()->GetMeasureInUnit(
+            XFA_Attribute::BottomInset, XFA_Unit::Pt);
+      }
+      bool bChanged = true;
+      while (bChanged) {
+        bChanged = false;
+        {
+          Optional<float> fRelSplitPos = pFormNode->FindSplitPos(
+              pNotify->GetHDOC()->GetDocView(), pLayoutItem->GetIndex(),
+              *fProposedSplitPos - fCurVerticalOffset);
+          if (fRelSplitPos.has_value()) {
+            bAnyChanged = true;
+            bChanged = true;
+            *fProposedSplitPos = fCurVerticalOffset + fRelSplitPos.value();
+            *bAppChange = true;
+            if (*fProposedSplitPos <=
+                fCurVerticalOffset + kXFALayoutPrecision) {
+              return true;
+            }
+          }
+        }
+        float fRelSplitPos = *fProposedSplitPos - fCurBottomMargin;
+        for (CXFA_LayoutItem* pIter = pLayoutItem->GetFirstChild(); pIter;
+             pIter = pIter->GetNextSibling()) {
+          CXFA_ContentLayoutItem* pChildItem = pIter->AsContentLayoutItem();
+          if (!pChildItem)
+            continue;
+
+          float fChildOffset =
+              fCurVerticalOffset + fCurTopMargin + pChildItem->m_sPos.y;
+          bool bChange = false;
+          if (FindLayoutItemSplitPos(pChildItem, fChildOffset, &fRelSplitPos,
+                                     &bChange, bCalculateMargin)) {
+            if (fRelSplitPos - fChildOffset < kXFALayoutPrecision && bChange) {
+              *fProposedSplitPos = fRelSplitPos - fCurTopMargin;
+            } else {
+              *fProposedSplitPos = fRelSplitPos + fCurBottomMargin;
+            }
+            bAnyChanged = true;
+            bChanged = true;
+            if (*fProposedSplitPos <=
+                fCurVerticalOffset + kXFALayoutPrecision) {
+              return true;
+            }
+            if (bAnyChanged)
+              break;
+          }
+        }
+      }
+      return bAnyChanged;
+    }
+    case XFA_AttributeValue::ContentArea:
+    case XFA_AttributeValue::PageArea: {
+      *fProposedSplitPos = fCurVerticalOffset;
+      return true;
+    }
+    default:
+      return false;
+  }
+}
+
+CFX_PointF CalculatePositionedContainerPos(CXFA_Node* pNode,
+                                           const CFX_SizeF& size) {
+  XFA_AttributeValue eAnchorType =
+      pNode->JSObject()->GetEnum(XFA_Attribute::AnchorType);
+  int32_t nAnchorType = 0;
+  switch (eAnchorType) {
+    case XFA_AttributeValue::TopLeft:
+      nAnchorType = 0;
+      break;
+    case XFA_AttributeValue::TopCenter:
+      nAnchorType = 1;
+      break;
+    case XFA_AttributeValue::TopRight:
+      nAnchorType = 2;
+      break;
+    case XFA_AttributeValue::MiddleLeft:
+      nAnchorType = 3;
+      break;
+    case XFA_AttributeValue::MiddleCenter:
+      nAnchorType = 4;
+      break;
+    case XFA_AttributeValue::MiddleRight:
+      nAnchorType = 5;
+      break;
+    case XFA_AttributeValue::BottomLeft:
+      nAnchorType = 6;
+      break;
+    case XFA_AttributeValue::BottomCenter:
+      nAnchorType = 7;
+      break;
+    case XFA_AttributeValue::BottomRight:
+      nAnchorType = 8;
+      break;
+    default:
+      break;
+  }
+  static const uint8_t nNextPos[4][9] = {{0, 1, 2, 3, 4, 5, 6, 7, 8},
+                                         {6, 3, 0, 7, 4, 1, 8, 5, 2},
+                                         {8, 7, 6, 5, 4, 3, 2, 1, 0},
+                                         {2, 5, 8, 1, 4, 7, 0, 3, 6}};
+
+  CFX_PointF pos(
+      pNode->JSObject()->GetMeasureInUnit(XFA_Attribute::X, XFA_Unit::Pt),
+      pNode->JSObject()->GetMeasureInUnit(XFA_Attribute::Y, XFA_Unit::Pt));
+  int32_t nRotate =
+      XFA_MapRotation(pNode->JSObject()->GetInteger(XFA_Attribute::Rotate)) /
+      90;
+  int32_t nAbsoluteAnchorType = nNextPos[nRotate][nAnchorType];
+  switch (nAbsoluteAnchorType / 3) {
+    case 1:
+      pos.y -= size.height / 2;
+      break;
+    case 2:
+      pos.y -= size.height;
+      break;
+    default:
+      break;
+  }
+  switch (nAbsoluteAnchorType % 3) {
+    case 1:
+      pos.x -= size.width / 2;
+      break;
+    case 2:
+      pos.x -= size.width;
+      break;
+    default:
+      break;
+  }
+  return pos;
+}
+
+}  // namespace
+
+CXFA_ContentLayoutProcessor::CXFA_ContentLayoutProcessor(
+    CXFA_Node* pNode,
+    CXFA_ViewLayoutProcessor* pViewLayoutProcessor)
+    : m_pFormNode(pNode), m_pViewLayoutProcessor(pViewLayoutProcessor) {
+  ASSERT(GetFormNode());
+  ASSERT(GetFormNode()->IsContainerNode() ||
+         GetFormNode()->GetElementType() == XFA_Element::Form);
+  m_pOldLayoutItem.Reset(
+      ToContentLayoutItem(GetFormNode()->JSObject()->GetLayoutItem()));
+}
+
+CXFA_ContentLayoutProcessor::~CXFA_ContentLayoutProcessor() {}
+
+RetainPtr<CXFA_ContentLayoutItem>
+CXFA_ContentLayoutProcessor::CreateContentLayoutItem(CXFA_Node* pFormNode) {
+  if (!pFormNode)
+    return nullptr;
+
+  if (m_pOldLayoutItem) {
+    RetainPtr<CXFA_ContentLayoutItem> pLayoutItem = m_pOldLayoutItem;
+    m_pOldLayoutItem.Reset(m_pOldLayoutItem->GetNext());
+    return pLayoutItem;
+  }
+  CXFA_FFNotify* pNotify = pFormNode->GetDocument()->GetNotify();
+  auto pNewLayoutItem = pdfium::MakeRetain<CXFA_ContentLayoutItem>(
+      pFormNode, pNotify->OnCreateContentLayoutItem(pFormNode));
+
+  CXFA_ContentLayoutItem* pPrevLayoutItem =
+      ToContentLayoutItem(pFormNode->JSObject()->GetLayoutItem());
+  if (pPrevLayoutItem) {
+    pPrevLayoutItem->GetLast()->InsertAfter(pNewLayoutItem.Get());
+  } else {
+    pFormNode->JSObject()->SetLayoutItem(pNewLayoutItem.Get());
+  }
+  return pNewLayoutItem;
+}
+
+float CXFA_ContentLayoutProcessor::FindSplitPos(float fProposedSplitPos) {
+  ASSERT(m_pLayoutItem);
+  auto value = GetFormNode()->JSObject()->TryEnum(XFA_Attribute::Layout, true);
+  XFA_AttributeValue eLayout = value.value_or(XFA_AttributeValue::Position);
+  bool bCalculateMargin = eLayout != XFA_AttributeValue::Position;
+  while (fProposedSplitPos > kXFALayoutPrecision) {
+    bool bAppChange = false;
+    if (!FindLayoutItemSplitPos(m_pLayoutItem.Get(), 0, &fProposedSplitPos,
+                                &bAppChange, bCalculateMargin)) {
+      break;
+    }
+  }
+  return fProposedSplitPos;
+}
+
+void CXFA_ContentLayoutProcessor::SplitLayoutItem(
+    CXFA_ContentLayoutItem* pLayoutItem,
+    CXFA_ContentLayoutItem* pSecondParent,
+    float fSplitPos) {
+  float fCurTopMargin = 0;
+  float fCurBottomMargin = 0;
+  auto value = GetFormNode()->JSObject()->TryEnum(XFA_Attribute::Layout, true);
+  XFA_AttributeValue eLayout = value.value_or(XFA_AttributeValue::Position);
+  bool bCalculateMargin = true;
+  if (eLayout == XFA_AttributeValue::Position)
+    bCalculateMargin = false;
+
+  CXFA_Margin* pMarginNode =
+      pLayoutItem->GetFormNode()->GetFirstChildByClass<CXFA_Margin>(
+          XFA_Element::Margin);
+  if (pMarginNode && bCalculateMargin) {
+    fCurTopMargin = pMarginNode->JSObject()->GetMeasureInUnit(
+        XFA_Attribute::TopInset, XFA_Unit::Pt);
+    fCurBottomMargin = pMarginNode->JSObject()->GetMeasureInUnit(
+        XFA_Attribute::BottomInset, XFA_Unit::Pt);
+  }
+
+  RetainPtr<CXFA_ContentLayoutItem> pSecondLayoutItem;
+  if (m_pCurChildPreprocessor &&
+      m_pCurChildPreprocessor->GetFormNode() == pLayoutItem->GetFormNode()) {
+    pSecondLayoutItem = m_pCurChildPreprocessor->CreateContentLayoutItem(
+        pLayoutItem->GetFormNode());
+  } else {
+    pSecondLayoutItem = CreateContentLayoutItem(pLayoutItem->GetFormNode());
+  }
+  pSecondLayoutItem->m_sPos.x = pLayoutItem->m_sPos.x;
+  pSecondLayoutItem->m_sSize.width = pLayoutItem->m_sSize.width;
+  pSecondLayoutItem->m_sPos.y = 0;
+  pSecondLayoutItem->m_sSize.height = pLayoutItem->m_sSize.height - fSplitPos;
+  pLayoutItem->m_sSize.height -= pSecondLayoutItem->m_sSize.height;
+  if (pLayoutItem->GetFirstChild())
+    pSecondLayoutItem->m_sSize.height += fCurTopMargin;
+
+  bool bOrphanedItem = false;
+  if (pSecondParent) {
+    pSecondParent->AppendLastChild(pSecondLayoutItem);
+    if (fCurTopMargin > 0 && pLayoutItem->GetFirstChild()) {
+      pSecondParent->m_sSize.height += fCurTopMargin;
+      for (CXFA_LayoutItem* pParentIter = pSecondParent->GetParent();
+           pParentIter; pParentIter = pParentIter->GetParent()) {
+        CXFA_ContentLayoutItem* pContentItem =
+            pParentIter->AsContentLayoutItem();
+        if (!pContentItem)
+          continue;
+
+        pContentItem->m_sSize.height += fCurTopMargin;
+      }
+    }
+  } else if (pLayoutItem->GetParent()) {
+    pLayoutItem->GetParent()->InsertAfter(pSecondLayoutItem, pLayoutItem);
+  } else {
+    // Parentless |pLayoutitem| would like to have |pSecondLayoutItem| as a
+    // sibling, but that would violate the tree invariant. Instead, keep
+    // it an orphan and add it as a child of |pLayoutItem| after performing
+    // the split.
+    bOrphanedItem = true;
+  }
+
+  std::vector<RetainPtr<CXFA_ContentLayoutItem>> children;
+  while (auto* pFirst = ToContentLayoutItem(pLayoutItem->GetFirstChild())) {
+    children.emplace_back(pFirst);
+    pLayoutItem->RemoveChild(children.back());
+  }
+
+  float lHeightForKeep = 0;
+  float fAddMarginHeight = 0;
+  std::vector<RetainPtr<CXFA_ContentLayoutItem>> keepLayoutItems;
+  for (auto& pChildItem : children) {
+    if (fSplitPos <= fCurTopMargin + pChildItem->m_sPos.y + fCurBottomMargin +
+                         kXFALayoutPrecision) {
+      if (!ExistContainerKeep(pChildItem->GetFormNode(), true)) {
+        pChildItem->m_sPos.y -= fSplitPos - fCurBottomMargin;
+        pChildItem->m_sPos.y += lHeightForKeep;
+        pChildItem->m_sPos.y += fAddMarginHeight;
+        pSecondLayoutItem->AppendLastChild(pChildItem);
+        continue;
+      }
+      if (lHeightForKeep < kXFALayoutPrecision) {
+        for (auto& pPreItem : keepLayoutItems) {
+          pLayoutItem->RemoveChild(pPreItem);
+          pPreItem->m_sPos.y -= fSplitPos;
+          if (pPreItem->m_sPos.y < 0)
+            pPreItem->m_sPos.y = 0;
+          if (pPreItem->m_sPos.y + pPreItem->m_sSize.height > lHeightForKeep) {
+            pPreItem->m_sPos.y = lHeightForKeep;
+            lHeightForKeep += pPreItem->m_sSize.height;
+            pSecondLayoutItem->m_sSize.height += pPreItem->m_sSize.height;
+            if (pSecondParent)
+              pSecondParent->m_sSize.height += pPreItem->m_sSize.height;
+          }
+          pSecondLayoutItem->AppendLastChild(pPreItem);
+        }
+      }
+      pChildItem->m_sPos.y -= fSplitPos;
+      pChildItem->m_sPos.y += lHeightForKeep;
+      pChildItem->m_sPos.y += fAddMarginHeight;
+      pSecondLayoutItem->AppendLastChild(pChildItem);
+      continue;
+    }
+    if (fSplitPos + kXFALayoutPrecision >= fCurTopMargin + fCurBottomMargin +
+                                               pChildItem->m_sPos.y +
+                                               pChildItem->m_sSize.height) {
+      pLayoutItem->AppendLastChild(pChildItem);
+      if (ExistContainerKeep(pChildItem->GetFormNode(), false))
+        keepLayoutItems.push_back(pChildItem);
+      else
+        keepLayoutItems.clear();
+      continue;
+    }
+
+    float fOldHeight = pSecondLayoutItem->m_sSize.height;
+    SplitLayoutItem(
+        pChildItem.Get(), pSecondLayoutItem.Get(),
+        fSplitPos - fCurTopMargin - fCurBottomMargin - pChildItem->m_sPos.y);
+    fAddMarginHeight = pSecondLayoutItem->m_sSize.height - fOldHeight;
+    pLayoutItem->AppendLastChild(pChildItem);
+  }
+  if (bOrphanedItem)
+    pLayoutItem->AppendLastChild(pSecondLayoutItem);
+}
+
+void CXFA_ContentLayoutProcessor::SplitLayoutItem(float fSplitPos) {
+  ASSERT(m_pLayoutItem);
+  SplitLayoutItem(m_pLayoutItem.Get(), nullptr, fSplitPos);
+}
+
+RetainPtr<CXFA_ContentLayoutItem>
+CXFA_ContentLayoutProcessor::ExtractLayoutItem() {
+  RetainPtr<CXFA_ContentLayoutItem> pLayoutItem = m_pLayoutItem;
+  if (pLayoutItem) {
+    m_pLayoutItem.Reset(ToContentLayoutItem(pLayoutItem->GetNextSibling()));
+    pLayoutItem->RemoveSelfIfParented();
+  }
+  if (m_nCurChildNodeStage != Stage::kDone || !m_pOldLayoutItem)
+    return pLayoutItem;
+
+  CXFA_FFNotify* pNotify =
+      m_pOldLayoutItem->GetFormNode()->GetDocument()->GetNotify();
+  auto* pDocLayout = CXFA_LayoutProcessor::FromDocument(
+      m_pOldLayoutItem->GetFormNode()->GetDocument());
+
+  while (m_pOldLayoutItem) {
+    RetainPtr<CXFA_ContentLayoutItem> pToDeleteItem = m_pOldLayoutItem;
+    m_pOldLayoutItem.Reset(pToDeleteItem->GetNext());
+    if (pToDeleteItem == pLayoutItem)
+      break;
+    pNotify->OnLayoutItemRemoving(pDocLayout, pToDeleteItem.Get());
+    pToDeleteItem->RemoveSelfIfParented();
+  }
+  return pLayoutItem;
+}
+
+void CXFA_ContentLayoutProcessor::GotoNextContainerNodeSimple(
+    bool bUsePageBreak) {
+  m_nCurChildNodeStage = GotoNextContainerNode(
+      m_nCurChildNodeStage, bUsePageBreak, GetFormNode(), &m_pCurChildNode);
+}
+
+CXFA_ContentLayoutProcessor::Stage
+CXFA_ContentLayoutProcessor::GotoNextContainerNode(Stage nCurStage,
+                                                   bool bUsePageBreak,
+                                                   CXFA_Node* pParentContainer,
+                                                   CXFA_Node** pCurActionNode) {
+  CXFA_Node* pChildContainer = nullptr;
+  switch (nCurStage) {
+    case Stage::kBreakBefore:
+    case Stage::kBreakAfter: {
+      pChildContainer = (*pCurActionNode)->GetParent();
+      break;
+    }
+    case Stage::kKeep:
+    case Stage::kContainer:
+      pChildContainer = *pCurActionNode;
+      break;
+    default:
+      pChildContainer = nullptr;
+      break;
+  }
+
+  Optional<Stage> ret;
+  switch (nCurStage) {
+    case Stage::kKeep:
+      ret = HandleKeep(pChildContainer->GetFirstChild(), pCurActionNode);
+      if (ret.has_value())
+        return ret.value();
+      break;
+
+    case Stage::kNone:
+      *pCurActionNode = nullptr;
+      FALLTHROUGH;
+
+    case Stage::kBookendLeader:
+      ret = HandleBookendLeader(pParentContainer, pCurActionNode);
+      if (ret.has_value())
+        return ret.value();
+
+      *pCurActionNode = nullptr;
+      FALLTHROUGH;
+
+    case Stage::kBreakBefore:
+      ret = HandleBreakBefore(pChildContainer, pCurActionNode);
+      if (ret.has_value())
+        return ret.value();
+      break;
+
+    case Stage::kContainer:
+      *pCurActionNode = nullptr;
+      FALLTHROUGH;
+
+    case Stage::kBreakAfter:
+      ret = HandleBreakAfter(pChildContainer, pCurActionNode);
+      if (ret.has_value())
+        return ret.value();
+      break;
+
+    case Stage::kBookendTrailer:
+      ret = HandleBookendTrailer(pParentContainer, pCurActionNode);
+      if (ret.has_value())
+        return ret.value();
+      FALLTHROUGH;
+
+    default:
+      *pCurActionNode = nullptr;
+      return Stage::kDone;
+  }
+
+  ret = HandleCheckNextChildContainer(pParentContainer, pChildContainer,
+                                      pCurActionNode);
+  if (ret.has_value())
+    return ret.value();
+
+  *pCurActionNode = nullptr;
+  ret = HandleBookendTrailer(pParentContainer, pCurActionNode);
+  if (ret.has_value())
+    return ret.value();
+
+  *pCurActionNode = nullptr;
+  return Stage::kDone;
+}
+
+Optional<CXFA_ContentLayoutProcessor::Stage>
+CXFA_ContentLayoutProcessor::ProcessKeepNodesForCheckNext(
+    CXFA_Node** pCurActionNode,
+    CXFA_Node** pNextContainer,
+    bool* pLastKeepNode) {
+  const bool bCanSplit =
+      (*pNextContainer)->GetIntact() == XFA_AttributeValue::None;
+  const bool bNextKeep = ExistContainerKeep(*pNextContainer, false);
+
+  if (bNextKeep && !bCanSplit) {
+    if (!m_bIsProcessKeep && !m_bKeepBreakFinish) {
+      m_pKeepHeadNode = *pNextContainer;
+      m_bIsProcessKeep = true;
+    }
+    return {};
+  }
+
+  if (!m_bIsProcessKeep || !m_pKeepHeadNode) {
+    if (m_bKeepBreakFinish)
+      *pLastKeepNode = true;
+    m_bKeepBreakFinish = false;
+    return {};
+  }
+
+  m_pKeepTailNode = *pNextContainer;
+  if (m_bKeepBreakFinish) {
+    *pNextContainer = m_pKeepHeadNode;
+    ProcessKeepNodesEnd();
+    return {};
+  }
+
+  Optional<Stage> ret =
+      FindBreakNode((*pNextContainer)->GetFirstChild(), true, pCurActionNode);
+  if (!ret.has_value()) {
+    *pNextContainer = m_pKeepHeadNode;
+    ProcessKeepNodesEnd();
+    return {};
+  }
+
+  return ret;
+}
+
+Optional<CXFA_ContentLayoutProcessor::Stage>
+CXFA_ContentLayoutProcessor::ProcessKeepNodesForBreakBefore(
+    CXFA_Node** pCurActionNode,
+    CXFA_Node* pContainerNode) {
+  if (m_pKeepTailNode == pContainerNode) {
+    *pCurActionNode = m_pKeepHeadNode;
+    ProcessKeepNodesEnd();
+    return Stage::kContainer;
+  }
+
+  CXFA_Node* pBreakAfterNode = pContainerNode->GetFirstChild();
+  return FindBreakNode(pBreakAfterNode, false, pCurActionNode);
+}
+
+void CXFA_ContentLayoutProcessor::DoLayoutPageArea(
+    CXFA_ViewLayoutItem* pPageAreaLayoutItem) {
+  CXFA_Node* pFormNode = pPageAreaLayoutItem->GetFormNode();
+  CXFA_Node* pCurChildNode = nullptr;
+  CXFA_LayoutItem* pBeforeItem = nullptr;
+  for (Stage nCurChildNodeStage = GotoNextContainerNode(
+           Stage::kNone, false, pFormNode, &pCurChildNode);
+       pCurChildNode;
+       nCurChildNodeStage = GotoNextContainerNode(nCurChildNodeStage, false,
+                                                  pFormNode, &pCurChildNode)) {
+    if (nCurChildNodeStage != Stage::kContainer)
+      continue;
+    if (pCurChildNode->GetElementType() == XFA_Element::Variables)
+      continue;
+
+    auto pProcessor =
+        pdfium::MakeUnique<CXFA_ContentLayoutProcessor>(pCurChildNode, nullptr);
+    pProcessor->DoLayout(false, FLT_MAX, FLT_MAX);
+    if (!pProcessor->HasLayoutItem())
+      continue;
+
+    pProcessor->SetCurrentComponentPos(CalculatePositionedContainerPos(
+        pCurChildNode, pProcessor->GetCurrentComponentSize()));
+    RetainPtr<CXFA_LayoutItem> pProcessItem = pProcessor->ExtractLayoutItem();
+    if (!pBeforeItem)
+      pPageAreaLayoutItem->AppendFirstChild(pProcessItem);
+    else
+      pPageAreaLayoutItem->InsertAfter(pProcessItem, pBeforeItem);
+
+    pBeforeItem = pProcessItem.Get();
+  }
+
+  pBeforeItem = nullptr;
+  RetainPtr<CXFA_LayoutItem> pLayoutItem(pPageAreaLayoutItem->GetFirstChild());
+  while (pLayoutItem) {
+    if (!pLayoutItem->IsContentLayoutItem() ||
+        pLayoutItem->GetFormNode()->GetElementType() != XFA_Element::Draw) {
+      pLayoutItem.Reset(pLayoutItem->GetNextSibling());
+      continue;
+    }
+    if (pLayoutItem->GetFormNode()->GetElementType() != XFA_Element::Draw)
+      continue;
+
+    CXFA_LayoutItem* pNextLayoutItem = pLayoutItem->GetNextSibling();
+    pPageAreaLayoutItem->RemoveChild(pLayoutItem);
+    if (!pBeforeItem)
+      pPageAreaLayoutItem->AppendFirstChild(pLayoutItem);
+    else
+      pPageAreaLayoutItem->InsertAfter(pLayoutItem, pBeforeItem);
+
+    pBeforeItem = pLayoutItem.Get();
+    pLayoutItem.Reset(pNextLayoutItem);
+  }
+}
+
+void CXFA_ContentLayoutProcessor::DoLayoutPositionedContainer(
+    Context* pContext) {
+  if (m_pLayoutItem)
+    return;
+
+  m_pLayoutItem = CreateContentLayoutItem(GetFormNode());
+  auto value = GetFormNode()->JSObject()->TryEnum(XFA_Attribute::Layout, true);
+  bool bIgnoreXY = value.value_or(XFA_AttributeValue::Position) !=
+                   XFA_AttributeValue::Position;
+  bool bContainerWidthAutoSize = true;
+  bool bContainerHeightAutoSize = true;
+  CFX_SizeF containerSize = CalculateContainerSpecifiedSize(
+      GetFormNode(), &bContainerWidthAutoSize, &bContainerHeightAutoSize);
+
+  float fContentCalculatedWidth = 0;
+  float fContentCalculatedHeight = 0;
+  float fHiddenContentCalculatedWidth = 0;
+  float fHiddenContentCalculatedHeight = 0;
+  if (!m_pCurChildNode)
+    GotoNextContainerNodeSimple(false);
+
+  int32_t iColIndex = 0;
+  for (; m_pCurChildNode; GotoNextContainerNodeSimple(false)) {
+    if (m_nCurChildNodeStage != Stage::kContainer)
+      continue;
+    if (m_pCurChildNode->GetElementType() == XFA_Element::Variables)
+      continue;
+
+    auto pProcessor = pdfium::MakeUnique<CXFA_ContentLayoutProcessor>(
+        m_pCurChildNode, m_pViewLayoutProcessor.Get());
+    if (pContext && pContext->m_prgSpecifiedColumnWidths) {
+      int32_t iColSpan =
+          m_pCurChildNode->JSObject()->GetInteger(XFA_Attribute::ColSpan);
+      if (iColSpan <= pdfium::CollectionSize<int32_t>(
+                          *pContext->m_prgSpecifiedColumnWidths) -
+                          iColIndex) {
+        pContext->m_fCurColumnWidth = 0.0f;
+        if (iColSpan == -1) {
+          iColSpan = pdfium::CollectionSize<int32_t>(
+              *pContext->m_prgSpecifiedColumnWidths);
+        }
+        for (int32_t i = 0; iColIndex + i < iColSpan; ++i) {
+          pContext->m_fCurColumnWidth.value() +=
+              (*pContext->m_prgSpecifiedColumnWidths)[iColIndex + i];
+        }
+        if (pContext->m_fCurColumnWidth.value() == 0)
+          pContext->m_fCurColumnWidth.reset();
+
+        iColIndex += iColSpan >= 0 ? iColSpan : 0;
+      }
+    }
+
+    pProcessor->DoLayoutInternal(false, FLT_MAX, FLT_MAX, pContext);
+    if (!pProcessor->HasLayoutItem())
+      continue;
+
+    CFX_SizeF size = pProcessor->GetCurrentComponentSize();
+    bool bChangeParentSize = false;
+    if (m_pCurChildNode->PresenceRequiresSpace())
+      bChangeParentSize = true;
+
+    CFX_PointF absolutePos;
+    if (!bIgnoreXY)
+      absolutePos = CalculatePositionedContainerPos(m_pCurChildNode, size);
+
+    pProcessor->SetCurrentComponentPos(absolutePos);
+    if (bContainerWidthAutoSize) {
+      float fChildSuppliedWidth = absolutePos.x + size.width;
+      if (bChangeParentSize) {
+        fContentCalculatedWidth =
+            std::max(fContentCalculatedWidth, fChildSuppliedWidth);
+      } else {
+        if (fHiddenContentCalculatedWidth < fChildSuppliedWidth &&
+            m_pCurChildNode->GetElementType() != XFA_Element::Subform) {
+          fHiddenContentCalculatedWidth = fChildSuppliedWidth;
+        }
+      }
+    }
+
+    if (bContainerHeightAutoSize) {
+      float fChildSuppliedHeight = absolutePos.y + size.height;
+      if (bChangeParentSize) {
+        fContentCalculatedHeight =
+            std::max(fContentCalculatedHeight, fChildSuppliedHeight);
+      } else {
+        if (fHiddenContentCalculatedHeight < fChildSuppliedHeight &&
+            m_pCurChildNode->GetElementType() != XFA_Element::Subform) {
+          fHiddenContentCalculatedHeight = fChildSuppliedHeight;
+        }
+      }
+    }
+    m_pLayoutItem->AppendLastChild(pProcessor->ExtractLayoutItem());
+  }
+
+  XFA_VERSION eVersion = GetFormNode()->GetDocument()->GetCurVersionMode();
+  if (fContentCalculatedWidth == 0 && eVersion < XFA_VERSION_207)
+    fContentCalculatedWidth = fHiddenContentCalculatedWidth;
+  if (fContentCalculatedHeight == 0 && eVersion < XFA_VERSION_207)
+    fContentCalculatedHeight = fHiddenContentCalculatedHeight;
+
+  containerSize = CalculateContainerComponentSizeFromContentSize(
+      GetFormNode(), bContainerWidthAutoSize, fContentCalculatedWidth,
+      bContainerHeightAutoSize, fContentCalculatedHeight, containerSize);
+  SetCurrentComponentSize(containerSize);
+}
+
+void CXFA_ContentLayoutProcessor::DoLayoutTableContainer(
+    CXFA_Node* pLayoutNode) {
+  if (m_pLayoutItem)
+    return;
+  if (!pLayoutNode)
+    pLayoutNode = GetFormNode();
+
+  ASSERT(!m_pCurChildNode);
+
+  m_pLayoutItem = CreateContentLayoutItem(GetFormNode());
+  bool bContainerWidthAutoSize = true;
+  bool bContainerHeightAutoSize = true;
+  CFX_SizeF containerSize = CalculateContainerSpecifiedSize(
+      GetFormNode(), &bContainerWidthAutoSize, &bContainerHeightAutoSize);
+  float fContentCalculatedWidth = 0;
+  float fContentCalculatedHeight = 0;
+  CXFA_Margin* pMarginNode =
+      GetFormNode()->GetFirstChildByClass<CXFA_Margin>(XFA_Element::Margin);
+  float fLeftInset = 0;
+  float fRightInset = 0;
+  if (pMarginNode) {
+    fLeftInset = pMarginNode->JSObject()->GetMeasureInUnit(
+        XFA_Attribute::LeftInset, XFA_Unit::Pt);
+    fRightInset = pMarginNode->JSObject()->GetMeasureInUnit(
+        XFA_Attribute::RightInset, XFA_Unit::Pt);
+  }
+
+  float fContentWidthLimit =
+      bContainerWidthAutoSize ? FLT_MAX
+                              : containerSize.width - fLeftInset - fRightInset;
+  WideString wsColumnWidths =
+      pLayoutNode->JSObject()->GetCData(XFA_Attribute::ColumnWidths);
+  if (!wsColumnWidths.IsEmpty()) {
+    for (auto& width : SeparateStringOnSpace(wsColumnWidths.span())) {
+      width.TrimLeft(L' ');
+      if (width.IsEmpty())
+        continue;
+
+      m_rgSpecifiedColumnWidths.push_back(
+          CXFA_Measurement(width.AsStringView()).ToUnit(XFA_Unit::Pt));
+    }
+  }
+
+  int32_t iSpecifiedColumnCount =
+      pdfium::CollectionSize<int32_t>(m_rgSpecifiedColumnWidths);
+  Context layoutContext;
+  layoutContext.m_prgSpecifiedColumnWidths = &m_rgSpecifiedColumnWidths;
+  Context* pLayoutContext =
+      iSpecifiedColumnCount > 0 ? &layoutContext : nullptr;
+  if (!m_pCurChildNode)
+    GotoNextContainerNodeSimple(false);
+
+  for (; m_pCurChildNode; GotoNextContainerNodeSimple(false)) {
+    layoutContext.m_fCurColumnWidth.reset();
+    if (m_nCurChildNodeStage != Stage::kContainer)
+      continue;
+
+    auto pProcessor = pdfium::MakeUnique<CXFA_ContentLayoutProcessor>(
+        m_pCurChildNode, m_pViewLayoutProcessor.Get());
+    pProcessor->DoLayoutInternal(false, FLT_MAX, FLT_MAX, pLayoutContext);
+    if (!pProcessor->HasLayoutItem())
+      continue;
+
+    m_pLayoutItem->AppendLastChild(pProcessor->ExtractLayoutItem());
+  }
+
+  int32_t iRowCount = 0;
+  int32_t iColCount = 0;
+  {
+    std::vector<CXFA_ContentLayoutItem*> rgRowItems;
+    std::vector<int32_t> rgRowItemsSpan;
+    std::vector<float> rgRowItemsWidth;
+    for (CXFA_LayoutItem* pIter = m_pLayoutItem->GetFirstChild(); pIter;
+         pIter = pIter->GetNextSibling()) {
+      CXFA_ContentLayoutItem* pLayoutChild = pIter->AsContentLayoutItem();
+      if (!pLayoutChild)
+        continue;
+      if (pLayoutChild->GetFormNode()->GetElementType() != XFA_Element::Subform)
+        continue;
+      if (!pLayoutChild->GetFormNode()->PresenceRequiresSpace())
+        continue;
+
+      XFA_AttributeValue eLayout =
+          pLayoutChild->GetFormNode()->JSObject()->GetEnum(
+              XFA_Attribute::Layout);
+      if (eLayout != XFA_AttributeValue::Row &&
+          eLayout != XFA_AttributeValue::Rl_row) {
+        continue;
+      }
+      CXFA_ContentLayoutItem* pRowLayoutCell =
+          ToContentLayoutItem(pLayoutChild->GetFirstChild());
+      if (pRowLayoutCell) {
+        rgRowItems.push_back(pRowLayoutCell);
+        int32_t iColSpan =
+            pRowLayoutCell->GetFormNode()->JSObject()->GetInteger(
+                XFA_Attribute::ColSpan);
+        rgRowItemsSpan.push_back(iColSpan);
+        rgRowItemsWidth.push_back(pRowLayoutCell->m_sSize.width);
+      }
+    }
+
+    iRowCount = pdfium::CollectionSize<int32_t>(rgRowItems);
+    iColCount = 0;
+    bool bMoreColumns = true;
+    while (bMoreColumns) {
+      bMoreColumns = false;
+      bool bAutoCol = false;
+      for (int32_t i = 0; i < iRowCount; i++) {
+        while (rgRowItems[i] &&
+               (rgRowItemsSpan[i] <= 0 ||
+                !rgRowItems[i]->GetFormNode()->PresenceRequiresSpace())) {
+          CXFA_ContentLayoutItem* pNewCell =
+              ToContentLayoutItem(rgRowItems[i]->GetNextSibling());
+          if (rgRowItemsSpan[i] < 0 &&
+              rgRowItems[i]->GetFormNode()->PresenceRequiresSpace()) {
+            pNewCell = nullptr;
+          }
+          rgRowItems[i] = pNewCell;
+          rgRowItemsSpan[i] =
+              pNewCell ? pNewCell->GetFormNode()->JSObject()->GetInteger(
+                             XFA_Attribute::ColSpan)
+                       : 0;
+          rgRowItemsWidth[i] = pNewCell ? pNewCell->m_sSize.width : 0;
+        }
+        CXFA_ContentLayoutItem* pCell = rgRowItems[i];
+        if (!pCell)
+          continue;
+
+        bMoreColumns = true;
+        if (rgRowItemsSpan[i] != 1)
+          continue;
+
+        if (iColCount >= iSpecifiedColumnCount) {
+          int32_t c =
+              iColCount + 1 -
+              pdfium::CollectionSize<int32_t>(m_rgSpecifiedColumnWidths);
+          for (int32_t j = 0; j < c; j++)
+            m_rgSpecifiedColumnWidths.push_back(0);
+        }
+        if (m_rgSpecifiedColumnWidths[iColCount] < kXFALayoutPrecision)
+          bAutoCol = true;
+        if (bAutoCol &&
+            m_rgSpecifiedColumnWidths[iColCount] < rgRowItemsWidth[i]) {
+          m_rgSpecifiedColumnWidths[iColCount] = rgRowItemsWidth[i];
+        }
+      }
+
+      if (!bMoreColumns)
+        continue;
+
+      float fFinalColumnWidth = 0.0f;
+      if (pdfium::IndexInBounds(m_rgSpecifiedColumnWidths, iColCount))
+        fFinalColumnWidth = m_rgSpecifiedColumnWidths[iColCount];
+
+      for (int32_t i = 0; i < iRowCount; ++i) {
+        if (!rgRowItems[i])
+          continue;
+        --rgRowItemsSpan[i];
+        rgRowItemsWidth[i] -= fFinalColumnWidth;
+      }
+      ++iColCount;
+    }
+  }
+
+  float fCurrentRowY = 0;
+  for (CXFA_LayoutItem* pIter = m_pLayoutItem->GetFirstChild(); pIter;
+       pIter = pIter->GetNextSibling()) {
+    RetainPtr<CXFA_ContentLayoutItem> pLayoutChild(
+        pIter->AsContentLayoutItem());
+    if (!pLayoutChild || !pLayoutChild->GetFormNode()->PresenceRequiresSpace())
+      continue;
+
+    if (pLayoutChild->GetFormNode()->GetElementType() == XFA_Element::Subform) {
+      XFA_AttributeValue eSubformLayout =
+          pLayoutChild->GetFormNode()->JSObject()->GetEnum(
+              XFA_Attribute::Layout);
+      if (eSubformLayout == XFA_AttributeValue::Row ||
+          eSubformLayout == XFA_AttributeValue::Rl_row) {
+        RelocateTableRowCells(pLayoutChild, m_rgSpecifiedColumnWidths,
+                              eSubformLayout);
+      }
+    }
+
+    pLayoutChild->m_sPos.y = fCurrentRowY;
+    if (bContainerWidthAutoSize) {
+      pLayoutChild->m_sPos.x = 0;
+    } else {
+      switch (pLayoutChild->GetFormNode()->JSObject()->GetEnum(
+          XFA_Attribute::HAlign)) {
+        case XFA_AttributeValue::Center:
+          pLayoutChild->m_sPos.x =
+              (fContentWidthLimit - pLayoutChild->m_sSize.width) / 2;
+          break;
+        case XFA_AttributeValue::Right:
+          pLayoutChild->m_sPos.x =
+              fContentWidthLimit - pLayoutChild->m_sSize.width;
+          break;
+        case XFA_AttributeValue::Left:
+        default:
+          pLayoutChild->m_sPos.x = 0;
+          break;
+      }
+    }
+
+    if (bContainerWidthAutoSize) {
+      float fChildSuppliedWidth =
+          pLayoutChild->m_sPos.x + pLayoutChild->m_sSize.width;
+      if (fContentWidthLimit < FLT_MAX &&
+          fContentWidthLimit > fChildSuppliedWidth) {
+        fChildSuppliedWidth = fContentWidthLimit;
+      }
+      fContentCalculatedWidth =
+          std::max(fContentCalculatedWidth, fChildSuppliedWidth);
+    }
+    fCurrentRowY += pLayoutChild->m_sSize.height;
+  }
+
+  if (bContainerHeightAutoSize)
+    fContentCalculatedHeight = std::max(fContentCalculatedHeight, fCurrentRowY);
+
+  containerSize = CalculateContainerComponentSizeFromContentSize(
+      GetFormNode(), bContainerWidthAutoSize, fContentCalculatedWidth,
+      bContainerHeightAutoSize, fContentCalculatedHeight, containerSize);
+  SetCurrentComponentSize(containerSize);
+}
+
+bool CXFA_ContentLayoutProcessor::IsAddNewRowForTrailer(
+    CXFA_ContentLayoutItem* pTrailerItem) {
+  if (!pTrailerItem)
+    return false;
+
+  float fWidth = pTrailerItem->m_sSize.width;
+  XFA_AttributeValue eLayout =
+      GetFormNode()->JSObject()->GetEnum(XFA_Attribute::Layout);
+  return eLayout == XFA_AttributeValue::Tb || m_fWidthLimit <= fWidth;
+}
+
+float CXFA_ContentLayoutProcessor::InsertKeepLayoutItems() {
+  if (m_ArrayKeepItems.empty())
+    return 0;
+
+  if (!m_pLayoutItem) {
+    m_pLayoutItem = CreateContentLayoutItem(GetFormNode());
+    m_pLayoutItem->m_sSize.clear();
+  }
+
+  float fTotalHeight = 0;
+  for (auto iter = m_ArrayKeepItems.rbegin(); iter != m_ArrayKeepItems.rend();
+       iter++) {
+    AddLeaderAfterSplit(*iter);
+    fTotalHeight += (*iter)->m_sSize.height;
+  }
+  m_ArrayKeepItems.clear();
+
+  return fTotalHeight;
+}
+
+bool CXFA_ContentLayoutProcessor::ProcessKeepForSplit(
+    CXFA_ContentLayoutProcessor* pChildProcessor,
+    Result eRetValue,
+    std::vector<RetainPtr<CXFA_ContentLayoutItem>>* rgCurLineLayoutItem,
+    float* fContentCurRowAvailWidth,
+    float* fContentCurRowHeight,
+    float* fContentCurRowY,
+    bool* bAddedItemInRow,
+    bool* bForceEndPage,
+    Result* result) {
+  if (!pChildProcessor)
+    return false;
+
+  if (m_pCurChildNode->GetIntact() == XFA_AttributeValue::None &&
+      pChildProcessor->m_bHasAvailHeight)
+    return false;
+
+  if (!ExistContainerKeep(m_pCurChildNode, true))
+    return false;
+
+  CFX_SizeF childSize = pChildProcessor->GetCurrentComponentSize();
+  std::vector<RetainPtr<CXFA_ContentLayoutItem>> keepLayoutItems;
+  if (JudgePutNextPage(m_pLayoutItem.Get(), childSize.height,
+                       &keepLayoutItems)) {
+    m_ArrayKeepItems.clear();
+    for (auto& item : keepLayoutItems) {
+      m_pLayoutItem->RemoveChild(item);
+      *fContentCurRowY -= item->m_sSize.height;
+      m_ArrayKeepItems.push_back(item);
+    }
+    *bAddedItemInRow = true;
+    *bForceEndPage = true;
+    *result = Result::kPageFullBreak;
+    return true;
+  }
+
+  rgCurLineLayoutItem->push_back(pChildProcessor->ExtractLayoutItem());
+  *bAddedItemInRow = true;
+  *fContentCurRowAvailWidth -= childSize.width;
+  *fContentCurRowHeight = std::max(*fContentCurRowHeight, childSize.height);
+  *result = eRetValue;
+  return true;
+}
+
+bool CXFA_ContentLayoutProcessor::JudgePutNextPage(
+    CXFA_ContentLayoutItem* pParentLayoutItem,
+    float fChildHeight,
+    std::vector<RetainPtr<CXFA_ContentLayoutItem>>* pKeepItems) {
+  if (!pParentLayoutItem)
+    return false;
+
+  float fItemsHeight = 0;
+  for (CXFA_LayoutItem* pIter = pParentLayoutItem->GetFirstChild(); pIter;
+       pIter = pIter->GetNextSibling()) {
+    RetainPtr<CXFA_ContentLayoutItem> pChildLayoutItem(
+        pIter->AsContentLayoutItem());
+    if (!pChildLayoutItem)
+      continue;
+
+    if (ExistContainerKeep(pChildLayoutItem->GetFormNode(), false)) {
+      pKeepItems->push_back(pChildLayoutItem);
+      fItemsHeight += pChildLayoutItem->m_sSize.height;
+    } else {
+      pKeepItems->clear();
+      fItemsHeight = 0;
+    }
+  }
+  fItemsHeight += fChildHeight;
+  return m_pViewLayoutProcessor->GetNextAvailContentHeight(fItemsHeight);
+}
+
+void CXFA_ContentLayoutProcessor::ProcessUnUseBinds(CXFA_Node* pFormNode) {
+  if (!pFormNode)
+    return;
+
+  CXFA_NodeIterator sIterator(pFormNode);
+  for (CXFA_Node* pNode = sIterator.MoveToNext(); pNode;
+       pNode = sIterator.MoveToNext()) {
+    if (pNode->IsContainerNode()) {
+      CXFA_Node* pBindNode = pNode->GetBindData();
+      if (pBindNode) {
+        pBindNode->RemoveBindItem(pNode);
+        pNode->SetBindingNode(nullptr);
+      }
+    }
+    pNode->SetFlag(XFA_NodeFlag_UnusedNode);
+  }
+}
+
+void CXFA_ContentLayoutProcessor::ProcessUnUseOverFlow(
+    CXFA_Node* pLeaderNode,
+    CXFA_Node* pTrailerNode,
+    const RetainPtr<CXFA_ContentLayoutItem>& pTrailerItem,
+    CXFA_Node* pFormNode) {
+  ProcessUnUseBinds(pLeaderNode);
+  ProcessUnUseBinds(pTrailerNode);
+  if (!pFormNode)
+    return;
+
+  if (pFormNode->GetElementType() == XFA_Element::Overflow ||
+      pFormNode->GetElementType() == XFA_Element::Break) {
+    pFormNode = pFormNode->GetParent();
+  }
+  if (pLeaderNode && pFormNode)
+    pFormNode->RemoveChildAndNotify(pLeaderNode, true);
+  if (pTrailerNode && pFormNode)
+    pFormNode->RemoveChildAndNotify(pTrailerNode, true);
+  if (pTrailerItem)
+    XFA_ReleaseLayoutItem(pTrailerItem);
+}
+
+CXFA_ContentLayoutProcessor::Result
+CXFA_ContentLayoutProcessor::DoLayoutFlowedContainer(
+    bool bUseBreakControl,
+    XFA_AttributeValue eFlowStrategy,
+    float fHeightLimit,
+    float fRealHeight,
+    Context* pContext,
+    bool bRootForceTb) {
+  m_bHasAvailHeight = true;
+  if (m_pCurChildPreprocessor)
+    m_pCurChildPreprocessor->m_ePreProcessRs = Result::kDone;
+
+  bool bContainerWidthAutoSize = true;
+  bool bContainerHeightAutoSize = true;
+  CFX_SizeF container_size = CalculateContainerSpecifiedSize(
+      GetFormNode(), &bContainerWidthAutoSize, &bContainerHeightAutoSize);
+  AdjustContainerSpecifiedSize(pContext, &container_size,
+                               &bContainerWidthAutoSize,
+                               &bContainerHeightAutoSize);
+
+  CXFA_Margin* pMargin =
+      GetFormNode()->GetFirstChildByClass<CXFA_Margin>(XFA_Element::Margin);
+  CFX_FloatRect inset = GetMarginInset(pMargin);
+  float fContentWidthLimit =
+      bContainerWidthAutoSize ? FLT_MAX
+                              : container_size.width - inset.left - inset.right;
+  float fAvailHeight = fHeightLimit - inset.top - inset.bottom;
+  if (fAvailHeight < 0)
+    m_bHasAvailHeight = false;
+
+  fRealHeight = fRealHeight - inset.top - inset.bottom;
+  CFX_SizeF calculated_size;
+  float fContentCurRowY = 0;
+  CXFA_ContentLayoutItem* pLastChild = nullptr;
+  if (m_pLayoutItem) {
+    pLastChild = FindLastContentLayoutItem(eFlowStrategy);
+    calculated_size = CalculateLayoutItemSize(pLastChild);
+    fContentCurRowY =
+        pLastChild ? pLastChild->m_sPos.y : calculated_size.height;
+  }
+
+  fContentCurRowY += InsertKeepLayoutItems();
+  if (m_nCurChildNodeStage == Stage::kNone)
+    GotoNextContainerNodeSimple(true);
+
+  fContentCurRowY += InsertPendingItems(GetFormNode());
+  if (m_pCurChildPreprocessor && m_nCurChildNodeStage == Stage::kContainer) {
+    if (ExistContainerKeep(m_pCurChildPreprocessor->GetFormNode(), false)) {
+      m_pKeepHeadNode = m_pCurChildNode;
+      m_bIsProcessKeep = true;
+      m_nCurChildNodeStage = Stage::kKeep;
+    }
+  }
+
+  bool bForceEndPage = false;
+  bool bBreakDone = false;
+  bool bIsManualBreak = false;
+  while (m_nCurChildNodeStage != Stage::kDone) {
+    float fContentCurRowHeight = 0;
+    float fContentCurRowAvailWidth = fContentWidthLimit;
+    m_fWidthLimit = fContentCurRowAvailWidth;
+    std::vector<RetainPtr<CXFA_ContentLayoutItem>> rgCurLineLayoutItems[3];
+    uint8_t uCurHAlignState =
+        (eFlowStrategy != XFA_AttributeValue::Rl_tb ? 0 : 2);
+    if (pLastChild) {
+      for (CXFA_LayoutItem* pNext = pLastChild; pNext;
+           pNext = pNext->GetNextSibling()) {
+        CXFA_ContentLayoutItem* pLayoutNext = pNext->AsContentLayoutItem();
+        if (!pLayoutNext)
+          continue;
+        if (!pLayoutNext->GetNextSibling() && m_pCurChildPreprocessor &&
+            m_pCurChildPreprocessor->GetFormNode() ==
+                pLayoutNext->GetFormNode()) {
+          if (m_pCurChildPreprocessor->m_pLayoutItem &&
+              m_pCurChildPreprocessor->m_pLayoutItem != pLayoutNext) {
+            pLayoutNext->InsertAfter(
+                m_pCurChildPreprocessor->m_pLayoutItem.Get());
+          }
+          m_pCurChildPreprocessor->m_pLayoutItem.Reset(pLayoutNext);
+          break;
+        }
+        uint8_t uHAlign =
+            HAlignEnumToInt(pLayoutNext->GetFormNode()->JSObject()->GetEnum(
+                XFA_Attribute::HAlign));
+        rgCurLineLayoutItems[uHAlign].emplace_back(pLayoutNext);
+        if (eFlowStrategy == XFA_AttributeValue::Lr_tb) {
+          if (uHAlign > uCurHAlignState)
+            uCurHAlignState = uHAlign;
+        } else if (uHAlign < uCurHAlignState) {
+          uCurHAlignState = uHAlign;
+        }
+        if (pLayoutNext->GetFormNode()->PresenceRequiresSpace()) {
+          if (pLayoutNext->m_sSize.height > fContentCurRowHeight)
+            fContentCurRowHeight = pLayoutNext->m_sSize.height;
+          fContentCurRowAvailWidth -= pLayoutNext->m_sSize.width;
+        }
+      }
+
+      RetainPtr<CXFA_ContentLayoutItem> pLayoutNextTemp(pLastChild);
+      while (pLayoutNextTemp) {
+        CXFA_ContentLayoutItem* pSaveLayoutNext =
+            ToContentLayoutItem(pLayoutNextTemp->GetNextSibling());
+        pLayoutNextTemp->RemoveSelfIfParented();
+        pLayoutNextTemp.Reset(pSaveLayoutNext);
+      }
+      pLastChild = nullptr;
+    }
+
+    while (m_pCurChildNode) {
+      std::unique_ptr<CXFA_ContentLayoutProcessor> pProcessor;
+      bool bAddedItemInRow = false;
+      fContentCurRowY += InsertPendingItems(GetFormNode());
+      switch (m_nCurChildNodeStage) {
+        case Stage::kKeep:
+        case Stage::kNone:
+          break;
+        case Stage::kBreakBefore: {
+          for (auto& item : m_ArrayKeepItems) {
+            m_pLayoutItem->RemoveChild(item);
+            calculated_size.height -= item->m_sSize.height;
+          }
+
+          if (!bUseBreakControl || !m_pViewLayoutProcessor)
+            break;
+
+          Optional<CXFA_ViewLayoutProcessor::BreakData> break_data =
+              m_pViewLayoutProcessor->ProcessBreakBefore(m_pCurChildNode);
+          if (!break_data.has_value() || !break_data.value().bCreatePage ||
+              GetFormNode()->GetElementType() == XFA_Element::Form) {
+            break;
+          }
+
+          CXFA_Node* pLeaderNode = break_data.value().pLeader;
+          CXFA_Node* pTrailerNode = break_data.value().pTrailer;
+          if (JudgeLeaderOrTrailerForOccur(pLeaderNode))
+            AddPendingNode(pLeaderNode, true);
+
+          if (JudgeLeaderOrTrailerForOccur(pTrailerNode)) {
+            if (GetFormNode()->GetParent()->GetElementType() ==
+                    XFA_Element::Form &&
+                !m_pLayoutItem) {
+              AddPendingNode(pTrailerNode, true);
+            } else {
+              auto pTempProcessor =
+                  pdfium::MakeUnique<CXFA_ContentLayoutProcessor>(pTrailerNode,
+                                                                  nullptr);
+              InsertFlowedItem(
+                  pTempProcessor.get(), bContainerWidthAutoSize,
+                  bContainerHeightAutoSize, container_size.height,
+                  eFlowStrategy, &uCurHAlignState, rgCurLineLayoutItems, false,
+                  FLT_MAX, FLT_MAX, fContentWidthLimit, &fContentCurRowY,
+                  &fContentCurRowAvailWidth, &fContentCurRowHeight,
+                  &bAddedItemInRow, &bForceEndPage, pContext, false);
+            }
+          }
+          GotoNextContainerNodeSimple(true);
+          bForceEndPage = true;
+          bIsManualBreak = true;
+          goto SuspendAndCreateNewRow;
+        }
+        case Stage::kBreakAfter: {
+          if (!bUseBreakControl || !m_pViewLayoutProcessor)
+            break;
+
+          Optional<CXFA_ViewLayoutProcessor::BreakData> break_data =
+              m_pViewLayoutProcessor->ProcessBreakAfter(m_pCurChildNode);
+          if (!break_data.has_value() ||
+              GetFormNode()->GetElementType() == XFA_Element::Form) {
+            break;
+          }
+
+          CXFA_Node* pLeaderNode = break_data.value().pLeader;
+          CXFA_Node* pTrailerNode = break_data.value().pTrailer;
+          bool bCreatePage = break_data.value().bCreatePage;
+          if (JudgeLeaderOrTrailerForOccur(pTrailerNode)) {
+            auto pTempProcessor =
+                pdfium::MakeUnique<CXFA_ContentLayoutProcessor>(pTrailerNode,
+                                                                nullptr);
+            InsertFlowedItem(pTempProcessor.get(), bContainerWidthAutoSize,
+                             bContainerHeightAutoSize, container_size.height,
+                             eFlowStrategy, &uCurHAlignState,
+                             rgCurLineLayoutItems, false, FLT_MAX, FLT_MAX,
+                             fContentWidthLimit, &fContentCurRowY,
+                             &fContentCurRowAvailWidth, &fContentCurRowHeight,
+                             &bAddedItemInRow, &bForceEndPage, pContext, false);
+          }
+          if (!bCreatePage) {
+            if (JudgeLeaderOrTrailerForOccur(pLeaderNode)) {
+              CalculateRowChildPosition(
+                  rgCurLineLayoutItems, eFlowStrategy, bContainerHeightAutoSize,
+                  bContainerWidthAutoSize, &calculated_size.width,
+                  &calculated_size.height, &fContentCurRowY,
+                  fContentCurRowHeight, fContentWidthLimit, false);
+              rgCurLineLayoutItems->clear();
+              auto pTempProcessor =
+                  pdfium::MakeUnique<CXFA_ContentLayoutProcessor>(pLeaderNode,
+                                                                  nullptr);
+              InsertFlowedItem(
+                  pTempProcessor.get(), bContainerWidthAutoSize,
+                  bContainerHeightAutoSize, container_size.height,
+                  eFlowStrategy, &uCurHAlignState, rgCurLineLayoutItems, false,
+                  FLT_MAX, FLT_MAX, fContentWidthLimit, &fContentCurRowY,
+                  &fContentCurRowAvailWidth, &fContentCurRowHeight,
+                  &bAddedItemInRow, &bForceEndPage, pContext, false);
+            }
+          } else {
+            if (JudgeLeaderOrTrailerForOccur(pLeaderNode))
+              AddPendingNode(pLeaderNode, true);
+          }
+
+          GotoNextContainerNodeSimple(true);
+          if (bCreatePage) {
+            bForceEndPage = true;
+            bIsManualBreak = true;
+            if (m_nCurChildNodeStage == Stage::kDone)
+              bBreakDone = true;
+          }
+          goto SuspendAndCreateNewRow;
+        }
+        case Stage::kBookendLeader: {
+          if (m_pCurChildPreprocessor) {
+            pProcessor = std::move(m_pCurChildPreprocessor);
+          } else if (m_pViewLayoutProcessor) {
+            CXFA_Node* pLeaderNode =
+                m_pViewLayoutProcessor->ProcessBookendLeader(m_pCurChildNode);
+            if (pLeaderNode) {
+              pProcessor = pdfium::MakeUnique<CXFA_ContentLayoutProcessor>(
+                  pLeaderNode, m_pViewLayoutProcessor.Get());
+            }
+          }
+
+          if (pProcessor) {
+            if (InsertFlowedItem(
+                    pProcessor.get(), bContainerWidthAutoSize,
+                    bContainerHeightAutoSize, container_size.height,
+                    eFlowStrategy, &uCurHAlignState, rgCurLineLayoutItems,
+                    bUseBreakControl, fAvailHeight, fRealHeight,
+                    fContentWidthLimit, &fContentCurRowY,
+                    &fContentCurRowAvailWidth, &fContentCurRowHeight,
+                    &bAddedItemInRow, &bForceEndPage, pContext,
+                    false) != Result::kDone) {
+              goto SuspendAndCreateNewRow;
+            }
+            pProcessor.reset();
+          }
+          break;
+        }
+        case Stage::kBookendTrailer: {
+          if (m_pCurChildPreprocessor) {
+            pProcessor = std::move(m_pCurChildPreprocessor);
+          } else if (m_pViewLayoutProcessor) {
+            CXFA_Node* pTrailerNode =
+                m_pViewLayoutProcessor->ProcessBookendTrailer(m_pCurChildNode);
+            if (pTrailerNode) {
+              pProcessor = pdfium::MakeUnique<CXFA_ContentLayoutProcessor>(
+                  pTrailerNode, m_pViewLayoutProcessor.Get());
+            }
+          }
+          if (pProcessor) {
+            if (InsertFlowedItem(
+                    pProcessor.get(), bContainerWidthAutoSize,
+                    bContainerHeightAutoSize, container_size.height,
+                    eFlowStrategy, &uCurHAlignState, rgCurLineLayoutItems,
+                    bUseBreakControl, fAvailHeight, fRealHeight,
+                    fContentWidthLimit, &fContentCurRowY,
+                    &fContentCurRowAvailWidth, &fContentCurRowHeight,
+                    &bAddedItemInRow, &bForceEndPage, pContext,
+                    false) != Result::kDone) {
+              goto SuspendAndCreateNewRow;
+            }
+            pProcessor.reset();
+          }
+          break;
+        }
+        case Stage::kContainer: {
+          ASSERT(m_pCurChildNode->IsContainerNode());
+          if (m_pCurChildNode->GetElementType() == XFA_Element::Variables)
+            break;
+          if (fContentCurRowY >= fHeightLimit + kXFALayoutPrecision &&
+              m_pCurChildNode->PresenceRequiresSpace()) {
+            bForceEndPage = true;
+            goto SuspendAndCreateNewRow;
+          }
+          if (!m_pCurChildNode->IsContainerNode())
+            break;
+
+          bool bNewRow = false;
+          if (m_pCurChildPreprocessor) {
+            pProcessor = std::move(m_pCurChildPreprocessor);
+            bNewRow = true;
+          } else {
+            pProcessor = pdfium::MakeUnique<CXFA_ContentLayoutProcessor>(
+                m_pCurChildNode, m_pViewLayoutProcessor.Get());
+          }
+
+          pProcessor->InsertPendingItems(m_pCurChildNode);
+          Result rs = InsertFlowedItem(
+              pProcessor.get(), bContainerWidthAutoSize,
+              bContainerHeightAutoSize, container_size.height, eFlowStrategy,
+              &uCurHAlignState, rgCurLineLayoutItems, bUseBreakControl,
+              fAvailHeight, fRealHeight, fContentWidthLimit, &fContentCurRowY,
+              &fContentCurRowAvailWidth, &fContentCurRowHeight,
+              &bAddedItemInRow, &bForceEndPage, pContext, bNewRow);
+          switch (rs) {
+            case Result::kManualBreak:
+              bIsManualBreak = true;
+              FALLTHROUGH;
+            case Result::kPageFullBreak:
+              bForceEndPage = true;
+              FALLTHROUGH;
+            case Result::kRowFullBreak:
+              goto SuspendAndCreateNewRow;
+            case Result::kDone:
+            default:
+              fContentCurRowY +=
+                  pProcessor->InsertPendingItems(m_pCurChildNode);
+              pProcessor.reset();
+              break;
+          }
+          break;
+        }
+        case Stage::kDone:
+          break;
+        default:
+          break;
+      }
+      GotoNextContainerNodeSimple(true);
+      if (bAddedItemInRow && eFlowStrategy == XFA_AttributeValue::Tb)
+        break;
+      continue;
+    SuspendAndCreateNewRow:
+      if (pProcessor)
+        m_pCurChildPreprocessor = std::move(pProcessor);
+      break;
+    }
+
+    CalculateRowChildPosition(rgCurLineLayoutItems, eFlowStrategy,
+                              bContainerHeightAutoSize, bContainerWidthAutoSize,
+                              &calculated_size.width, &calculated_size.height,
+                              &fContentCurRowY, fContentCurRowHeight,
+                              fContentWidthLimit, bRootForceTb);
+    m_fWidthLimit = fContentCurRowAvailWidth;
+    if (bForceEndPage)
+      break;
+  }
+
+  bool bRetValue =
+      m_nCurChildNodeStage == Stage::kDone && m_PendingNodes.empty();
+  if (bBreakDone)
+    bRetValue = false;
+
+  container_size = CalculateContainerComponentSizeFromContentSize(
+      GetFormNode(), bContainerWidthAutoSize, calculated_size.width,
+      bContainerHeightAutoSize, calculated_size.height, container_size);
+
+  if (container_size.height >= kXFALayoutPrecision || m_pLayoutItem ||
+      bRetValue) {
+    if (!m_pLayoutItem)
+      m_pLayoutItem = CreateContentLayoutItem(GetFormNode());
+    container_size.height = std::max(container_size.height, 0.f);
+
+    SetCurrentComponentSize(container_size);
+    if (bForceEndPage)
+      m_fUsedSize = 0;
+    else
+      m_fUsedSize += m_pLayoutItem->m_sSize.height;
+  }
+
+  if (bRetValue)
+    return Result::kDone;
+  return bIsManualBreak ? Result::kManualBreak : Result::kPageFullBreak;
+}
+
+bool CXFA_ContentLayoutProcessor::CalculateRowChildPosition(
+    std::vector<RetainPtr<CXFA_ContentLayoutItem>> (&rgCurLineLayoutItems)[3],
+    XFA_AttributeValue eFlowStrategy,
+    bool bContainerHeightAutoSize,
+    bool bContainerWidthAutoSize,
+    float* fContentCalculatedWidth,
+    float* fContentCalculatedHeight,
+    float* fContentCurRowY,
+    float fContentCurRowHeight,
+    float fContentWidthLimit,
+    bool bRootForceTb) {
+  int32_t nGroupLengths[3] = {0, 0, 0};
+  float fGroupWidths[3] = {0, 0, 0};
+  int32_t nTotalLength = 0;
+  for (int32_t i = 0; i < 3; i++) {
+    nGroupLengths[i] = pdfium::CollectionSize<int32_t>(rgCurLineLayoutItems[i]);
+    for (int32_t c = nGroupLengths[i], j = 0; j < c; j++) {
+      nTotalLength++;
+      if (rgCurLineLayoutItems[i][j]->GetFormNode()->PresenceRequiresSpace())
+        fGroupWidths[i] += rgCurLineLayoutItems[i][j]->m_sSize.width;
+    }
+  }
+  if (!nTotalLength) {
+    if (bContainerHeightAutoSize) {
+      *fContentCalculatedHeight =
+          std::min(*fContentCalculatedHeight, *fContentCurRowY);
+    }
+    return false;
+  }
+  if (!m_pLayoutItem)
+    m_pLayoutItem = CreateContentLayoutItem(GetFormNode());
+
+  if (eFlowStrategy != XFA_AttributeValue::Rl_tb) {
+    float fCurPos;
+    fCurPos = 0;
+    for (int32_t c = nGroupLengths[0], j = 0; j < c; j++) {
+      if (bRootForceTb) {
+        rgCurLineLayoutItems[0][j]->m_sPos = CalculatePositionedContainerPos(
+            rgCurLineLayoutItems[0][j]->GetFormNode(),
+            rgCurLineLayoutItems[0][j]->m_sSize);
+      } else {
+        rgCurLineLayoutItems[0][j]->m_sPos =
+            CFX_PointF(fCurPos, *fContentCurRowY);
+        if (rgCurLineLayoutItems[0][j]->GetFormNode()->PresenceRequiresSpace())
+          fCurPos += rgCurLineLayoutItems[0][j]->m_sSize.width;
+      }
+      m_pLayoutItem->AppendLastChild(rgCurLineLayoutItems[0][j]);
+      m_fLastRowWidth = fCurPos;
+    }
+    fCurPos = (fContentWidthLimit + fGroupWidths[0] - fGroupWidths[1] -
+               fGroupWidths[2]) /
+              2;
+    for (int32_t c = nGroupLengths[1], j = 0; j < c; j++) {
+      if (bRootForceTb) {
+        rgCurLineLayoutItems[1][j]->m_sPos = CalculatePositionedContainerPos(
+            rgCurLineLayoutItems[1][j]->GetFormNode(),
+            rgCurLineLayoutItems[1][j]->m_sSize);
+      } else {
+        rgCurLineLayoutItems[1][j]->m_sPos =
+            CFX_PointF(fCurPos, *fContentCurRowY);
+        if (rgCurLineLayoutItems[1][j]->GetFormNode()->PresenceRequiresSpace())
+          fCurPos += rgCurLineLayoutItems[1][j]->m_sSize.width;
+      }
+      m_pLayoutItem->AppendLastChild(rgCurLineLayoutItems[1][j]);
+      m_fLastRowWidth = fCurPos;
+    }
+    fCurPos = fContentWidthLimit - fGroupWidths[2];
+    for (int32_t c = nGroupLengths[2], j = 0; j < c; j++) {
+      if (bRootForceTb) {
+        rgCurLineLayoutItems[2][j]->m_sPos = CalculatePositionedContainerPos(
+            rgCurLineLayoutItems[2][j]->GetFormNode(),
+            rgCurLineLayoutItems[2][j]->m_sSize);
+      } else {
+        rgCurLineLayoutItems[2][j]->m_sPos =
+            CFX_PointF(fCurPos, *fContentCurRowY);
+        if (rgCurLineLayoutItems[2][j]->GetFormNode()->PresenceRequiresSpace())
+          fCurPos += rgCurLineLayoutItems[2][j]->m_sSize.width;
+      }
+      m_pLayoutItem->AppendLastChild(rgCurLineLayoutItems[2][j]);
+      m_fLastRowWidth = fCurPos;
+    }
+  } else {
+    float fCurPos;
+    fCurPos = fGroupWidths[0];
+    for (int32_t c = nGroupLengths[0], j = 0; j < c; j++) {
+      if (rgCurLineLayoutItems[0][j]->GetFormNode()->PresenceRequiresSpace())
+        fCurPos -= rgCurLineLayoutItems[0][j]->m_sSize.width;
+
+      rgCurLineLayoutItems[0][j]->m_sPos =
+          CFX_PointF(fCurPos, *fContentCurRowY);
+      m_pLayoutItem->AppendLastChild(rgCurLineLayoutItems[0][j]);
+      m_fLastRowWidth = fCurPos;
+    }
+    fCurPos = (fContentWidthLimit + fGroupWidths[0] + fGroupWidths[1] -
+               fGroupWidths[2]) /
+              2;
+    for (int32_t c = nGroupLengths[1], j = 0; j < c; j++) {
+      if (rgCurLineLayoutItems[1][j]->GetFormNode()->PresenceRequiresSpace())
+        fCurPos -= rgCurLineLayoutItems[1][j]->m_sSize.width;
+
+      rgCurLineLayoutItems[1][j]->m_sPos =
+          CFX_PointF(fCurPos, *fContentCurRowY);
+      m_pLayoutItem->AppendLastChild(rgCurLineLayoutItems[1][j]);
+      m_fLastRowWidth = fCurPos;
+    }
+    fCurPos = fContentWidthLimit;
+    for (int32_t c = nGroupLengths[2], j = 0; j < c; j++) {
+      if (rgCurLineLayoutItems[2][j]->GetFormNode()->PresenceRequiresSpace())
+        fCurPos -= rgCurLineLayoutItems[2][j]->m_sSize.width;
+
+      rgCurLineLayoutItems[2][j]->m_sPos =
+          CFX_PointF(fCurPos, *fContentCurRowY);
+      m_pLayoutItem->AppendLastChild(rgCurLineLayoutItems[2][j]);
+      m_fLastRowWidth = fCurPos;
+    }
+  }
+  m_fLastRowY = *fContentCurRowY;
+  *fContentCurRowY += fContentCurRowHeight;
+  if (bContainerWidthAutoSize) {
+    float fChildSuppliedWidth = fGroupWidths[0];
+    if (fContentWidthLimit < FLT_MAX &&
+        fContentWidthLimit > fChildSuppliedWidth) {
+      fChildSuppliedWidth = fContentWidthLimit;
+    }
+    *fContentCalculatedWidth =
+        std::max(*fContentCalculatedWidth, fChildSuppliedWidth);
+  }
+  if (bContainerHeightAutoSize) {
+    *fContentCalculatedHeight =
+        std::max(*fContentCalculatedHeight, *fContentCurRowY);
+  }
+  return true;
+}
+
+CXFA_Node* CXFA_ContentLayoutProcessor::GetSubformSetParent(
+    CXFA_Node* pSubformSet) {
+  if (pSubformSet && pSubformSet->GetElementType() == XFA_Element::SubformSet) {
+    CXFA_Node* pParent = pSubformSet->GetParent();
+    while (pParent) {
+      if (pParent->GetElementType() != XFA_Element::SubformSet)
+        return pParent;
+      pParent = pParent->GetParent();
+    }
+  }
+  return pSubformSet;
+}
+
+void CXFA_ContentLayoutProcessor::DoLayoutField() {
+  if (m_pLayoutItem)
+    return;
+
+  ASSERT(!m_pCurChildNode);
+  m_pLayoutItem = CreateContentLayoutItem(GetFormNode());
+  if (!m_pLayoutItem)
+    return;
+
+  CXFA_Document* pDocument = GetFormNode()->GetDocument();
+  CXFA_FFNotify* pNotify = pDocument->GetNotify();
+  CFX_SizeF size(-1, -1);
+  pNotify->StartFieldDrawLayout(GetFormNode(), &size.width, &size.height);
+
+  int32_t nRotate = XFA_MapRotation(
+      GetFormNode()->JSObject()->GetInteger(XFA_Attribute::Rotate));
+  if (nRotate == 90 || nRotate == 270)
+    std::swap(size.width, size.height);
+
+  SetCurrentComponentSize(size);
+}
+
+CXFA_ContentLayoutProcessor::Result CXFA_ContentLayoutProcessor::DoLayout(
+    bool bUseBreakControl,
+    float fHeightLimit,
+    float fRealHeight) {
+  return DoLayoutInternal(bUseBreakControl, fHeightLimit, fRealHeight, nullptr);
+}
+
+CXFA_ContentLayoutProcessor::Result
+CXFA_ContentLayoutProcessor::DoLayoutInternal(bool bUseBreakControl,
+                                              float fHeightLimit,
+                                              float fRealHeight,
+                                              Context* pContext) {
+  switch (GetFormNode()->GetElementType()) {
+    case XFA_Element::Subform:
+    case XFA_Element::Area:
+    case XFA_Element::ExclGroup:
+    case XFA_Element::SubformSet: {
+      bool bRootForceTb = false;
+      CXFA_Node* pLayoutNode = GetSubformSetParent(GetFormNode());
+      XFA_AttributeValue eLayoutStrategy =
+          GetLayout(pLayoutNode, &bRootForceTb);
+      switch (eLayoutStrategy) {
+        case XFA_AttributeValue::Tb:
+        case XFA_AttributeValue::Lr_tb:
+        case XFA_AttributeValue::Rl_tb:
+          return DoLayoutFlowedContainer(bUseBreakControl, eLayoutStrategy,
+                                         fHeightLimit, fRealHeight, pContext,
+                                         bRootForceTb);
+        case XFA_AttributeValue::Position:
+        case XFA_AttributeValue::Row:
+        case XFA_AttributeValue::Rl_row:
+        default:
+          DoLayoutPositionedContainer(pContext);
+          m_nCurChildNodeStage = Stage::kDone;
+          return Result::kDone;
+        case XFA_AttributeValue::Table:
+          DoLayoutTableContainer(pLayoutNode);
+          m_nCurChildNodeStage = Stage::kDone;
+          return Result::kDone;
+      }
+    }
+    case XFA_Element::Draw:
+    case XFA_Element::Field:
+      DoLayoutField();
+      m_nCurChildNodeStage = Stage::kDone;
+      return Result::kDone;
+    case XFA_Element::ContentArea:
+    default:
+      return Result::kDone;
+  }
+}
+
+CFX_SizeF CXFA_ContentLayoutProcessor::GetCurrentComponentSize() {
+  return CFX_SizeF(m_pLayoutItem->m_sSize.width, m_pLayoutItem->m_sSize.height);
+}
+
+void CXFA_ContentLayoutProcessor::SetCurrentComponentPos(
+    const CFX_PointF& pos) {
+  m_pLayoutItem->m_sPos = pos;
+}
+
+void CXFA_ContentLayoutProcessor::SetCurrentComponentSize(
+    const CFX_SizeF& size) {
+  m_pLayoutItem->m_sSize = size;
+}
+
+bool CXFA_ContentLayoutProcessor::JudgeLeaderOrTrailerForOccur(
+    CXFA_Node* pFormNode) {
+  if (!pFormNode)
+    return false;
+
+  CXFA_Node* pTemplate = pFormNode->GetTemplateNodeIfExists();
+  if (!pTemplate)
+    pTemplate = pFormNode;
+
+  auto* pOccur =
+      pTemplate->GetFirstChildByClass<CXFA_Occur>(XFA_Element::Occur);
+  if (!pOccur)
+    return false;
+
+  int32_t iMax = pOccur->GetMax();
+  if (iMax < 0)
+    return true;
+
+  int32_t iCount = m_PendingNodesCount[pTemplate];
+  if (iCount >= iMax)
+    return false;
+
+  m_PendingNodesCount[pTemplate] = iCount + 1;
+  return true;
+}
+
+void CXFA_ContentLayoutProcessor::UpdatePendingItemLayout(
+    const RetainPtr<CXFA_ContentLayoutItem>& pLayoutItem) {
+  XFA_AttributeValue eLayout =
+      pLayoutItem->GetFormNode()->JSObject()->GetEnum(XFA_Attribute::Layout);
+  switch (eLayout) {
+    case XFA_AttributeValue::Row:
+    case XFA_AttributeValue::Rl_row:
+      RelocateTableRowCells(pLayoutItem, m_rgSpecifiedColumnWidths, eLayout);
+      break;
+    default:
+      break;
+  }
+}
+
+void CXFA_ContentLayoutProcessor::AddTrailerBeforeSplit(
+    float fSplitPos,
+    const RetainPtr<CXFA_ContentLayoutItem>& pTrailerLayoutItem,
+    bool bUseInherited) {
+  if (!pTrailerLayoutItem)
+    return;
+
+  float fHeight = pTrailerLayoutItem->m_sSize.height;
+  if (bUseInherited) {
+    float fNewSplitPos = 0;
+    if (fSplitPos - fHeight > kXFALayoutPrecision)
+      fNewSplitPos = FindSplitPos(fSplitPos - fHeight);
+    if (fNewSplitPos > kXFALayoutPrecision)
+      SplitLayoutItem(fNewSplitPos);
+    return;
+  }
+
+  UpdatePendingItemLayout(pTrailerLayoutItem);
+  CXFA_Margin* pMargin =
+      GetFormNode()->GetFirstChildByClass<CXFA_Margin>(XFA_Element::Margin);
+  CFX_FloatRect inset = GetMarginInset(pMargin);
+  if (!IsAddNewRowForTrailer(pTrailerLayoutItem.Get())) {
+    pTrailerLayoutItem->m_sPos.y = m_fLastRowY;
+    pTrailerLayoutItem->m_sPos.x = m_fLastRowWidth;
+    m_pLayoutItem->m_sSize.width += pTrailerLayoutItem->m_sSize.width;
+    m_pLayoutItem->AppendLastChild(pTrailerLayoutItem);
+    return;
+  }
+
+  float fNewSplitPos = 0;
+  if (fSplitPos - fHeight > kXFALayoutPrecision)
+    fNewSplitPos = FindSplitPos(fSplitPos - fHeight);
+
+  if (fNewSplitPos > kXFALayoutPrecision) {
+    SplitLayoutItem(fNewSplitPos);
+    pTrailerLayoutItem->m_sPos.y = fNewSplitPos - inset.top - inset.bottom;
+  } else {
+    pTrailerLayoutItem->m_sPos.y = fSplitPos - inset.top - inset.bottom;
+  }
+
+  switch (pTrailerLayoutItem->GetFormNode()->JSObject()->GetEnum(
+      XFA_Attribute::HAlign)) {
+    case XFA_AttributeValue::Right:
+      pTrailerLayoutItem->m_sPos.x = m_pLayoutItem->m_sSize.width -
+                                     inset.right -
+                                     pTrailerLayoutItem->m_sSize.width;
+      break;
+    case XFA_AttributeValue::Center:
+      pTrailerLayoutItem->m_sPos.x =
+          (m_pLayoutItem->m_sSize.width - inset.left - inset.right -
+           pTrailerLayoutItem->m_sSize.width) /
+          2;
+      break;
+    case XFA_AttributeValue::Left:
+    default:
+      pTrailerLayoutItem->m_sPos.x = inset.left;
+      break;
+  }
+  m_pLayoutItem->m_sSize.height += fHeight;
+  m_pLayoutItem->AppendLastChild(pTrailerLayoutItem);
+}
+
+void CXFA_ContentLayoutProcessor::AddLeaderAfterSplit(
+    const RetainPtr<CXFA_ContentLayoutItem>& pLeaderLayoutItem) {
+  UpdatePendingItemLayout(pLeaderLayoutItem);
+
+  CXFA_Margin* pMarginNode =
+      GetFormNode()->GetFirstChildByClass<CXFA_Margin>(XFA_Element::Margin);
+  float fLeftInset = 0;
+  float fRightInset = 0;
+  if (pMarginNode) {
+    fLeftInset = pMarginNode->JSObject()->GetMeasureInUnit(
+        XFA_Attribute::LeftInset, XFA_Unit::Pt);
+    fRightInset = pMarginNode->JSObject()->GetMeasureInUnit(
+        XFA_Attribute::RightInset, XFA_Unit::Pt);
+  }
+
+  float fHeight = pLeaderLayoutItem->m_sSize.height;
+  for (CXFA_LayoutItem* pIter = m_pLayoutItem->GetFirstChild(); pIter;
+       pIter = pIter->GetNextSibling()) {
+    CXFA_ContentLayoutItem* pContentItem = pIter->AsContentLayoutItem();
+    if (!pContentItem)
+      continue;
+
+    pContentItem->m_sPos.y += fHeight;
+  }
+  pLeaderLayoutItem->m_sPos.y = 0;
+
+  switch (pLeaderLayoutItem->GetFormNode()->JSObject()->GetEnum(
+      XFA_Attribute::HAlign)) {
+    case XFA_AttributeValue::Right:
+      pLeaderLayoutItem->m_sPos.x = m_pLayoutItem->m_sSize.width - fRightInset -
+                                    pLeaderLayoutItem->m_sSize.width;
+      break;
+    case XFA_AttributeValue::Center:
+      pLeaderLayoutItem->m_sPos.x =
+          (m_pLayoutItem->m_sSize.width - fLeftInset - fRightInset -
+           pLeaderLayoutItem->m_sSize.width) /
+          2;
+      break;
+    case XFA_AttributeValue::Left:
+    default:
+      pLeaderLayoutItem->m_sPos.x = fLeftInset;
+      break;
+  }
+  m_pLayoutItem->m_sSize.height += fHeight;
+  m_pLayoutItem->AppendLastChild(pLeaderLayoutItem);
+}
+
+void CXFA_ContentLayoutProcessor::AddPendingNode(CXFA_Node* pPendingNode,
+                                                 bool bBreakPending) {
+  m_PendingNodes.push_back(pPendingNode);
+  m_bBreakPending = bBreakPending;
+}
+
+float CXFA_ContentLayoutProcessor::InsertPendingItems(
+    CXFA_Node* pCurChildNode) {
+  float fTotalHeight = 0;
+  if (m_PendingNodes.empty())
+    return fTotalHeight;
+
+  if (!m_pLayoutItem) {
+    m_pLayoutItem = CreateContentLayoutItem(pCurChildNode);
+    m_pLayoutItem->m_sSize.clear();
+  }
+
+  while (!m_PendingNodes.empty()) {
+    auto pPendingProcessor = pdfium::MakeUnique<CXFA_ContentLayoutProcessor>(
+        m_PendingNodes.front(), nullptr);
+    m_PendingNodes.pop_front();
+    pPendingProcessor->DoLayout(false, FLT_MAX, FLT_MAX);
+    RetainPtr<CXFA_ContentLayoutItem> pPendingLayoutItem;
+    if (pPendingProcessor->HasLayoutItem())
+      pPendingLayoutItem = pPendingProcessor->ExtractLayoutItem();
+    if (pPendingLayoutItem) {
+      AddLeaderAfterSplit(pPendingLayoutItem);
+      if (m_bBreakPending)
+        fTotalHeight += pPendingLayoutItem->m_sSize.height;
+    }
+  }
+  return fTotalHeight;
+}
+
+CXFA_ContentLayoutProcessor::Result
+CXFA_ContentLayoutProcessor::InsertFlowedItem(
+    CXFA_ContentLayoutProcessor* pProcessor,
+    bool bContainerWidthAutoSize,
+    bool bContainerHeightAutoSize,
+    float fContainerHeight,
+    XFA_AttributeValue eFlowStrategy,
+    uint8_t* uCurHAlignState,
+    std::vector<RetainPtr<CXFA_ContentLayoutItem>> (&rgCurLineLayoutItems)[3],
+    bool bUseBreakControl,
+    float fAvailHeight,
+    float fRealHeight,
+    float fContentWidthLimit,
+    float* fContentCurRowY,
+    float* fContentCurRowAvailWidth,
+    float* fContentCurRowHeight,
+    bool* bAddedItemInRow,
+    bool* bForceEndPage,
+    Context* pLayoutContext,
+    bool bNewRow) {
+  bool bTakeSpace = pProcessor->GetFormNode()->PresenceRequiresSpace();
+  uint8_t uHAlign = HAlignEnumToInt(
+      m_pCurChildNode->JSObject()->GetEnum(XFA_Attribute::HAlign));
+  if (bContainerWidthAutoSize)
+    uHAlign = 0;
+
+  if ((eFlowStrategy != XFA_AttributeValue::Rl_tb &&
+       uHAlign < *uCurHAlignState) ||
+      (eFlowStrategy == XFA_AttributeValue::Rl_tb &&
+       uHAlign > *uCurHAlignState)) {
+    return Result::kRowFullBreak;
+  }
+
+  *uCurHAlignState = uHAlign;
+  bool bIsOwnSplit =
+      pProcessor->GetFormNode()->GetIntact() == XFA_AttributeValue::None;
+  bool bUseRealHeight = bTakeSpace && bContainerHeightAutoSize && bIsOwnSplit &&
+                        pProcessor->GetFormNode()->GetParent()->GetIntact() ==
+                            XFA_AttributeValue::None;
+  bool bIsTransHeight = bTakeSpace;
+  if (bIsTransHeight && !bIsOwnSplit) {
+    bool bRootForceTb = false;
+    XFA_AttributeValue eLayoutStrategy =
+        GetLayout(pProcessor->GetFormNode(), &bRootForceTb);
+    if (eLayoutStrategy == XFA_AttributeValue::Lr_tb ||
+        eLayoutStrategy == XFA_AttributeValue::Rl_tb) {
+      bIsTransHeight = false;
+    }
+  }
+
+  bool bUseInherited = false;
+  Context layoutContext;
+  if (m_pViewLayoutProcessor) {
+    CXFA_Node* pOverflowNode =
+        m_pViewLayoutProcessor->QueryOverflow(GetFormNode());
+    if (pOverflowNode) {
+      layoutContext.m_pOverflowNode = pOverflowNode;
+      layoutContext.m_pOverflowProcessor = this;
+      pLayoutContext = &layoutContext;
+    }
+  }
+
+  Result eRetValue = Result::kDone;
+  if (!bNewRow || pProcessor->m_ePreProcessRs == Result::kDone) {
+    eRetValue = pProcessor->DoLayoutInternal(
+        bTakeSpace && bUseBreakControl,
+        bUseRealHeight ? fRealHeight - *fContentCurRowY : FLT_MAX,
+        bIsTransHeight ? fRealHeight - *fContentCurRowY : FLT_MAX,
+        pLayoutContext);
+    pProcessor->m_ePreProcessRs = eRetValue;
+  } else {
+    eRetValue = pProcessor->m_ePreProcessRs;
+    pProcessor->m_ePreProcessRs = Result::kDone;
+  }
+  if (!pProcessor->HasLayoutItem())
+    return eRetValue;
+
+  CFX_SizeF childSize = pProcessor->GetCurrentComponentSize();
+  if (bUseRealHeight && fRealHeight < kXFALayoutPrecision) {
+    fRealHeight = FLT_MAX;
+    fAvailHeight = FLT_MAX;
+  }
+  if (bTakeSpace &&
+      (childSize.width > *fContentCurRowAvailWidth + kXFALayoutPrecision) &&
+      (fContentWidthLimit - *fContentCurRowAvailWidth > kXFALayoutPrecision)) {
+    return Result::kRowFullBreak;
+  }
+
+  CXFA_Node* pOverflowLeaderNode = nullptr;
+  CXFA_Node* pOverflowTrailerNode = nullptr;
+  CXFA_Node* pFormNode = nullptr;
+  RetainPtr<CXFA_ContentLayoutItem> pTrailerLayoutItem;
+  bool bIsAddTrailerHeight = false;
+  if (m_pViewLayoutProcessor &&
+      pProcessor->GetFormNode()->GetIntact() == XFA_AttributeValue::None) {
+    pFormNode =
+        m_pViewLayoutProcessor->QueryOverflow(pProcessor->GetFormNode());
+    if (!pFormNode && pLayoutContext && pLayoutContext->m_pOverflowProcessor) {
+      pFormNode = pLayoutContext->m_pOverflowNode.Get();
+      bUseInherited = true;
+    }
+    Optional<CXFA_ViewLayoutProcessor::OverflowData> overflow_data =
+        m_pViewLayoutProcessor->ProcessOverflow(pFormNode, false);
+    if (overflow_data.has_value()) {
+      pOverflowLeaderNode = overflow_data.value().pLeader;
+      pOverflowTrailerNode = overflow_data.value().pTrailer;
+      if (pProcessor->JudgeLeaderOrTrailerForOccur(pOverflowTrailerNode)) {
+        if (pOverflowTrailerNode) {
+          auto pOverflowLeaderProcessor =
+              pdfium::MakeUnique<CXFA_ContentLayoutProcessor>(
+                  pOverflowTrailerNode, nullptr);
+          pOverflowLeaderProcessor->DoLayout(false, FLT_MAX, FLT_MAX);
+          pTrailerLayoutItem =
+              pOverflowLeaderProcessor->HasLayoutItem()
+                  ? pOverflowLeaderProcessor->ExtractLayoutItem()
+                  : nullptr;
+        }
+
+        bIsAddTrailerHeight =
+            bUseInherited
+                ? IsAddNewRowForTrailer(pTrailerLayoutItem.Get())
+                : pProcessor->IsAddNewRowForTrailer(pTrailerLayoutItem.Get());
+        if (bIsAddTrailerHeight) {
+          childSize.height += pTrailerLayoutItem->m_sSize.height;
+          bIsAddTrailerHeight = true;
+        }
+      }
+    }
+  }
+
+  if (!bTakeSpace ||
+      *fContentCurRowY + childSize.height <=
+          fAvailHeight + kXFALayoutPrecision ||
+      (!bContainerHeightAutoSize &&
+       m_fUsedSize + fAvailHeight + kXFALayoutPrecision >= fContainerHeight)) {
+    if (!bTakeSpace || eRetValue == Result::kDone) {
+      if (pProcessor->m_bUseInherited) {
+        if (pTrailerLayoutItem)
+          pProcessor->AddTrailerBeforeSplit(childSize.height,
+                                            pTrailerLayoutItem, false);
+        if (pProcessor->JudgeLeaderOrTrailerForOccur(pOverflowLeaderNode))
+          pProcessor->AddPendingNode(pOverflowLeaderNode, false);
+
+        pProcessor->m_bUseInherited = false;
+      } else {
+        if (bIsAddTrailerHeight)
+          childSize.height -= pTrailerLayoutItem->m_sSize.height;
+
+        pProcessor->ProcessUnUseOverFlow(pOverflowLeaderNode,
+                                         pOverflowTrailerNode,
+                                         pTrailerLayoutItem, pFormNode);
+      }
+
+      RetainPtr<CXFA_ContentLayoutItem> pChildLayoutItem =
+          pProcessor->ExtractLayoutItem();
+      if (ExistContainerKeep(pProcessor->GetFormNode(), false) &&
+          pProcessor->GetFormNode()->GetIntact() == XFA_AttributeValue::None) {
+        m_ArrayKeepItems.push_back(pChildLayoutItem);
+      } else {
+        m_ArrayKeepItems.clear();
+      }
+      rgCurLineLayoutItems[uHAlign].push_back(pChildLayoutItem);
+      *bAddedItemInRow = true;
+      if (bTakeSpace) {
+        *fContentCurRowAvailWidth -= childSize.width;
+        *fContentCurRowHeight =
+            std::max(*fContentCurRowHeight, childSize.height);
+      }
+      return Result::kDone;
+    }
+
+    if (eRetValue == Result::kPageFullBreak) {
+      if (pProcessor->m_bUseInherited) {
+        if (pTrailerLayoutItem) {
+          pProcessor->AddTrailerBeforeSplit(childSize.height,
+                                            pTrailerLayoutItem, false);
+        }
+        if (pProcessor->JudgeLeaderOrTrailerForOccur(pOverflowLeaderNode))
+          pProcessor->AddPendingNode(pOverflowLeaderNode, false);
+
+        pProcessor->m_bUseInherited = false;
+      } else {
+        if (bIsAddTrailerHeight)
+          childSize.height -= pTrailerLayoutItem->m_sSize.height;
+
+        pProcessor->ProcessUnUseOverFlow(pOverflowLeaderNode,
+                                         pOverflowTrailerNode,
+                                         pTrailerLayoutItem, pFormNode);
+      }
+    }
+    rgCurLineLayoutItems[uHAlign].push_back(pProcessor->ExtractLayoutItem());
+    *bAddedItemInRow = true;
+    *fContentCurRowAvailWidth -= childSize.width;
+    *fContentCurRowHeight = std::max(*fContentCurRowHeight, childSize.height);
+    return eRetValue;
+  }
+
+  Result eResult;
+  if (ProcessKeepForSplit(pProcessor, eRetValue, &rgCurLineLayoutItems[uHAlign],
+                          fContentCurRowAvailWidth, fContentCurRowHeight,
+                          fContentCurRowY, bAddedItemInRow, bForceEndPage,
+                          &eResult)) {
+    return eResult;
+  }
+
+  *bForceEndPage = true;
+  float fSplitPos = pProcessor->FindSplitPos(fAvailHeight - *fContentCurRowY);
+  if (fSplitPos > kXFALayoutPrecision) {
+    XFA_AttributeValue eLayout =
+        pProcessor->GetFormNode()->JSObject()->GetEnum(XFA_Attribute::Layout);
+    if (eLayout == XFA_AttributeValue::Tb && eRetValue == Result::kDone) {
+      pProcessor->ProcessUnUseOverFlow(pOverflowLeaderNode,
+                                       pOverflowTrailerNode, pTrailerLayoutItem,
+                                       pFormNode);
+      rgCurLineLayoutItems[uHAlign].push_back(pProcessor->ExtractLayoutItem());
+      *bAddedItemInRow = true;
+      if (bTakeSpace) {
+        *fContentCurRowAvailWidth -= childSize.width;
+        *fContentCurRowHeight =
+            std::max(*fContentCurRowHeight, childSize.height);
+      }
+      return Result::kPageFullBreak;
+    }
+
+    if (m_pViewLayoutProcessor && !pProcessor->m_bUseInherited &&
+        eRetValue != Result::kPageFullBreak) {
+      m_pViewLayoutProcessor->ProcessOverflow(pFormNode, true);
+    }
+    if (pTrailerLayoutItem && bIsAddTrailerHeight) {
+      pProcessor->AddTrailerBeforeSplit(fSplitPos, pTrailerLayoutItem,
+                                        bUseInherited);
+    } else {
+      pProcessor->SplitLayoutItem(fSplitPos);
+    }
+
+    if (bUseInherited) {
+      pProcessor->ProcessUnUseOverFlow(pOverflowLeaderNode,
+                                       pOverflowTrailerNode, pTrailerLayoutItem,
+                                       pFormNode);
+      m_bUseInherited = true;
+    } else {
+      CXFA_LayoutItem* firstChild = pProcessor->m_pLayoutItem->GetFirstChild();
+      if (firstChild && !firstChild->GetNextSibling() &&
+          firstChild->GetFormNode()->IsLayoutGeneratedNode()) {
+        pProcessor->ProcessUnUseOverFlow(pOverflowLeaderNode,
+                                         pOverflowTrailerNode,
+                                         pTrailerLayoutItem, pFormNode);
+      } else if (pProcessor->JudgeLeaderOrTrailerForOccur(
+                     pOverflowLeaderNode)) {
+        pProcessor->AddPendingNode(pOverflowLeaderNode, false);
+      }
+    }
+
+    if (pProcessor->m_pLayoutItem->GetNextSibling()) {
+      childSize = pProcessor->GetCurrentComponentSize();
+      rgCurLineLayoutItems[uHAlign].push_back(pProcessor->ExtractLayoutItem());
+      *bAddedItemInRow = true;
+      if (bTakeSpace) {
+        *fContentCurRowAvailWidth -= childSize.width;
+        *fContentCurRowHeight =
+            std::max(*fContentCurRowHeight, childSize.height);
+      }
+    }
+    return Result::kPageFullBreak;
+  }
+
+  if (*fContentCurRowY <= kXFALayoutPrecision) {
+    childSize = pProcessor->GetCurrentComponentSize();
+    if (pProcessor->m_pViewLayoutProcessor->GetNextAvailContentHeight(
+            childSize.height)) {
+      if (m_pViewLayoutProcessor) {
+        if (!pFormNode && pLayoutContext)
+          pFormNode = pLayoutContext->m_pOverflowProcessor->GetFormNode();
+
+        m_pViewLayoutProcessor->ProcessOverflow(pFormNode, true);
+      }
+      if (bUseInherited) {
+        pProcessor->ProcessUnUseOverFlow(pOverflowLeaderNode,
+                                         pOverflowTrailerNode,
+                                         pTrailerLayoutItem, pFormNode);
+        m_bUseInherited = true;
+      }
+      return Result::kPageFullBreak;
+    }
+
+    rgCurLineLayoutItems[uHAlign].push_back(pProcessor->ExtractLayoutItem());
+    *bAddedItemInRow = true;
+    if (bTakeSpace) {
+      *fContentCurRowAvailWidth -= childSize.width;
+      *fContentCurRowHeight = std::max(*fContentCurRowHeight, childSize.height);
+    }
+    if (eRetValue == Result::kDone)
+      *bForceEndPage = false;
+
+    return eRetValue;
+  }
+
+  XFA_AttributeValue eLayout =
+      pProcessor->GetFormNode()->JSObject()->GetEnum(XFA_Attribute::Layout);
+  if (pProcessor->GetFormNode()->GetIntact() == XFA_AttributeValue::None &&
+      eLayout == XFA_AttributeValue::Tb) {
+    if (m_pViewLayoutProcessor) {
+      Optional<CXFA_ViewLayoutProcessor::OverflowData> overflow_data =
+          m_pViewLayoutProcessor->ProcessOverflow(pFormNode, true);
+      if (overflow_data.has_value()) {
+        pOverflowLeaderNode = overflow_data.value().pLeader;
+        pOverflowTrailerNode = overflow_data.value().pTrailer;
+      }
+    }
+    if (pTrailerLayoutItem)
+      pProcessor->AddTrailerBeforeSplit(fSplitPos, pTrailerLayoutItem, false);
+    if (pProcessor->JudgeLeaderOrTrailerForOccur(pOverflowLeaderNode))
+      pProcessor->AddPendingNode(pOverflowLeaderNode, false);
+
+    return Result::kPageFullBreak;
+  }
+
+  if (eRetValue != Result::kDone)
+    return Result::kPageFullBreak;
+
+  if (!pFormNode && pLayoutContext)
+    pFormNode = pLayoutContext->m_pOverflowProcessor->GetFormNode();
+  if (m_pViewLayoutProcessor) {
+    Optional<CXFA_ViewLayoutProcessor::OverflowData> overflow_data =
+        m_pViewLayoutProcessor->ProcessOverflow(pFormNode, true);
+    if (overflow_data.has_value()) {
+      pOverflowLeaderNode = overflow_data.value().pLeader;
+      pOverflowTrailerNode = overflow_data.value().pTrailer;
+    }
+  }
+  if (bUseInherited) {
+    pProcessor->ProcessUnUseOverFlow(pOverflowLeaderNode, pOverflowTrailerNode,
+                                     pTrailerLayoutItem, pFormNode);
+    m_bUseInherited = true;
+  }
+  return Result::kPageFullBreak;
+}
+
+Optional<CXFA_ContentLayoutProcessor::Stage>
+CXFA_ContentLayoutProcessor::HandleKeep(CXFA_Node* pBreakAfterNode,
+                                        CXFA_Node** pCurActionNode) {
+  if (m_bKeepBreakFinish)
+    return {};
+  return FindBreakNode(pBreakAfterNode, false, pCurActionNode);
+}
+
+Optional<CXFA_ContentLayoutProcessor::Stage>
+CXFA_ContentLayoutProcessor::HandleBookendLeader(CXFA_Node* pParentContainer,
+                                                 CXFA_Node** pCurActionNode) {
+  for (CXFA_Node* pBookendNode = *pCurActionNode
+                                     ? (*pCurActionNode)->GetNextSibling()
+                                     : pParentContainer->GetFirstChild();
+       pBookendNode; pBookendNode = pBookendNode->GetNextSibling()) {
+    switch (pBookendNode->GetElementType()) {
+      case XFA_Element::Bookend:
+      case XFA_Element::Break:
+        *pCurActionNode = pBookendNode;
+        return Stage::kBookendLeader;
+      default:
+        break;
+    }
+  }
+  return {};
+}
+
+Optional<CXFA_ContentLayoutProcessor::Stage>
+CXFA_ContentLayoutProcessor::HandleBreakBefore(CXFA_Node* pChildContainer,
+                                               CXFA_Node** pCurActionNode) {
+  if (!*pCurActionNode)
+    return {};
+
+  CXFA_Node* pBreakBeforeNode = (*pCurActionNode)->GetNextSibling();
+  if (!m_bKeepBreakFinish) {
+    Optional<Stage> ret = FindBreakNode(pBreakBeforeNode, true, pCurActionNode);
+    if (ret.has_value())
+      return ret.value();
+  }
+  if (m_bIsProcessKeep)
+    return ProcessKeepNodesForBreakBefore(pCurActionNode, pChildContainer);
+
+  *pCurActionNode = pChildContainer;
+  return Stage::kContainer;
+}
+
+Optional<CXFA_ContentLayoutProcessor::Stage>
+CXFA_ContentLayoutProcessor::HandleBreakAfter(CXFA_Node* pChildContainer,
+                                              CXFA_Node** pCurActionNode) {
+  if (*pCurActionNode) {
+    CXFA_Node* pBreakAfterNode = (*pCurActionNode)->GetNextSibling();
+    return FindBreakNode(pBreakAfterNode, false, pCurActionNode);
+  }
+
+  CXFA_Node* pBreakAfterNode = pChildContainer->GetFirstChild();
+  return HandleKeep(pBreakAfterNode, pCurActionNode);
+}
+
+Optional<CXFA_ContentLayoutProcessor::Stage>
+CXFA_ContentLayoutProcessor::HandleCheckNextChildContainer(
+    CXFA_Node* pParentContainer,
+    CXFA_Node* pChildContainer,
+    CXFA_Node** pCurActionNode) {
+  CXFA_Node* pNextChildContainer =
+      pChildContainer ? pChildContainer->GetNextContainerSibling()
+                      : pParentContainer->GetFirstContainerChild();
+  while (pNextChildContainer && pNextChildContainer->IsLayoutGeneratedNode()) {
+    CXFA_Node* pSaveNode = pNextChildContainer;
+    pNextChildContainer = pNextChildContainer->GetNextContainerSibling();
+    if (pSaveNode->IsUnusedNode())
+      DeleteLayoutGeneratedNode(pSaveNode);
+  }
+  if (!pNextChildContainer)
+    return {};
+
+  bool bLastKeep = false;
+  Optional<Stage> ret = ProcessKeepNodesForCheckNext(
+      pCurActionNode, &pNextChildContainer, &bLastKeep);
+  if (ret.has_value())
+    return ret.value();
+
+  if (!m_bKeepBreakFinish && !bLastKeep) {
+    ret = FindBreakNode(pNextChildContainer->GetFirstChild(), true,
+                        pCurActionNode);
+    if (ret.has_value())
+      return ret.value();
+  }
+  *pCurActionNode = pNextChildContainer;
+  return m_bIsProcessKeep ? Stage::kKeep : Stage::kContainer;
+}
+
+Optional<CXFA_ContentLayoutProcessor::Stage>
+CXFA_ContentLayoutProcessor::HandleBookendTrailer(CXFA_Node* pParentContainer,
+                                                  CXFA_Node** pCurActionNode) {
+  for (CXFA_Node* pBookendNode = *pCurActionNode
+                                     ? (*pCurActionNode)->GetNextSibling()
+                                     : pParentContainer->GetFirstChild();
+       pBookendNode; pBookendNode = pBookendNode->GetNextSibling()) {
+    switch (pBookendNode->GetElementType()) {
+      case XFA_Element::Bookend:
+      case XFA_Element::Break:
+        *pCurActionNode = pBookendNode;
+        return Stage::kBookendTrailer;
+      default:
+        break;
+    }
+  }
+  return {};
+}
+
+void CXFA_ContentLayoutProcessor::ProcessKeepNodesEnd() {
+  m_bKeepBreakFinish = true;
+  m_pKeepHeadNode = nullptr;
+  m_pKeepTailNode = nullptr;
+  m_bIsProcessKeep = false;
+}
+
+void CXFA_ContentLayoutProcessor::AdjustContainerSpecifiedSize(
+    Context* pContext,
+    CFX_SizeF* pSize,
+    bool* pContainerWidthAutoSize,
+    bool* pContainerHeightAutoSize) {
+  if (pContext && pContext->m_fCurColumnWidth.has_value()) {
+    pSize->width = pContext->m_fCurColumnWidth.value();
+    *pContainerWidthAutoSize = false;
+  }
+  if (*pContainerHeightAutoSize)
+    return;
+
+  pSize->height -= m_fUsedSize;
+  CXFA_Node* pParentNode = GetFormNode()->GetParent();
+  bool bFocrTb = false;
+  if (!pParentNode ||
+      GetLayout(pParentNode, &bFocrTb) != XFA_AttributeValue::Row) {
+    return;
+  }
+
+  CXFA_Node* pChildContainer = GetFormNode()->GetFirstContainerChild();
+  if (!pChildContainer || !pChildContainer->GetNextContainerSibling())
+    return;
+
+  pSize->height = 0;
+  *pContainerHeightAutoSize = true;
+}
+
+CXFA_ContentLayoutItem* CXFA_ContentLayoutProcessor::FindLastContentLayoutItem(
+    XFA_AttributeValue eFlowStrategy) {
+  if (m_nCurChildNodeStage == Stage::kDone ||
+      eFlowStrategy == XFA_AttributeValue::Tb) {
+    return nullptr;
+  }
+
+  CXFA_ContentLayoutItem* pLastChild =
+      ToContentLayoutItem(m_pLayoutItem->GetFirstChild());
+  for (CXFA_LayoutItem* pNext = pLastChild; pNext;
+       pNext = pNext->GetNextSibling()) {
+    CXFA_ContentLayoutItem* pContentNext = pNext->AsContentLayoutItem();
+    if (pContentNext && pContentNext->m_sPos.y != pLastChild->m_sPos.y)
+      pLastChild = pContentNext;
+  }
+  return pLastChild;
+}
+
+CFX_SizeF CXFA_ContentLayoutProcessor::CalculateLayoutItemSize(
+    const CXFA_ContentLayoutItem* pLastChild) {
+  CFX_SizeF size;
+  for (CXFA_LayoutItem* pChild = m_pLayoutItem->GetFirstChild();
+       pChild != pLastChild; pChild = pChild->GetNextSibling()) {
+    CXFA_ContentLayoutItem* pLayout = pChild->AsContentLayoutItem();
+    if (!pLayout || !pLayout->GetFormNode()->PresenceRequiresSpace())
+      continue;
+
+    float fWidth = pLayout->m_sPos.x + pLayout->m_sSize.width;
+    float fHeight = pLayout->m_sPos.y + pLayout->m_sSize.height;
+    size.width = std::max(size.width, fWidth);
+    size.height = std::max(size.height, fHeight);
+  }
+  return size;
+}
+
+CXFA_ContentLayoutProcessor::Context::Context() = default;
+
+CXFA_ContentLayoutProcessor::Context::~Context() = default;
diff --git a/xfa/fxfa/layout/cxfa_contentlayoutprocessor.h b/xfa/fxfa/layout/cxfa_contentlayoutprocessor.h
new file mode 100644
index 0000000..c4cfbe7
--- /dev/null
+++ b/xfa/fxfa/layout/cxfa_contentlayoutprocessor.h
@@ -0,0 +1,230 @@
+// Copyright 2014 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_LAYOUT_CXFA_CONTENTLAYOUTPROCESSOR_H_
+#define XFA_FXFA_LAYOUT_CXFA_CONTENTLAYOUTPROCESSOR_H_
+
+#include <float.h>
+
+#include <list>
+#include <map>
+#include <memory>
+#include <vector>
+
+#include "core/fxcrt/fx_coordinates.h"
+#include "core/fxcrt/retain_ptr.h"
+#include "core/fxcrt/unowned_ptr.h"
+#include "third_party/base/optional.h"
+#include "xfa/fxfa/fxfa_basic.h"
+
+constexpr float kXFALayoutPrecision = 0.0005f;
+
+class CXFA_ContentLayoutItem;
+class CXFA_ContentLayoutProcessor;
+class CXFA_LayoutProcessor;
+class CXFA_Node;
+class CXFA_ViewLayoutItem;
+class CXFA_ViewLayoutProcessor;
+
+class CXFA_ContentLayoutProcessor {
+ public:
+  enum class Result : uint8_t {
+    kDone,
+    kPageFullBreak,
+    kRowFullBreak,
+    kManualBreak,
+  };
+
+  enum class Stage : uint8_t {
+    kNone,
+    kBookendLeader,
+    kBreakBefore,
+    kKeep,
+    kContainer,
+    kBreakAfter,
+    kBookendTrailer,
+    kDone,
+  };
+
+  CXFA_ContentLayoutProcessor(CXFA_Node* pNode,
+                              CXFA_ViewLayoutProcessor* pViewLayoutProcessor);
+  ~CXFA_ContentLayoutProcessor();
+
+  Result DoLayout(bool bUseBreakControl, float fHeightLimit, float fRealHeight);
+  void DoLayoutPageArea(CXFA_ViewLayoutItem* pPageAreaLayoutItem);
+
+  CXFA_Node* GetFormNode() { return m_pFormNode; }
+  RetainPtr<CXFA_ContentLayoutItem> ExtractLayoutItem();
+
+ private:
+  class Context {
+   public:
+    Context();
+    ~Context();
+
+    Optional<float> m_fCurColumnWidth;
+    UnownedPtr<std::vector<float>> m_prgSpecifiedColumnWidths;
+    UnownedPtr<CXFA_ContentLayoutProcessor> m_pOverflowProcessor;
+    UnownedPtr<CXFA_Node> m_pOverflowNode;
+  };
+
+  Result DoLayoutInternal(bool bUseBreakControl,
+                          float fHeightLimit,
+                          float fRealHeight,
+                          Context* pContext);
+
+  CFX_SizeF GetCurrentComponentSize();
+  bool HasLayoutItem() const { return !!m_pLayoutItem; }
+  void SplitLayoutItem(float fSplitPos);
+  float FindSplitPos(float fProposedSplitPos);
+  bool ProcessKeepForSplit(
+      CXFA_ContentLayoutProcessor* pChildProcessor,
+      Result eRetValue,
+      std::vector<RetainPtr<CXFA_ContentLayoutItem>>* rgCurLineLayoutItem,
+      float* fContentCurRowAvailWidth,
+      float* fContentCurRowHeight,
+      float* fContentCurRowY,
+      bool* bAddedItemInRow,
+      bool* bForceEndPage,
+      Result* result);
+  void ProcessUnUseOverFlow(
+      CXFA_Node* pLeaderNode,
+      CXFA_Node* pTrailerNode,
+      const RetainPtr<CXFA_ContentLayoutItem>& pTrailerItem,
+      CXFA_Node* pFormNode);
+  bool IsAddNewRowForTrailer(CXFA_ContentLayoutItem* pTrailerItem);
+  bool JudgeLeaderOrTrailerForOccur(CXFA_Node* pFormNode);
+
+  RetainPtr<CXFA_ContentLayoutItem> CreateContentLayoutItem(
+      CXFA_Node* pFormNode);
+
+  void SetCurrentComponentPos(const CFX_PointF& pos);
+  void SetCurrentComponentSize(const CFX_SizeF& size);
+
+  void SplitLayoutItem(CXFA_ContentLayoutItem* pLayoutItem,
+                       CXFA_ContentLayoutItem* pSecondParent,
+                       float fSplitPos);
+  float InsertKeepLayoutItems();
+  bool CalculateRowChildPosition(
+      std::vector<RetainPtr<CXFA_ContentLayoutItem>> (&rgCurLineLayoutItems)[3],
+      XFA_AttributeValue eFlowStrategy,
+      bool bContainerHeightAutoSize,
+      bool bContainerWidthAutoSize,
+      float* fContentCalculatedWidth,
+      float* fContentCalculatedHeight,
+      float* fContentCurRowY,
+      float fContentCurRowHeight,
+      float fContentWidthLimit,
+      bool bRootForceTb);
+  void ProcessUnUseBinds(CXFA_Node* pFormNode);
+  bool JudgePutNextPage(
+      CXFA_ContentLayoutItem* pParentLayoutItem,
+      float fChildHeight,
+      std::vector<RetainPtr<CXFA_ContentLayoutItem>>* pKeepItems);
+
+  void DoLayoutPositionedContainer(Context* pContext);
+  void DoLayoutTableContainer(CXFA_Node* pLayoutNode);
+  Result DoLayoutFlowedContainer(bool bUseBreakControl,
+                                 XFA_AttributeValue eFlowStrategy,
+                                 float fHeightLimit,
+                                 float fRealHeight,
+                                 Context* pContext,
+                                 bool bRootForceTb);
+  void DoLayoutField();
+
+  void GotoNextContainerNodeSimple(bool bUsePageBreak);
+  Stage GotoNextContainerNode(Stage nCurStage,
+                              bool bUsePageBreak,
+                              CXFA_Node* pParentContainer,
+                              CXFA_Node** pCurActionNode);
+
+  Optional<Stage> ProcessKeepNodesForCheckNext(CXFA_Node** pCurActionNode,
+                                               CXFA_Node** pNextContainer,
+                                               bool* pLastKeepNode);
+
+  Optional<Stage> ProcessKeepNodesForBreakBefore(CXFA_Node** pCurActionNode,
+                                                 CXFA_Node* pContainerNode);
+
+  CXFA_Node* GetSubformSetParent(CXFA_Node* pSubformSet);
+
+  void UpdatePendingItemLayout(
+      const RetainPtr<CXFA_ContentLayoutItem>& pLayoutItem);
+  void AddTrailerBeforeSplit(
+      float fSplitPos,
+      const RetainPtr<CXFA_ContentLayoutItem>& pTrailerLayoutItem,
+      bool bUseInherited);
+  void AddLeaderAfterSplit(
+      const RetainPtr<CXFA_ContentLayoutItem>& pLeaderLayoutItem);
+  void AddPendingNode(CXFA_Node* pPendingNode, bool bBreakPending);
+  float InsertPendingItems(CXFA_Node* pCurChildNode);
+  Result InsertFlowedItem(
+      CXFA_ContentLayoutProcessor* pProcessor,
+      bool bContainerWidthAutoSize,
+      bool bContainerHeightAutoSize,
+      float fContainerHeight,
+      XFA_AttributeValue eFlowStrategy,
+      uint8_t* uCurHAlignState,
+      std::vector<RetainPtr<CXFA_ContentLayoutItem>> (&rgCurLineLayoutItems)[3],
+      bool bUseBreakControl,
+      float fAvailHeight,
+      float fRealHeight,
+      float fContentWidthLimit,
+      float* fContentCurRowY,
+      float* fContentCurRowAvailWidth,
+      float* fContentCurRowHeight,
+      bool* bAddedItemInRow,
+      bool* bForceEndPage,
+      Context* pLayoutContext,
+      bool bNewRow);
+
+  Optional<Stage> HandleKeep(CXFA_Node* pBreakAfterNode,
+                             CXFA_Node** pCurActionNode);
+  Optional<Stage> HandleBookendLeader(CXFA_Node* pParentContainer,
+                                      CXFA_Node** pCurActionNode);
+  Optional<Stage> HandleBreakBefore(CXFA_Node* pChildContainer,
+                                    CXFA_Node** pCurActionNode);
+  Optional<Stage> HandleBreakAfter(CXFA_Node* pChildContainer,
+                                   CXFA_Node** pCurActionNode);
+  Optional<Stage> HandleCheckNextChildContainer(CXFA_Node* pParentContainer,
+                                                CXFA_Node* pChildContainer,
+                                                CXFA_Node** pCurActionNode);
+  Optional<Stage> HandleBookendTrailer(CXFA_Node* pParentContainer,
+                                       CXFA_Node** pCurActionNode);
+  void ProcessKeepNodesEnd();
+  void AdjustContainerSpecifiedSize(Context* pContext,
+                                    CFX_SizeF* pSize,
+                                    bool* pContainerWidthAutoSize,
+                                    bool* pContainerHeightAutoSize);
+  CXFA_ContentLayoutItem* FindLastContentLayoutItem(
+      XFA_AttributeValue eFlowStrategy);
+  CFX_SizeF CalculateLayoutItemSize(const CXFA_ContentLayoutItem* pLayoutChild);
+
+  Stage m_nCurChildNodeStage = Stage::kNone;
+  Result m_ePreProcessRs = Result::kDone;
+  bool m_bBreakPending = true;
+  bool m_bUseInherited = false;
+  bool m_bKeepBreakFinish = false;
+  bool m_bIsProcessKeep = false;
+  bool m_bHasAvailHeight = true;
+  float m_fUsedSize = 0;
+  float m_fLastRowWidth = 0;
+  float m_fLastRowY = 0;
+  float m_fWidthLimit = 0;
+  CXFA_Node* const m_pFormNode;
+  CXFA_Node* m_pCurChildNode = nullptr;
+  CXFA_Node* m_pKeepHeadNode = nullptr;
+  CXFA_Node* m_pKeepTailNode = nullptr;
+  RetainPtr<CXFA_ContentLayoutItem> m_pLayoutItem;
+  RetainPtr<CXFA_ContentLayoutItem> m_pOldLayoutItem;
+  UnownedPtr<CXFA_ViewLayoutProcessor> m_pViewLayoutProcessor;
+  std::vector<float> m_rgSpecifiedColumnWidths;
+  std::vector<RetainPtr<CXFA_ContentLayoutItem>> m_ArrayKeepItems;
+  std::list<CXFA_Node*> m_PendingNodes;
+  std::map<CXFA_Node*, int32_t> m_PendingNodesCount;
+  std::unique_ptr<CXFA_ContentLayoutProcessor> m_pCurChildPreprocessor;
+};
+
+#endif  // XFA_FXFA_LAYOUT_CXFA_CONTENTLAYOUTPROCESSOR_H_
diff --git a/xfa/fxfa/layout/cxfa_layoutitem.cpp b/xfa/fxfa/layout/cxfa_layoutitem.cpp
new file mode 100644
index 0000000..b4523c9
--- /dev/null
+++ b/xfa/fxfa/layout/cxfa_layoutitem.cpp
@@ -0,0 +1,77 @@
+// Copyright 2016 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
+
+#include "xfa/fxfa/layout/cxfa_layoutitem.h"
+
+#include <utility>
+
+#include "fxjs/xfa/cjx_object.h"
+#include "xfa/fxfa/cxfa_ffnotify.h"
+#include "xfa/fxfa/layout/cxfa_contentlayoutitem.h"
+#include "xfa/fxfa/layout/cxfa_layoutprocessor.h"
+#include "xfa/fxfa/layout/cxfa_viewlayoutitem.h"
+#include "xfa/fxfa/parser/cxfa_margin.h"
+#include "xfa/fxfa/parser/cxfa_measurement.h"
+#include "xfa/fxfa/parser/cxfa_node.h"
+
+void XFA_ReleaseLayoutItem(const RetainPtr<CXFA_LayoutItem>& pLayoutItem) {
+  RetainPtr<CXFA_LayoutItem> pNode(pLayoutItem->GetFirstChild());
+  while (pNode) {
+    RetainPtr<CXFA_LayoutItem> pNext(pNode->GetNextSibling());
+    XFA_ReleaseLayoutItem(pNode);
+    pNode = std::move(pNext);
+  }
+  CXFA_Document* pDocument = pLayoutItem->GetFormNode()->GetDocument();
+  CXFA_FFNotify* pNotify = pDocument->GetNotify();
+  auto* pDocLayout = CXFA_LayoutProcessor::FromDocument(pDocument);
+  pNotify->OnLayoutItemRemoving(pDocLayout, pLayoutItem.Get());
+  if (pLayoutItem->GetFormNode()->GetElementType() == XFA_Element::PageArea) {
+    pNotify->OnPageEvent(ToViewLayoutItem(pLayoutItem.Get()),
+                         XFA_PAGEVIEWEVENT_PostRemoved);
+  }
+  pLayoutItem->RemoveSelfIfParented();
+}
+
+CXFA_LayoutItem::CXFA_LayoutItem(CXFA_Node* pNode, ItemType type)
+    : m_ItemType(type), m_pFormNode(pNode) {}
+
+CXFA_LayoutItem::~CXFA_LayoutItem() {
+  CHECK(!GetParent());
+  if (m_pFormNode) {
+    auto* pJSObj = m_pFormNode->JSObject();
+    if (pJSObj && pJSObj->GetLayoutItem() == this)
+      pJSObj->SetLayoutItem(nullptr);
+  }
+}
+
+CXFA_ViewLayoutItem* CXFA_LayoutItem::AsViewLayoutItem() {
+  return IsViewLayoutItem() ? static_cast<CXFA_ViewLayoutItem*>(this) : nullptr;
+}
+
+const CXFA_ViewLayoutItem* CXFA_LayoutItem::AsViewLayoutItem() const {
+  return IsViewLayoutItem() ? static_cast<const CXFA_ViewLayoutItem*>(this)
+                            : nullptr;
+}
+
+CXFA_ContentLayoutItem* CXFA_LayoutItem::AsContentLayoutItem() {
+  return IsContentLayoutItem() ? static_cast<CXFA_ContentLayoutItem*>(this)
+                               : nullptr;
+}
+
+const CXFA_ContentLayoutItem* CXFA_LayoutItem::AsContentLayoutItem() const {
+  return IsContentLayoutItem()
+             ? static_cast<const CXFA_ContentLayoutItem*>(this)
+             : nullptr;
+}
+
+const CXFA_ViewLayoutItem* CXFA_LayoutItem::GetPage() const {
+  for (CXFA_LayoutItem* pCurNode = const_cast<CXFA_LayoutItem*>(this); pCurNode;
+       pCurNode = pCurNode->GetParent()) {
+    if (pCurNode->m_pFormNode->GetElementType() == XFA_Element::PageArea)
+      return pCurNode->AsViewLayoutItem();
+  }
+  return nullptr;
+}
diff --git a/xfa/fxfa/layout/cxfa_layoutitem.h b/xfa/fxfa/layout/cxfa_layoutitem.h
new file mode 100644
index 0000000..034c145
--- /dev/null
+++ b/xfa/fxfa/layout/cxfa_layoutitem.h
@@ -0,0 +1,53 @@
+// Copyright 2016 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_LAYOUT_CXFA_LAYOUTITEM_H_
+#define XFA_FXFA_LAYOUT_CXFA_LAYOUTITEM_H_
+
+#include "core/fxcrt/retain_ptr.h"
+#include "core/fxcrt/retained_tree_node.h"
+#include "core/fxcrt/unowned_ptr.h"
+#include "xfa/fxfa/parser/cxfa_document.h"
+
+class CXFA_ContentLayoutItem;
+class CXFA_LayoutProcessor;
+class CXFA_ViewLayoutItem;
+
+class CXFA_LayoutItem : public RetainedTreeNode<CXFA_LayoutItem> {
+ public:
+  ~CXFA_LayoutItem() override;
+
+  bool IsViewLayoutItem() const { return m_ItemType == kViewItem; }
+  bool IsContentLayoutItem() const { return m_ItemType == kContentItem; }
+  CXFA_ViewLayoutItem* AsViewLayoutItem();
+  const CXFA_ViewLayoutItem* AsViewLayoutItem() const;
+  CXFA_ContentLayoutItem* AsContentLayoutItem();
+  const CXFA_ContentLayoutItem* AsContentLayoutItem() const;
+
+  const CXFA_ViewLayoutItem* GetPage() const;
+  CXFA_Node* GetFormNode() const { return m_pFormNode.Get(); }
+  void SetFormNode(CXFA_Node* pNode) { m_pFormNode = pNode; }
+
+ protected:
+  enum ItemType { kViewItem, kContentItem };
+  CXFA_LayoutItem(CXFA_Node* pNode, ItemType type);
+
+ private:
+  const ItemType m_ItemType;
+  UnownedPtr<CXFA_Node> m_pFormNode;
+};
+
+inline CXFA_ViewLayoutItem* ToViewLayoutItem(CXFA_LayoutItem* item) {
+  return item ? item->AsViewLayoutItem() : nullptr;
+}
+
+inline CXFA_ContentLayoutItem* ToContentLayoutItem(CXFA_LayoutItem* item) {
+  return item ? item->AsContentLayoutItem() : nullptr;
+}
+
+void XFA_ReleaseLayoutItem(const RetainPtr<CXFA_LayoutItem>& pLayoutItem);
+
+#endif  // XFA_FXFA_LAYOUT_CXFA_LAYOUTITEM_H_
diff --git a/xfa/fxfa/layout/cxfa_layoutitem_embeddertest.cpp b/xfa/fxfa/layout/cxfa_layoutitem_embeddertest.cpp
new file mode 100644
index 0000000..0ba54ef
--- /dev/null
+++ b/xfa/fxfa/layout/cxfa_layoutitem_embeddertest.cpp
@@ -0,0 +1,50 @@
+// Copyright 2019 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 "testing/embedder_test.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+class CXFALayoutItemEmbedderTest : public EmbedderTest {};
+
+#if defined(LEAK_SANITIZER)
+
+// Leaks. See https://crbug.com/pdfium/1301
+#define MAYBE_Bug_1301 DISABLED_Bug_1301
+
+#else
+#define MAYBE_Bug_1301 Bug_1301
+#endif
+
+TEST_F(CXFALayoutItemEmbedderTest, Bug_1265) {
+  EXPECT_TRUE(OpenDocument("bug_1265.pdf"));
+  FPDF_PAGE page0 = LoadPage(0);
+  FPDF_PAGE page1 = LoadPage(1);
+  EXPECT_NE(nullptr, page0);
+  EXPECT_EQ(nullptr, page1);
+  UnloadPage(page0);
+}
+
+TEST_F(CXFALayoutItemEmbedderTest, MAYBE_Bug_1301) {
+  EXPECT_TRUE(OpenDocument("bug_1301.pdf"));
+  FPDF_PAGE page0 = LoadPage(0);
+  FPDF_PAGE page1 = LoadPage(1);
+  FPDF_PAGE page2 = LoadPage(2);
+  EXPECT_NE(nullptr, page0);
+  EXPECT_NE(nullptr, page1);
+  EXPECT_EQ(nullptr, page2);
+  UnloadPage(page0);
+  UnloadPage(page1);
+}
+
+TEST_F(CXFALayoutItemEmbedderTest, Bug_306123) {
+  EXPECT_TRUE(OpenDocument("bug_306123.pdf"));
+  FPDF_PAGE page0 = LoadPage(0);
+  FPDF_PAGE page1 = LoadPage(1);
+  FPDF_PAGE page2 = LoadPage(2);
+  EXPECT_NE(nullptr, page0);
+  EXPECT_NE(nullptr, page1);
+  EXPECT_EQ(nullptr, page2);
+  UnloadPage(page0);
+  UnloadPage(page1);
+}
diff --git a/xfa/fxfa/layout/cxfa_layoutprocessor.cpp b/xfa/fxfa/layout/cxfa_layoutprocessor.cpp
new file mode 100644
index 0000000..bb38fbe
--- /dev/null
+++ b/xfa/fxfa/layout/cxfa_layoutprocessor.cpp
@@ -0,0 +1,133 @@
+// Copyright 2016 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
+
+#include "xfa/fxfa/layout/cxfa_layoutprocessor.h"
+
+#include "fxjs/xfa/cjx_object.h"
+#include "third_party/base/ptr_util.h"
+#include "third_party/base/stl_util.h"
+#include "xfa/fxfa/layout/cxfa_contentlayoutitem.h"
+#include "xfa/fxfa/layout/cxfa_contentlayoutprocessor.h"
+#include "xfa/fxfa/layout/cxfa_viewlayoutprocessor.h"
+#include "xfa/fxfa/parser/cxfa_document.h"
+#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_subform.h"
+#include "xfa/fxfa/parser/xfa_document_datamerger_imp.h"
+#include "xfa/fxfa/parser/xfa_utils.h"
+
+// static
+CXFA_LayoutProcessor* CXFA_LayoutProcessor::FromDocument(
+    const CXFA_Document* pXFADoc) {
+  return static_cast<CXFA_LayoutProcessor*>(pXFADoc->GetLayoutProcessor());
+}
+
+CXFA_LayoutProcessor::CXFA_LayoutProcessor() = default;
+
+CXFA_LayoutProcessor::~CXFA_LayoutProcessor() = default;
+
+void CXFA_LayoutProcessor::SetForceRelayout(bool bForceRestart) {
+  m_bNeedLayout = bForceRestart;
+}
+
+int32_t CXFA_LayoutProcessor::StartLayout(bool bForceRestart) {
+  if (!bForceRestart && !NeedLayout())
+    return 100;
+
+  m_pContentLayoutProcessor.reset();
+  m_nProgressCounter = 0;
+  CXFA_Node* pFormPacketNode =
+      ToNode(GetDocument()->GetXFAObject(XFA_HASHCODE_Form));
+  if (!pFormPacketNode)
+    return -1;
+
+  CXFA_Subform* pFormRoot =
+      pFormPacketNode->GetFirstChildByClass<CXFA_Subform>(XFA_Element::Subform);
+  if (!pFormRoot)
+    return -1;
+
+  if (!m_pViewLayoutProcessor)
+    m_pViewLayoutProcessor = pdfium::MakeUnique<CXFA_ViewLayoutProcessor>(this);
+  if (!m_pViewLayoutProcessor->InitLayoutPage(pFormRoot))
+    return -1;
+
+  if (!m_pViewLayoutProcessor->PrepareFirstPage(pFormRoot))
+    return -1;
+
+  m_pContentLayoutProcessor = pdfium::MakeUnique<CXFA_ContentLayoutProcessor>(
+      pFormRoot, m_pViewLayoutProcessor.get());
+  m_nProgressCounter = 1;
+  return 0;
+}
+
+int32_t CXFA_LayoutProcessor::DoLayout() {
+  if (m_nProgressCounter < 1)
+    return -1;
+
+  CXFA_ContentLayoutProcessor::Result eStatus;
+  CXFA_Node* pFormNode = m_pContentLayoutProcessor->GetFormNode();
+  float fPosX =
+      pFormNode->JSObject()->GetMeasureInUnit(XFA_Attribute::X, XFA_Unit::Pt);
+  float fPosY =
+      pFormNode->JSObject()->GetMeasureInUnit(XFA_Attribute::Y, XFA_Unit::Pt);
+  do {
+    float fAvailHeight = m_pViewLayoutProcessor->GetAvailHeight();
+    eStatus =
+        m_pContentLayoutProcessor->DoLayout(true, fAvailHeight, fAvailHeight);
+    if (eStatus != CXFA_ContentLayoutProcessor::Result::kDone)
+      m_nProgressCounter++;
+
+    RetainPtr<CXFA_ContentLayoutItem> pLayoutItem =
+        m_pContentLayoutProcessor->ExtractLayoutItem();
+    if (pLayoutItem)
+      pLayoutItem->m_sPos = CFX_PointF(fPosX, fPosY);
+
+    m_pViewLayoutProcessor->SubmitContentItem(pLayoutItem, eStatus);
+  } while (eStatus != CXFA_ContentLayoutProcessor::Result::kDone);
+
+  if (eStatus == CXFA_ContentLayoutProcessor::Result::kDone) {
+    m_pViewLayoutProcessor->FinishPaginatedPageSets();
+    m_pViewLayoutProcessor->SyncLayoutData();
+    m_bNeedLayout = false;
+    m_rgChangedContainers.clear();
+  }
+  return 100 *
+         (eStatus == CXFA_ContentLayoutProcessor::Result::kDone
+              ? m_nProgressCounter
+              : m_nProgressCounter - 1) /
+         m_nProgressCounter;
+}
+
+bool CXFA_LayoutProcessor::IncrementLayout() {
+  if (m_bNeedLayout) {
+    StartLayout(true);
+    return DoLayout() == 100;
+  }
+  return m_rgChangedContainers.empty();
+}
+
+int32_t CXFA_LayoutProcessor::CountPages() const {
+  return m_pViewLayoutProcessor ? m_pViewLayoutProcessor->GetPageCount() : 0;
+}
+
+CXFA_ViewLayoutItem* CXFA_LayoutProcessor::GetPage(int32_t index) const {
+  return m_pViewLayoutProcessor ? m_pViewLayoutProcessor->GetPage(index)
+                                : nullptr;
+}
+
+CXFA_LayoutItem* CXFA_LayoutProcessor::GetLayoutItem(CXFA_Node* pFormItem) {
+  return pFormItem->JSObject()->GetLayoutItem();
+}
+
+void CXFA_LayoutProcessor::AddChangedContainer(CXFA_Node* pContainer) {
+  if (!pdfium::ContainsValue(m_rgChangedContainers, pContainer))
+    m_rgChangedContainers.push_back(pContainer);
+}
+
+bool CXFA_LayoutProcessor::NeedLayout() const {
+  return m_bNeedLayout || !m_rgChangedContainers.empty();
+}
diff --git a/xfa/fxfa/layout/cxfa_layoutprocessor.h b/xfa/fxfa/layout/cxfa_layoutprocessor.h
new file mode 100644
index 0000000..18dc208
--- /dev/null
+++ b/xfa/fxfa/layout/cxfa_layoutprocessor.h
@@ -0,0 +1,57 @@
+// Copyright 2016 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_LAYOUT_CXFA_LAYOUTPROCESSOR_H_
+#define XFA_FXFA_LAYOUT_CXFA_LAYOUTPROCESSOR_H_
+
+#include <memory>
+#include <vector>
+
+#include "core/fxcrt/fx_system.h"
+#include "core/fxcrt/unowned_ptr.h"
+#include "xfa/fxfa/parser/cxfa_document.h"
+
+class CXFA_ContentLayoutProcessor;
+class CXFA_LayoutItem;
+class CXFA_Node;
+class CXFA_ViewLayoutItem;
+class CXFA_ViewLayoutProcessor;
+
+class CXFA_LayoutProcessor : public CXFA_Document::LayoutProcessorIface {
+ public:
+  static CXFA_LayoutProcessor* FromDocument(const CXFA_Document* pXFADoc);
+
+  CXFA_LayoutProcessor();
+  ~CXFA_LayoutProcessor() override;
+
+  // CXFA_Document::LayoutProcessorIface:
+  void SetForceRelayout(bool bForceRestart) override;
+  void AddChangedContainer(CXFA_Node* pContainer) override;
+
+  int32_t StartLayout(bool bForceRestart);
+  int32_t DoLayout();
+  bool IncrementLayout();
+  int32_t CountPages() const;
+  CXFA_ViewLayoutItem* GetPage(int32_t index) const;
+  CXFA_LayoutItem* GetLayoutItem(CXFA_Node* pFormItem);
+  CXFA_ContentLayoutProcessor* GetRootContentLayoutProcessor() const {
+    return m_pContentLayoutProcessor.get();
+  }
+  CXFA_ViewLayoutProcessor* GetLayoutPageMgr() const {
+    return m_pViewLayoutProcessor.get();
+  }
+
+ private:
+  bool NeedLayout() const;
+
+  std::unique_ptr<CXFA_ViewLayoutProcessor> m_pViewLayoutProcessor;
+  std::unique_ptr<CXFA_ContentLayoutProcessor> m_pContentLayoutProcessor;
+  std::vector<CXFA_Node*> m_rgChangedContainers;
+  uint32_t m_nProgressCounter = 0;
+  bool m_bNeedLayout = true;
+};
+
+#endif  // XFA_FXFA_LAYOUT_CXFA_LAYOUTPROCESSOR_H_
diff --git a/xfa/fxfa/layout/cxfa_traversestrategy_layoutitem.h b/xfa/fxfa/layout/cxfa_traversestrategy_layoutitem.h
new file mode 100644
index 0000000..f71d708
--- /dev/null
+++ b/xfa/fxfa/layout/cxfa_traversestrategy_layoutitem.h
@@ -0,0 +1,32 @@
+// Copyright 2016 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_LAYOUT_CXFA_TRAVERSESTRATEGY_LAYOUTITEM_H_
+#define XFA_FXFA_LAYOUT_CXFA_TRAVERSESTRATEGY_LAYOUTITEM_H_
+
+#include "core/fxcrt/retain_ptr.h"
+#include "xfa/fxfa/layout/cxfa_layoutitem.h"
+#include "xfa/fxfa/parser/cxfa_nodeiteratortemplate.h"
+
+class CXFA_TraverseStrategy_LayoutItem {
+ public:
+  static CXFA_LayoutItem* GetFirstChild(CXFA_LayoutItem* pLayoutItem) {
+    return pLayoutItem->GetFirstChild();
+  }
+  static CXFA_LayoutItem* GetNextSibling(CXFA_LayoutItem* pLayoutItem) {
+    return pLayoutItem->GetNextSibling();
+  }
+  static CXFA_LayoutItem* GetParent(CXFA_LayoutItem* pLayoutItem) {
+    return pLayoutItem->GetParent();
+  }
+};
+
+using CXFA_LayoutItemIterator =
+    CXFA_NodeIteratorTemplate<CXFA_LayoutItem,
+                              CXFA_TraverseStrategy_LayoutItem,
+                              RetainPtr<CXFA_LayoutItem>>;
+
+#endif  // XFA_FXFA_LAYOUT_CXFA_TRAVERSESTRATEGY_LAYOUTITEM_H_
diff --git a/xfa/fxfa/layout/cxfa_viewlayoutitem.cpp b/xfa/fxfa/layout/cxfa_viewlayoutitem.cpp
new file mode 100644
index 0000000..fcef2ab
--- /dev/null
+++ b/xfa/fxfa/layout/cxfa_viewlayoutitem.cpp
@@ -0,0 +1,61 @@
+// Copyright 2016 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
+
+#include "xfa/fxfa/layout/cxfa_viewlayoutitem.h"
+
+#include <utility>
+
+#include "fxjs/xfa/cjx_object.h"
+#include "xfa/fxfa/cxfa_ffpageview.h"
+#include "xfa/fxfa/layout/cxfa_layoutprocessor.h"
+#include "xfa/fxfa/layout/cxfa_viewlayoutprocessor.h"
+#include "xfa/fxfa/parser/cxfa_measurement.h"
+#include "xfa/fxfa/parser/cxfa_medium.h"
+#include "xfa/fxfa/parser/cxfa_node.h"
+
+CXFA_ViewLayoutItem::CXFA_ViewLayoutItem(
+    CXFA_Node* pNode,
+    std::unique_ptr<CXFA_FFPageView> pPageView)
+    : CXFA_LayoutItem(pNode, kViewItem), m_pFFPageView(std::move(pPageView)) {
+  if (m_pFFPageView)
+    m_pFFPageView->SetLayoutItem(this);
+}
+
+CXFA_ViewLayoutItem::~CXFA_ViewLayoutItem() {
+  if (m_pFFPageView)
+    m_pFFPageView->SetLayoutItem(nullptr);
+}
+
+CXFA_LayoutProcessor* CXFA_ViewLayoutItem::GetLayout() const {
+  return CXFA_LayoutProcessor::FromDocument(GetFormNode()->GetDocument());
+}
+
+int32_t CXFA_ViewLayoutItem::GetPageIndex() const {
+  auto* pLayout =
+      CXFA_LayoutProcessor::FromDocument(GetFormNode()->GetDocument());
+  return pLayout->GetLayoutPageMgr()->GetPageIndex(this);
+}
+
+CFX_SizeF CXFA_ViewLayoutItem::GetPageSize() const {
+  CFX_SizeF size;
+  CXFA_Medium* pMedium =
+      GetFormNode()->GetFirstChildByClass<CXFA_Medium>(XFA_Element::Medium);
+  if (!pMedium)
+    return size;
+
+  size = CFX_SizeF(
+      pMedium->JSObject()->GetMeasureInUnit(XFA_Attribute::Short, XFA_Unit::Pt),
+      pMedium->JSObject()->GetMeasureInUnit(XFA_Attribute::Long, XFA_Unit::Pt));
+  if (pMedium->JSObject()->GetEnum(XFA_Attribute::Orientation) ==
+      XFA_AttributeValue::Landscape) {
+    size = CFX_SizeF(size.height, size.width);
+  }
+  return size;
+}
+
+CXFA_Node* CXFA_ViewLayoutItem::GetMasterPage() const {
+  return GetFormNode();
+}
diff --git a/xfa/fxfa/layout/cxfa_viewlayoutitem.h b/xfa/fxfa/layout/cxfa_viewlayoutitem.h
new file mode 100644
index 0000000..1c9f77c
--- /dev/null
+++ b/xfa/fxfa/layout/cxfa_viewlayoutitem.h
@@ -0,0 +1,38 @@
+// Copyright 2016 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_LAYOUT_CXFA_VIEWLAYOUTITEM_H_
+#define XFA_FXFA_LAYOUT_CXFA_VIEWLAYOUTITEM_H_
+
+#include <memory>
+
+#include "xfa/fxfa/layout/cxfa_layoutitem.h"
+
+class CXFA_FFPageView;
+
+class CXFA_ViewLayoutItem : public CXFA_LayoutItem {
+ public:
+  template <typename T, typename... Args>
+  friend RetainPtr<T> pdfium::MakeRetain(Args&&... args);
+
+  ~CXFA_ViewLayoutItem() override;
+
+  CXFA_FFPageView* GetPageView() const { return m_pFFPageView.get(); }
+  CXFA_LayoutProcessor* GetLayout() const;
+  int32_t GetPageIndex() const;
+  CFX_SizeF GetPageSize() const;
+  CXFA_Node* GetMasterPage() const;
+
+  UnownedPtr<CXFA_Node> m_pOldSubform;
+
+ private:
+  CXFA_ViewLayoutItem(CXFA_Node* pNode,
+                      std::unique_ptr<CXFA_FFPageView> pPageView);
+
+  std::unique_ptr<CXFA_FFPageView> const m_pFFPageView;
+};
+
+#endif  // XFA_FXFA_LAYOUT_CXFA_VIEWLAYOUTITEM_H_
diff --git a/xfa/fxfa/layout/cxfa_viewlayoutprocessor.cpp b/xfa/fxfa/layout/cxfa_viewlayoutprocessor.cpp
new file mode 100644
index 0000000..dcfdd47
--- /dev/null
+++ b/xfa/fxfa/layout/cxfa_viewlayoutprocessor.cpp
@@ -0,0 +1,2005 @@
+// Copyright 2014 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
+
+#include "xfa/fxfa/layout/cxfa_viewlayoutprocessor.h"
+
+#include <utility>
+
+#include "fxjs/xfa/cfxjse_engine.h"
+#include "fxjs/xfa/cjx_object.h"
+#include "third_party/base/ptr_util.h"
+#include "third_party/base/stl_util.h"
+#include "xfa/fxfa/cxfa_ffnotify.h"
+#include "xfa/fxfa/cxfa_ffpageview.h"
+#include "xfa/fxfa/layout/cxfa_contentlayoutitem.h"
+#include "xfa/fxfa/layout/cxfa_contentlayoutprocessor.h"
+#include "xfa/fxfa/layout/cxfa_layoutprocessor.h"
+#include "xfa/fxfa/layout/cxfa_traversestrategy_layoutitem.h"
+#include "xfa/fxfa/layout/cxfa_viewlayoutitem.h"
+#include "xfa/fxfa/parser/cxfa_contentarea.h"
+#include "xfa/fxfa/parser/cxfa_document.h"
+#include "xfa/fxfa/parser/cxfa_localemgr.h"
+#include "xfa/fxfa/parser/cxfa_measurement.h"
+#include "xfa/fxfa/parser/cxfa_medium.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_occur.h"
+#include "xfa/fxfa/parser/cxfa_pageset.h"
+#include "xfa/fxfa/parser/cxfa_subform.h"
+#include "xfa/fxfa/parser/cxfa_traversestrategy_xfacontainernode.h"
+#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"
+
+namespace {
+
+class TraverseStrategy_ViewLayoutItem {
+ public:
+  static CXFA_ViewLayoutItem* GetFirstChild(CXFA_ViewLayoutItem* pLayoutItem) {
+    for (CXFA_LayoutItem* pChildItem = pLayoutItem->GetFirstChild(); pChildItem;
+         pChildItem = pChildItem->GetNextSibling()) {
+      if (CXFA_ViewLayoutItem* pContainer = pChildItem->AsViewLayoutItem()) {
+        return pContainer;
+      }
+    }
+    return nullptr;
+  }
+
+  static CXFA_ViewLayoutItem* GetNextSibling(CXFA_ViewLayoutItem* pLayoutItem) {
+    for (CXFA_LayoutItem* pChildItem = pLayoutItem->GetNextSibling();
+         pChildItem; pChildItem = pChildItem->GetNextSibling()) {
+      if (CXFA_ViewLayoutItem* pContainer = pChildItem->AsViewLayoutItem()) {
+        return pContainer;
+      }
+    }
+    return nullptr;
+  }
+
+  static CXFA_ViewLayoutItem* GetParent(CXFA_ViewLayoutItem* pLayoutItem) {
+    return ToViewLayoutItem(pLayoutItem->GetParent());
+  }
+};
+
+using ViewLayoutItemIterator =
+    CXFA_NodeIteratorTemplate<CXFA_ViewLayoutItem,
+                              TraverseStrategy_ViewLayoutItem>;
+
+class TraverseStrategy_PageSet {
+ public:
+  static CXFA_ViewLayoutItem* GetFirstChild(CXFA_ViewLayoutItem* pLayoutItem) {
+    if (pLayoutItem->GetFormNode()->GetElementType() != XFA_Element::PageSet)
+      return nullptr;
+
+    for (CXFA_LayoutItem* pChildItem = pLayoutItem->GetFirstChild(); pChildItem;
+         pChildItem = pChildItem->GetNextSibling()) {
+      CXFA_ViewLayoutItem* pContainer = pChildItem->AsViewLayoutItem();
+      if (pContainer &&
+          pContainer->GetFormNode()->GetElementType() == XFA_Element::PageSet) {
+        return pContainer;
+      }
+    }
+    return nullptr;
+  }
+
+  static CXFA_ViewLayoutItem* GetNextSibling(CXFA_ViewLayoutItem* pLayoutItem) {
+    for (CXFA_LayoutItem* pChildItem = pLayoutItem->GetNextSibling();
+         pChildItem; pChildItem = pChildItem->GetNextSibling()) {
+      CXFA_ViewLayoutItem* pContainer = pChildItem->AsViewLayoutItem();
+      if (pContainer &&
+          pContainer->GetFormNode()->GetElementType() == XFA_Element::PageSet) {
+        return pContainer;
+      }
+    }
+    return nullptr;
+  }
+
+  static CXFA_ViewLayoutItem* GetParent(CXFA_ViewLayoutItem* pLayoutItem) {
+    return ToViewLayoutItem(pLayoutItem->GetParent());
+  }
+};
+
+using PageSetIterator =
+    CXFA_NodeIteratorTemplate<CXFA_ViewLayoutItem, TraverseStrategy_PageSet>;
+
+uint32_t GetRelevant(CXFA_Node* pFormItem, uint32_t dwParentRelvant) {
+  uint32_t dwRelevant = XFA_WidgetStatus_Viewable | XFA_WidgetStatus_Printable;
+  WideString wsRelevant =
+      pFormItem->JSObject()->GetCData(XFA_Attribute::Relevant);
+  if (!wsRelevant.IsEmpty()) {
+    if (wsRelevant.EqualsASCII("+print") || wsRelevant.EqualsASCII("print"))
+      dwRelevant &= ~XFA_WidgetStatus_Viewable;
+    else if (wsRelevant.EqualsASCII("-print"))
+      dwRelevant &= ~XFA_WidgetStatus_Printable;
+  }
+  if (!(dwParentRelvant & XFA_WidgetStatus_Viewable) &&
+      (dwRelevant != XFA_WidgetStatus_Viewable)) {
+    dwRelevant &= ~XFA_WidgetStatus_Viewable;
+  }
+  if (!(dwParentRelvant & XFA_WidgetStatus_Printable) &&
+      (dwRelevant != XFA_WidgetStatus_Printable)) {
+    dwRelevant &= ~XFA_WidgetStatus_Printable;
+  }
+  return dwRelevant;
+}
+
+void SyncContainer(CXFA_FFNotify* pNotify,
+                   CXFA_LayoutProcessor* pDocLayout,
+                   CXFA_LayoutItem* pViewItem,
+                   uint32_t dwRelevant,
+                   bool bVisible,
+                   int32_t nPageIndex) {
+  bool bVisibleItem = false;
+  uint32_t dwStatus = 0;
+  uint32_t dwRelevantContainer = 0;
+  if (bVisible) {
+    XFA_AttributeValue eAttributeValue =
+        pViewItem->GetFormNode()
+            ->JSObject()
+            ->TryEnum(XFA_Attribute::Presence, true)
+            .value_or(XFA_AttributeValue::Visible);
+    if (eAttributeValue == XFA_AttributeValue::Visible)
+      bVisibleItem = true;
+
+    dwRelevantContainer = GetRelevant(pViewItem->GetFormNode(), dwRelevant);
+    dwStatus =
+        (bVisibleItem ? XFA_WidgetStatus_Visible : 0) | dwRelevantContainer;
+  }
+  pNotify->OnLayoutItemAdded(pDocLayout, pViewItem, nPageIndex, dwStatus);
+  for (CXFA_LayoutItem* pChild = pViewItem->GetFirstChild(); pChild;
+       pChild = pChild->GetNextSibling()) {
+    if (pChild->IsContentLayoutItem()) {
+      SyncContainer(pNotify, pDocLayout, pChild, dwRelevantContainer,
+                    bVisibleItem, nPageIndex);
+    }
+  }
+}
+
+void ReorderLayoutItemToTail(const RetainPtr<CXFA_LayoutItem>& pLayoutItem) {
+  CXFA_LayoutItem* pParentLayoutItem = pLayoutItem->GetParent();
+  if (!pParentLayoutItem)
+    return;
+
+  pParentLayoutItem->RemoveChild(pLayoutItem);
+  pParentLayoutItem->AppendLastChild(pLayoutItem);
+}
+
+CXFA_Node* ResolveBreakTarget(CXFA_Node* pPageSetRoot,
+                              bool bNewExprStyle,
+                              WideString* pTargetAll) {
+  if (!pPageSetRoot)
+    return nullptr;
+
+  CXFA_Document* pDocument = pPageSetRoot->GetDocument();
+  if (pTargetAll->IsEmpty())
+    return nullptr;
+
+  pTargetAll->Trim();
+  int32_t iSplitIndex = 0;
+  bool bTargetAllFind = true;
+  while (iSplitIndex != -1) {
+    WideString wsExpr;
+    Optional<size_t> iSplitNextIndex = 0;
+    if (!bTargetAllFind) {
+      iSplitNextIndex = pTargetAll->Find(' ', iSplitIndex);
+      if (!iSplitNextIndex.has_value())
+        return nullptr;
+      wsExpr = pTargetAll->Substr(iSplitIndex,
+                                  iSplitNextIndex.value() - iSplitIndex);
+    } else {
+      wsExpr = *pTargetAll;
+    }
+    if (wsExpr.IsEmpty())
+      return nullptr;
+
+    bTargetAllFind = false;
+    if (wsExpr[0] == '#') {
+      CXFA_Node* pNode = pDocument->GetNodeByID(
+          ToNode(pDocument->GetXFAObject(XFA_HASHCODE_Template)),
+          wsExpr.Last(wsExpr.GetLength() - 1).AsStringView());
+      if (pNode)
+        return pNode;
+    } else if (bNewExprStyle) {
+      WideString wsProcessedTarget = wsExpr;
+      if (wsExpr.First(4).EqualsASCII("som(") && wsExpr.Back() == L')')
+        wsProcessedTarget = wsExpr.Substr(4, wsExpr.GetLength() - 5);
+
+      XFA_RESOLVENODE_RS rs;
+      bool bRet = pDocument->GetScriptContext()->ResolveObjects(
+          pPageSetRoot, wsProcessedTarget.AsStringView(), &rs,
+          XFA_RESOLVENODE_Children | XFA_RESOLVENODE_Properties |
+              XFA_RESOLVENODE_Attributes | XFA_RESOLVENODE_Siblings |
+              XFA_RESOLVENODE_Parent,
+          nullptr);
+      if (bRet && rs.objects.front()->IsNode())
+        return rs.objects.front()->AsNode();
+    }
+    iSplitIndex = iSplitNextIndex.value();
+  }
+  return nullptr;
+}
+
+void SetLayoutGeneratedNodeFlag(CXFA_Node* pNode) {
+  pNode->SetFlag(XFA_NodeFlag_LayoutGeneratedNode);
+  pNode->ClearFlag(XFA_NodeFlag_UnusedNode);
+}
+
+// Note: Returning nullptr is not the same as returning pdfium::nullopt.
+Optional<CXFA_ViewLayoutItem*> CheckContentAreaNotUsed(
+    CXFA_ViewLayoutItem* pPageAreaLayoutItem,
+    CXFA_Node* pContentArea) {
+  for (CXFA_LayoutItem* pChild = pPageAreaLayoutItem->GetFirstChild(); pChild;
+       pChild = pChild->GetNextSibling()) {
+    CXFA_ViewLayoutItem* pLayoutItem = pChild->AsViewLayoutItem();
+    if (pLayoutItem && pLayoutItem->GetFormNode() == pContentArea) {
+      if (!pLayoutItem->GetFirstChild())
+        return pLayoutItem;
+      return pdfium::nullopt;
+    }
+  }
+  return nullptr;
+}
+
+void SyncRemoveLayoutItem(CXFA_LayoutItem* pLayoutItem,
+                          CXFA_FFNotify* pNotify,
+                          CXFA_LayoutProcessor* pDocLayout) {
+  RetainPtr<CXFA_LayoutItem> pCurLayoutItem(pLayoutItem->GetFirstChild());
+  while (pCurLayoutItem) {
+    RetainPtr<CXFA_LayoutItem> pNextLayoutItem(
+        pCurLayoutItem->GetNextSibling());
+    SyncRemoveLayoutItem(pCurLayoutItem.Get(), pNotify, pDocLayout);
+    pCurLayoutItem = std::move(pNextLayoutItem);
+  }
+  pNotify->OnLayoutItemRemoving(pDocLayout, pLayoutItem);
+  pLayoutItem->RemoveSelfIfParented();
+}
+
+bool RunBreakTestScript(CXFA_Script* pTestScript) {
+  WideString wsExpression = pTestScript->JSObject()->GetContent(false);
+  if (wsExpression.IsEmpty())
+    return true;
+  return pTestScript->GetDocument()->GetNotify()->RunScript(
+      pTestScript, pTestScript->GetContainerParent());
+}
+
+float CalculateLayoutItemHeight(const CXFA_LayoutItem* pItem) {
+  float fHeight = 0;
+  for (const CXFA_LayoutItem* pChild = pItem->GetFirstChild(); pChild;
+       pChild = pChild->GetNextSibling()) {
+    const CXFA_ContentLayoutItem* pContent = pChild->AsContentLayoutItem();
+    if (pContent)
+      fHeight += pContent->m_sSize.height;
+  }
+  return fHeight;
+}
+
+std::vector<float> GetHeightsForContentAreas(const CXFA_LayoutItem* pItem) {
+  std::vector<float> heights;
+  for (const CXFA_LayoutItem* pChild = pItem->GetFirstChild(); pChild;
+       pChild = pChild->GetNextSibling()) {
+    if (pChild->GetFormNode()->GetElementType() == XFA_Element::ContentArea)
+      heights.push_back(CalculateLayoutItemHeight(pChild));
+  }
+  return heights;
+}
+
+std::pair<size_t, CXFA_LayoutItem*> GetPageAreaCountAndLastPageAreaFromPageSet(
+    CXFA_ViewLayoutItem* pPageSetLayoutItem) {
+  size_t nCount = 0;
+  CXFA_LayoutItem* pLast = nullptr;
+  for (CXFA_LayoutItem* pPageAreaLayoutItem =
+           pPageSetLayoutItem->GetFirstChild();
+       pPageAreaLayoutItem;
+       pPageAreaLayoutItem = pPageAreaLayoutItem->GetNextSibling()) {
+    XFA_Element type = pPageAreaLayoutItem->GetFormNode()->GetElementType();
+    if (type != XFA_Element::PageArea)
+      continue;
+
+    ++nCount;
+    pLast = pPageAreaLayoutItem;
+  }
+  return {nCount, pLast};
+}
+
+bool ContentAreasFitInPageAreas(const CXFA_Node* pNode,
+                                const std::vector<float>& rgUsedHeights) {
+  size_t iCurContentAreaIndex = 0;
+  for (const CXFA_Node* pContentAreaNode = pNode->GetFirstChild();
+       pContentAreaNode;
+       pContentAreaNode = pContentAreaNode->GetNextSibling()) {
+    if (pContentAreaNode->GetElementType() != XFA_Element::ContentArea)
+      continue;
+
+    if (iCurContentAreaIndex >= rgUsedHeights.size())
+      return false;
+
+    const float fHeight = pContentAreaNode->JSObject()->GetMeasureInUnit(
+                              XFA_Attribute::H, XFA_Unit::Pt) +
+                          kXFALayoutPrecision;
+    if (rgUsedHeights[iCurContentAreaIndex] > fHeight)
+      return false;
+
+    ++iCurContentAreaIndex;
+  }
+  return true;
+}
+
+}  // namespace
+
+CXFA_ViewLayoutProcessor::CXFA_ViewRecord::CXFA_ViewRecord() = default;
+
+CXFA_ViewLayoutProcessor::CXFA_ViewRecord::~CXFA_ViewRecord() = default;
+
+CXFA_ViewLayoutProcessor::CXFA_ViewLayoutProcessor(
+    CXFA_LayoutProcessor* pLayoutProcessor)
+    : m_pLayoutProcessor(pLayoutProcessor),
+      m_CurrentViewRecordIter(m_ProposedViewRecords.end()) {}
+
+CXFA_ViewLayoutProcessor::~CXFA_ViewLayoutProcessor() {
+  ClearData();
+  RetainPtr<CXFA_LayoutItem> pLayoutItem(GetRootLayoutItem());
+  while (pLayoutItem) {
+    CXFA_LayoutItem* pNextLayout = pLayoutItem->GetNextSibling();
+    XFA_ReleaseLayoutItem(pLayoutItem);
+    pLayoutItem.Reset(pNextLayout);
+  }
+}
+
+bool CXFA_ViewLayoutProcessor::InitLayoutPage(CXFA_Node* pFormNode) {
+  PrepareLayout();
+  CXFA_Node* pTemplateNode = pFormNode->GetTemplateNodeIfExists();
+  if (!pTemplateNode)
+    return false;
+
+  m_pPageSetNode = pTemplateNode->JSObject()->GetOrCreateProperty<CXFA_PageSet>(
+      0, XFA_Element::PageSet);
+  ASSERT(m_pPageSetNode);
+
+  if (m_pPageSetRootLayoutItem) {
+    m_pPageSetRootLayoutItem->RemoveSelfIfParented();
+  } else {
+    m_pPageSetRootLayoutItem =
+        pdfium::MakeRetain<CXFA_ViewLayoutItem>(m_pPageSetNode, nullptr);
+  }
+  m_pPageSetCurLayoutItem = m_pPageSetRootLayoutItem;
+  m_pPageSetNode->JSObject()->SetLayoutItem(m_pPageSetRootLayoutItem.Get());
+
+  XFA_AttributeValue eRelation =
+      m_pPageSetNode->JSObject()->GetEnum(XFA_Attribute::Relation);
+  if (eRelation != XFA_AttributeValue::Unknown)
+    m_ePageSetMode = eRelation;
+
+  InitPageSetMap();
+  CXFA_Node* pPageArea = nullptr;
+  int32_t iCount = 0;
+  for (pPageArea = m_pPageSetNode->GetFirstChild(); pPageArea;
+       pPageArea = pPageArea->GetNextSibling()) {
+    if (pPageArea->GetElementType() != XFA_Element::PageArea)
+      continue;
+
+    iCount++;
+    if (pPageArea->GetFirstChildByClass<CXFA_ContentArea>(
+            XFA_Element::ContentArea)) {
+      return true;
+    }
+  }
+  if (iCount > 0)
+    return false;
+
+  CXFA_Document* pDocument = pTemplateNode->GetDocument();
+  pPageArea =
+      m_pPageSetNode->GetChild<CXFA_Node>(0, XFA_Element::PageArea, false);
+  if (!pPageArea) {
+    pPageArea = pDocument->CreateNode(m_pPageSetNode->GetPacketType(),
+                                      XFA_Element::PageArea);
+    if (!pPageArea)
+      return false;
+
+    m_pPageSetNode->InsertChildAndNotify(pPageArea, nullptr);
+    pPageArea->SetFlagAndNotify(XFA_NodeFlag_Initialized);
+  }
+  CXFA_ContentArea* pContentArea =
+      pPageArea->GetChild<CXFA_ContentArea>(0, XFA_Element::ContentArea, false);
+  if (!pContentArea) {
+    pContentArea = static_cast<CXFA_ContentArea*>(pDocument->CreateNode(
+        pPageArea->GetPacketType(), XFA_Element::ContentArea));
+    if (!pContentArea)
+      return false;
+
+    pPageArea->InsertChildAndNotify(pContentArea, nullptr);
+    pContentArea->SetFlagAndNotify(XFA_NodeFlag_Initialized);
+    pContentArea->JSObject()->SetMeasure(
+        XFA_Attribute::X, CXFA_Measurement(0.25f, XFA_Unit::In), false);
+    pContentArea->JSObject()->SetMeasure(
+        XFA_Attribute::Y, CXFA_Measurement(0.25f, XFA_Unit::In), false);
+    pContentArea->JSObject()->SetMeasure(
+        XFA_Attribute::W, CXFA_Measurement(8.0f, XFA_Unit::In), false);
+    pContentArea->JSObject()->SetMeasure(
+        XFA_Attribute::H, CXFA_Measurement(10.5f, XFA_Unit::In), false);
+  }
+  CXFA_Medium* pMedium =
+      pPageArea->GetChild<CXFA_Medium>(0, XFA_Element::Medium, false);
+  if (!pMedium) {
+    pMedium = static_cast<CXFA_Medium*>(
+        pDocument->CreateNode(pPageArea->GetPacketType(), XFA_Element::Medium));
+    if (!pContentArea)
+      return false;
+
+    pPageArea->InsertChildAndNotify(pMedium, nullptr);
+    pMedium->SetFlagAndNotify(XFA_NodeFlag_Initialized);
+    pMedium->JSObject()->SetMeasure(
+        XFA_Attribute::Short, CXFA_Measurement(8.5f, XFA_Unit::In), false);
+    pMedium->JSObject()->SetMeasure(
+        XFA_Attribute::Long, CXFA_Measurement(11.0f, XFA_Unit::In), false);
+  }
+  return true;
+}
+
+bool CXFA_ViewLayoutProcessor::PrepareFirstPage(CXFA_Node* pRootSubform) {
+  bool bProBreakBefore = false;
+  const CXFA_Node* pBreakBeforeNode = nullptr;
+  while (pRootSubform) {
+    for (const CXFA_Node* pBreakNode = pRootSubform->GetFirstChild();
+         pBreakNode; pBreakNode = pBreakNode->GetNextSibling()) {
+      XFA_Element eType = pBreakNode->GetElementType();
+      if (eType == XFA_Element::BreakBefore ||
+          (eType == XFA_Element::Break &&
+           pBreakNode->JSObject()->GetEnum(XFA_Attribute::Before) !=
+               XFA_AttributeValue::Auto)) {
+        bProBreakBefore = true;
+        pBreakBeforeNode = pBreakNode;
+        break;
+      }
+    }
+    if (bProBreakBefore)
+      break;
+
+    bProBreakBefore = true;
+    pRootSubform =
+        pRootSubform->GetFirstChildByClass<CXFA_Subform>(XFA_Element::Subform);
+    while (pRootSubform && !pRootSubform->PresenceRequiresSpace()) {
+      pRootSubform = pRootSubform->GetNextSameClassSibling<CXFA_Subform>(
+          XFA_Element::Subform);
+    }
+  }
+  if (pBreakBeforeNode) {
+    BreakData ret = ExecuteBreakBeforeOrAfter(pBreakBeforeNode, true);
+    if (ret.bCreatePage) {
+      ResetToFirstViewRecord();
+      return true;
+    }
+  }
+  return AppendNewPage(true);
+}
+
+bool CXFA_ViewLayoutProcessor::AppendNewPage(bool bFirstTemPage) {
+  if (m_CurrentViewRecordIter != GetTailPosition())
+    return true;
+
+  CXFA_Node* pPageNode = GetNextAvailPageArea(nullptr, nullptr, false, false);
+  if (!pPageNode)
+    return false;
+
+  if (bFirstTemPage && !HasCurrentViewRecord())
+    ResetToFirstViewRecord();
+  return !bFirstTemPage || HasCurrentViewRecord();
+}
+
+void CXFA_ViewLayoutProcessor::RemoveLayoutRecord(
+    CXFA_ViewRecord* pNewRecord,
+    CXFA_ViewRecord* pPrevRecord) {
+  if (!pNewRecord || !pPrevRecord)
+    return;
+  if (pNewRecord->pCurPageSet != pPrevRecord->pCurPageSet) {
+    pNewRecord->pCurPageSet->RemoveSelfIfParented();
+    return;
+  }
+  if (pNewRecord->pCurPageArea != pPrevRecord->pCurPageArea) {
+    pNewRecord->pCurPageArea->RemoveSelfIfParented();
+    return;
+  }
+  if (pNewRecord->pCurContentArea != pPrevRecord->pCurContentArea) {
+    pNewRecord->pCurContentArea->RemoveSelfIfParented();
+    return;
+  }
+}
+
+void CXFA_ViewLayoutProcessor::ReorderPendingLayoutRecordToTail(
+    CXFA_ViewRecord* pNewRecord,
+    CXFA_ViewRecord* pPrevRecord) {
+  if (!pNewRecord || !pPrevRecord)
+    return;
+  if (pNewRecord->pCurPageSet != pPrevRecord->pCurPageSet) {
+    ReorderLayoutItemToTail(pNewRecord->pCurPageSet);
+    return;
+  }
+  if (pNewRecord->pCurPageArea != pPrevRecord->pCurPageArea) {
+    ReorderLayoutItemToTail(pNewRecord->pCurPageArea);
+    return;
+  }
+  if (pNewRecord->pCurContentArea != pPrevRecord->pCurContentArea) {
+    ReorderLayoutItemToTail(pNewRecord->pCurContentArea);
+    return;
+  }
+}
+
+void CXFA_ViewLayoutProcessor::SubmitContentItem(
+    const RetainPtr<CXFA_ContentLayoutItem>& pContentLayoutItem,
+    CXFA_ContentLayoutProcessor::Result eStatus) {
+  if (pContentLayoutItem) {
+    if (!HasCurrentViewRecord())
+      return;
+
+    GetCurrentViewRecord()->pCurContentArea->AppendLastChild(
+        pContentLayoutItem);
+    m_bCreateOverFlowPage = false;
+  }
+
+  if (eStatus != CXFA_ContentLayoutProcessor::Result::kDone) {
+    if (eStatus == CXFA_ContentLayoutProcessor::Result::kPageFullBreak &&
+        m_CurrentViewRecordIter == GetTailPosition()) {
+      AppendNewPage(false);
+    }
+    m_CurrentViewRecordIter = GetTailPosition();
+    m_pCurPageArea = GetCurrentViewRecord()->pCurPageArea->GetFormNode();
+  }
+}
+
+float CXFA_ViewLayoutProcessor::GetAvailHeight() {
+  if (!HasCurrentViewRecord())
+    return 0.0f;
+
+  RetainPtr<CXFA_ViewLayoutItem> pLayoutItem =
+      GetCurrentViewRecord()->pCurContentArea;
+  if (!pLayoutItem || !pLayoutItem->GetFormNode())
+    return 0.0f;
+
+  float fAvailHeight = pLayoutItem->GetFormNode()->JSObject()->GetMeasureInUnit(
+      XFA_Attribute::H, XFA_Unit::Pt);
+  if (fAvailHeight >= kXFALayoutPrecision)
+    return fAvailHeight;
+  if (m_CurrentViewRecordIter == m_ProposedViewRecords.begin())
+    return 0.0f;
+  return FLT_MAX;
+}
+
+CXFA_ViewLayoutProcessor::CXFA_ViewRecord*
+CXFA_ViewLayoutProcessor::AppendNewRecord(
+    std::unique_ptr<CXFA_ViewRecord> pNewRecord) {
+  m_ProposedViewRecords.push_back(std::move(pNewRecord));
+  return m_ProposedViewRecords.back().get();
+}
+
+CXFA_ViewLayoutProcessor::CXFA_ViewRecord*
+CXFA_ViewLayoutProcessor::CreateViewRecord(CXFA_Node* pPageNode,
+                                           bool bCreateNew) {
+  ASSERT(pPageNode);
+  auto pNewRecord = pdfium::MakeUnique<CXFA_ViewRecord>();
+  if (!HasCurrentViewRecord()) {
+    CXFA_Node* pPageSet = pPageNode->GetParent();
+    if (pPageSet == m_pPageSetNode) {
+      pNewRecord->pCurPageSet = m_pPageSetRootLayoutItem;
+    } else {
+      auto pPageSetLayoutItem =
+          pdfium::MakeRetain<CXFA_ViewLayoutItem>(pPageSet, nullptr);
+      pPageSet->JSObject()->SetLayoutItem(pPageSetLayoutItem.Get());
+      m_pPageSetRootLayoutItem->AppendLastChild(pPageSetLayoutItem);
+      pNewRecord->pCurPageSet = std::move(pPageSetLayoutItem);
+    }
+    return AppendNewRecord(std::move(pNewRecord));
+  }
+
+  if (!IsPageSetRootOrderedOccurrence()) {
+    *pNewRecord = *GetCurrentViewRecord();
+    return AppendNewRecord(std::move(pNewRecord));
+  }
+
+  CXFA_Node* pPageSet = pPageNode->GetParent();
+  if (!bCreateNew) {
+    if (pPageSet == m_pPageSetNode) {
+      pNewRecord->pCurPageSet = m_pPageSetCurLayoutItem;
+    } else {
+      RetainPtr<CXFA_ViewLayoutItem> pParentLayoutItem(
+          ToViewLayoutItem(pPageSet->JSObject()->GetLayoutItem()));
+      if (!pParentLayoutItem)
+        pParentLayoutItem = m_pPageSetCurLayoutItem;
+
+      pNewRecord->pCurPageSet = pParentLayoutItem;
+    }
+    return AppendNewRecord(std::move(pNewRecord));
+  }
+
+  CXFA_ViewLayoutItem* pParentPageSetLayout = nullptr;
+  if (pPageSet == GetCurrentViewRecord()->pCurPageSet->GetFormNode()) {
+    pParentPageSetLayout =
+        ToViewLayoutItem(GetCurrentViewRecord()->pCurPageSet->GetParent());
+  } else {
+    pParentPageSetLayout =
+        ToViewLayoutItem(pPageSet->GetParent()->JSObject()->GetLayoutItem());
+  }
+  auto pPageSetLayoutItem =
+      pdfium::MakeRetain<CXFA_ViewLayoutItem>(pPageSet, nullptr);
+  pPageSet->JSObject()->SetLayoutItem(pPageSetLayoutItem.Get());
+  if (!pParentPageSetLayout) {
+    RetainPtr<CXFA_ViewLayoutItem> pPrePageSet(m_pPageSetRootLayoutItem);
+    while (pPrePageSet->GetNextSibling()) {
+      pPrePageSet.Reset(pPrePageSet->GetNextSibling()->AsViewLayoutItem());
+    }
+    if (pPrePageSet->GetParent()) {
+      pPrePageSet->GetParent()->InsertAfter(pPageSetLayoutItem,
+                                            pPrePageSet.Get());
+    }
+    m_pPageSetCurLayoutItem = pPageSetLayoutItem;
+  } else {
+    pParentPageSetLayout->AppendLastChild(pPageSetLayoutItem);
+  }
+  pNewRecord->pCurPageSet = pPageSetLayoutItem;
+  return AppendNewRecord(std::move(pNewRecord));
+}
+
+CXFA_ViewLayoutProcessor::CXFA_ViewRecord*
+CXFA_ViewLayoutProcessor::CreateViewRecordSimple() {
+  auto pNewRecord = pdfium::MakeUnique<CXFA_ViewRecord>();
+  if (HasCurrentViewRecord())
+    *pNewRecord = *GetCurrentViewRecord();
+  else
+    pNewRecord->pCurPageSet = m_pPageSetRootLayoutItem;
+  return AppendNewRecord(std::move(pNewRecord));
+}
+
+void CXFA_ViewLayoutProcessor::AddPageAreaLayoutItem(
+    CXFA_ViewRecord* pNewRecord,
+    CXFA_Node* pNewPageArea) {
+  RetainPtr<CXFA_ViewLayoutItem> pNewPageAreaLayoutItem;
+  if (pdfium::IndexInBounds(m_PageArray, m_nAvailPages)) {
+    RetainPtr<CXFA_ViewLayoutItem> pViewItem = m_PageArray[m_nAvailPages];
+    pViewItem->SetFormNode(pNewPageArea);
+    m_nAvailPages++;
+    pNewPageAreaLayoutItem = std::move(pViewItem);
+  } else {
+    CXFA_FFNotify* pNotify = pNewPageArea->GetDocument()->GetNotify();
+    auto pViewItem = pdfium::MakeRetain<CXFA_ViewLayoutItem>(
+        pNewPageArea, pNotify->OnCreateViewLayoutItem(pNewPageArea));
+    m_PageArray.push_back(pViewItem);
+    m_nAvailPages++;
+    pNotify->OnPageEvent(pViewItem.Get(), XFA_PAGEVIEWEVENT_PostRemoved);
+    pNewPageAreaLayoutItem = pViewItem;
+  }
+  pNewRecord->pCurPageSet->AppendLastChild(pNewPageAreaLayoutItem);
+  pNewRecord->pCurPageArea = pNewPageAreaLayoutItem;
+  pNewRecord->pCurContentArea = nullptr;
+}
+
+void CXFA_ViewLayoutProcessor::AddContentAreaLayoutItem(
+    CXFA_ViewRecord* pNewRecord,
+    CXFA_Node* pContentArea) {
+  if (!pContentArea) {
+    pNewRecord->pCurContentArea = nullptr;
+    return;
+  }
+  auto pNewViewLayoutItem =
+      pdfium::MakeRetain<CXFA_ViewLayoutItem>(pContentArea, nullptr);
+  pNewRecord->pCurPageArea->AppendLastChild(pNewViewLayoutItem);
+  pNewRecord->pCurContentArea = std::move(pNewViewLayoutItem);
+}
+
+void CXFA_ViewLayoutProcessor::FinishPaginatedPageSets() {
+  for (CXFA_ViewLayoutItem* pRootPageSetLayoutItem =
+           m_pPageSetRootLayoutItem.Get();
+       pRootPageSetLayoutItem; pRootPageSetLayoutItem = ToViewLayoutItem(
+                                   pRootPageSetLayoutItem->GetNextSibling())) {
+    PageSetIterator sIterator(pRootPageSetLayoutItem);
+    for (CXFA_ViewLayoutItem* pPageSetLayoutItem = sIterator.GetCurrent();
+         pPageSetLayoutItem; pPageSetLayoutItem = sIterator.MoveToNext()) {
+      XFA_AttributeValue ePageRelation =
+          pPageSetLayoutItem->GetFormNode()->JSObject()->GetEnum(
+              XFA_Attribute::Relation);
+      switch (ePageRelation) {
+        case XFA_AttributeValue::SimplexPaginated:
+        case XFA_AttributeValue::DuplexPaginated:
+          ProcessSimplexOrDuplexPageSets(
+              pPageSetLayoutItem,
+              ePageRelation == XFA_AttributeValue::SimplexPaginated);
+          break;
+        default:
+          ProcessLastPageSet();
+          break;
+      }
+    }
+  }
+}
+
+int32_t CXFA_ViewLayoutProcessor::GetPageCount() const {
+  return pdfium::CollectionSize<int32_t>(m_PageArray);
+}
+
+CXFA_ViewLayoutItem* CXFA_ViewLayoutProcessor::GetPage(int32_t index) const {
+  if (!pdfium::IndexInBounds(m_PageArray, index))
+    return nullptr;
+  return m_PageArray[index].Get();
+}
+
+int32_t CXFA_ViewLayoutProcessor::GetPageIndex(
+    const CXFA_ViewLayoutItem* pPage) const {
+  auto it = std::find(m_PageArray.begin(), m_PageArray.end(), pPage);
+  return it != m_PageArray.end() ? it - m_PageArray.begin() : -1;
+}
+
+bool CXFA_ViewLayoutProcessor::RunBreak(XFA_Element eBreakType,
+                                        XFA_AttributeValue eTargetType,
+                                        CXFA_Node* pTarget,
+                                        bool bStartNew) {
+  bool bRet = false;
+  switch (eTargetType) {
+    case XFA_AttributeValue::ContentArea:
+      if (pTarget && pTarget->GetElementType() != XFA_Element::ContentArea)
+        pTarget = nullptr;
+      if (ShouldGetNextPageArea(pTarget, bStartNew)) {
+        CXFA_Node* pPageArea = nullptr;
+        if (pTarget)
+          pPageArea = pTarget->GetParent();
+
+        pPageArea = GetNextAvailPageArea(pPageArea, pTarget, false, false);
+        bRet = !!pPageArea;
+      }
+      break;
+    case XFA_AttributeValue::PageArea:
+      if (pTarget && pTarget->GetElementType() != XFA_Element::PageArea)
+        pTarget = nullptr;
+      if (ShouldGetNextPageArea(pTarget, bStartNew)) {
+        CXFA_Node* pPageArea =
+            GetNextAvailPageArea(pTarget, nullptr, true, false);
+        bRet = !!pPageArea;
+      }
+      break;
+    case XFA_AttributeValue::PageOdd:
+      if (pTarget && pTarget->GetElementType() != XFA_Element::PageArea)
+        pTarget = nullptr;
+      break;
+    case XFA_AttributeValue::PageEven:
+      if (pTarget && pTarget->GetElementType() != XFA_Element::PageArea)
+        pTarget = nullptr;
+      break;
+    case XFA_AttributeValue::Auto:
+    default:
+      break;
+  }
+  return bRet;
+}
+
+bool CXFA_ViewLayoutProcessor::ShouldGetNextPageArea(CXFA_Node* pTarget,
+                                                     bool bStartNew) const {
+  return bStartNew || !pTarget || !HasCurrentViewRecord() ||
+         pTarget != GetCurrentViewRecord()->pCurPageArea->GetFormNode();
+}
+
+CXFA_ViewLayoutProcessor::BreakData
+CXFA_ViewLayoutProcessor::ExecuteBreakBeforeOrAfter(const CXFA_Node* pCurNode,
+                                                    bool bBefore) {
+  BreakData ret = {nullptr, nullptr, false};
+  XFA_Element eType = pCurNode->GetElementType();
+  switch (eType) {
+    case XFA_Element::BreakBefore:
+    case XFA_Element::BreakAfter: {
+      WideString wsBreakLeader;
+      WideString wsBreakTrailer;
+      CXFA_Node* pFormNode = pCurNode->GetContainerParent();
+      CXFA_Node* pContainer = pFormNode->GetTemplateNodeIfExists();
+      bool bStartNew =
+          pCurNode->JSObject()->GetInteger(XFA_Attribute::StartNew) != 0;
+      CXFA_Script* pScript =
+          pCurNode->GetFirstChildByClass<CXFA_Script>(XFA_Element::Script);
+      if (pScript && !RunBreakTestScript(pScript))
+        break;
+
+      WideString wsTarget =
+          pCurNode->JSObject()->GetCData(XFA_Attribute::Target);
+      CXFA_Node* pTarget = ResolveBreakTarget(m_pPageSetNode, true, &wsTarget);
+      wsBreakTrailer = pCurNode->JSObject()->GetCData(XFA_Attribute::Trailer);
+      wsBreakLeader = pCurNode->JSObject()->GetCData(XFA_Attribute::Leader);
+      ret.pLeader = ResolveBreakTarget(pContainer, true, &wsBreakLeader);
+      ret.pTrailer = ResolveBreakTarget(pContainer, true, &wsBreakTrailer);
+      if (RunBreak(eType,
+                   pCurNode->JSObject()->GetEnum(XFA_Attribute::TargetType),
+                   pTarget, bStartNew)) {
+        ret.bCreatePage = true;
+        break;
+      }
+      if (!m_ProposedViewRecords.empty() &&
+          m_CurrentViewRecordIter == m_ProposedViewRecords.begin() &&
+          eType == XFA_Element::BreakBefore) {
+        CXFA_Node* pParentNode = pFormNode->GetContainerParent();
+        if (!pParentNode ||
+            pFormNode != pParentNode->GetFirstContainerChild()) {
+          break;
+        }
+        pParentNode = pParentNode->GetParent();
+        if (!pParentNode ||
+            pParentNode->GetElementType() != XFA_Element::Form) {
+          break;
+        }
+        ret.bCreatePage = true;
+      }
+      break;
+    }
+    case XFA_Element::Break: {
+      bool bStartNew =
+          pCurNode->JSObject()->GetInteger(XFA_Attribute::StartNew) != 0;
+      WideString wsTarget = pCurNode->JSObject()->GetCData(
+          bBefore ? XFA_Attribute::BeforeTarget : XFA_Attribute::AfterTarget);
+      CXFA_Node* pTarget = ResolveBreakTarget(m_pPageSetNode, true, &wsTarget);
+      if (RunBreak(bBefore ? XFA_Element::BreakBefore : XFA_Element::BreakAfter,
+                   pCurNode->JSObject()->GetEnum(
+                       bBefore ? XFA_Attribute::Before : XFA_Attribute::After),
+                   pTarget, bStartNew)) {
+        ret.bCreatePage = true;
+      }
+      break;
+    }
+    default:
+      break;
+  }
+  return ret;
+}
+
+Optional<CXFA_ViewLayoutProcessor::BreakData>
+CXFA_ViewLayoutProcessor::ProcessBreakBefore(const CXFA_Node* pBreakNode) {
+  return ProcessBreakBeforeOrAfter(pBreakNode, /*before=*/true);
+}
+
+Optional<CXFA_ViewLayoutProcessor::BreakData>
+CXFA_ViewLayoutProcessor::ProcessBreakAfter(const CXFA_Node* pBreakNode) {
+  return ProcessBreakBeforeOrAfter(pBreakNode, /*before=*/false);
+}
+
+Optional<CXFA_ViewLayoutProcessor::BreakData>
+CXFA_ViewLayoutProcessor::ProcessBreakBeforeOrAfter(const CXFA_Node* pBreakNode,
+                                                    bool bBefore) {
+  CXFA_Node* pFormNode = pBreakNode->GetContainerParent();
+  if (!pFormNode->PresenceRequiresSpace())
+    return pdfium::nullopt;
+
+  BreakData break_data = ExecuteBreakBeforeOrAfter(pBreakNode, bBefore);
+  CXFA_Document* pDocument = pBreakNode->GetDocument();
+  CXFA_Node* pDataScope = nullptr;
+  pFormNode = pFormNode->GetContainerParent();
+  if (break_data.pLeader) {
+    if (!break_data.pLeader->IsContainerNode())
+      return pdfium::nullopt;
+
+    pDataScope = XFA_DataMerge_FindDataScope(pFormNode);
+    break_data.pLeader = pDocument->DataMerge_CopyContainer(
+        break_data.pLeader, pFormNode, pDataScope, true, true, true);
+    if (!break_data.pLeader)
+      return pdfium::nullopt;
+
+    pDocument->DataMerge_UpdateBindingRelations(break_data.pLeader);
+    SetLayoutGeneratedNodeFlag(break_data.pLeader);
+  }
+  if (break_data.pTrailer) {
+    if (!break_data.pTrailer->IsContainerNode())
+      return pdfium::nullopt;
+
+    if (!pDataScope)
+      pDataScope = XFA_DataMerge_FindDataScope(pFormNode);
+
+    break_data.pTrailer = pDocument->DataMerge_CopyContainer(
+        break_data.pTrailer, pFormNode, pDataScope, true, true, true);
+    if (!break_data.pTrailer)
+      return pdfium::nullopt;
+
+    pDocument->DataMerge_UpdateBindingRelations(break_data.pTrailer);
+    SetLayoutGeneratedNodeFlag(break_data.pTrailer);
+  }
+  return break_data;
+}
+
+CXFA_Node* CXFA_ViewLayoutProcessor::ProcessBookendLeader(
+    const CXFA_Node* pBookendNode) {
+  return ProcessBookendLeaderOrTrailer(pBookendNode, /*leader=*/true);
+}
+
+CXFA_Node* CXFA_ViewLayoutProcessor::ProcessBookendTrailer(
+    const CXFA_Node* pBookendNode) {
+  return ProcessBookendLeaderOrTrailer(pBookendNode, /*leader=*/false);
+}
+
+CXFA_Node* CXFA_ViewLayoutProcessor::ProcessBookendLeaderOrTrailer(
+    const CXFA_Node* pBookendNode,
+    bool bLeader) {
+  CXFA_Node* pFormNode = pBookendNode->GetContainerParent();
+  CXFA_Node* pLeaderTemplate =
+      ResolveBookendLeaderOrTrailer(pBookendNode, bLeader);
+  if (!pLeaderTemplate)
+    return nullptr;
+
+  CXFA_Document* pDocument = pBookendNode->GetDocument();
+  CXFA_Node* pDataScope = XFA_DataMerge_FindDataScope(pFormNode);
+  CXFA_Node* pBookendAppendNode = pDocument->DataMerge_CopyContainer(
+      pLeaderTemplate, pFormNode, pDataScope, true, true, true);
+  if (!pBookendAppendNode)
+    return nullptr;
+
+  pDocument->DataMerge_UpdateBindingRelations(pBookendAppendNode);
+  SetLayoutGeneratedNodeFlag(pBookendAppendNode);
+  return pBookendAppendNode;
+}
+
+bool CXFA_ViewLayoutProcessor::BreakOverflow(const CXFA_Node* pOverflowNode,
+                                             bool bCreatePage,
+                                             CXFA_Node** pLeaderTemplate,
+                                             CXFA_Node** pTrailerTemplate) {
+  CXFA_Node* pContainer =
+      pOverflowNode->GetContainerParent()->GetTemplateNodeIfExists();
+  if (pOverflowNode->GetElementType() == XFA_Element::Break) {
+    WideString wsOverflowLeader =
+        pOverflowNode->JSObject()->GetCData(XFA_Attribute::OverflowLeader);
+    WideString wsOverflowTarget =
+        pOverflowNode->JSObject()->GetCData(XFA_Attribute::OverflowTarget);
+    WideString wsOverflowTrailer =
+        pOverflowNode->JSObject()->GetCData(XFA_Attribute::OverflowTrailer);
+    if (wsOverflowTarget.IsEmpty() && wsOverflowLeader.IsEmpty() &&
+        wsOverflowTrailer.IsEmpty()) {
+      return false;
+    }
+
+    if (!wsOverflowTarget.IsEmpty() && bCreatePage && !m_bCreateOverFlowPage) {
+      CXFA_Node* pTarget =
+          ResolveBreakTarget(m_pPageSetNode, true, &wsOverflowTarget);
+      if (pTarget) {
+        m_bCreateOverFlowPage = true;
+        switch (pTarget->GetElementType()) {
+          case XFA_Element::PageArea:
+            RunBreak(XFA_Element::Overflow, XFA_AttributeValue::PageArea,
+                     pTarget, true);
+            break;
+          case XFA_Element::ContentArea:
+            RunBreak(XFA_Element::Overflow, XFA_AttributeValue::ContentArea,
+                     pTarget, true);
+            break;
+          default:
+            break;
+        }
+      }
+    }
+    if (!bCreatePage) {
+      *pLeaderTemplate =
+          ResolveBreakTarget(pContainer, true, &wsOverflowLeader);
+      *pTrailerTemplate =
+          ResolveBreakTarget(pContainer, true, &wsOverflowTrailer);
+    }
+    return true;
+  }
+
+  if (pOverflowNode->GetElementType() != XFA_Element::Overflow)
+    return false;
+
+  WideString wsOverflowTarget =
+      pOverflowNode->JSObject()->GetCData(XFA_Attribute::Target);
+  if (!wsOverflowTarget.IsEmpty() && bCreatePage && !m_bCreateOverFlowPage) {
+    CXFA_Node* pTarget =
+        ResolveBreakTarget(m_pPageSetNode, true, &wsOverflowTarget);
+    if (pTarget) {
+      m_bCreateOverFlowPage = true;
+      switch (pTarget->GetElementType()) {
+        case XFA_Element::PageArea:
+          RunBreak(XFA_Element::Overflow, XFA_AttributeValue::PageArea, pTarget,
+                   true);
+          break;
+        case XFA_Element::ContentArea:
+          RunBreak(XFA_Element::Overflow, XFA_AttributeValue::ContentArea,
+                   pTarget, true);
+          break;
+        default:
+          break;
+      }
+    }
+  }
+  if (!bCreatePage) {
+    WideString wsLeader =
+        pOverflowNode->JSObject()->GetCData(XFA_Attribute::Leader);
+    WideString wsTrailer =
+        pOverflowNode->JSObject()->GetCData(XFA_Attribute::Trailer);
+    *pLeaderTemplate = ResolveBreakTarget(pContainer, true, &wsLeader);
+    *pTrailerTemplate = ResolveBreakTarget(pContainer, true, &wsTrailer);
+  }
+  return true;
+}
+
+Optional<CXFA_ViewLayoutProcessor::OverflowData>
+CXFA_ViewLayoutProcessor::ProcessOverflow(CXFA_Node* pFormNode,
+                                          bool bCreatePage) {
+  if (!pFormNode)
+    return pdfium::nullopt;
+
+  CXFA_Node* pLeaderTemplate = nullptr;
+  CXFA_Node* pTrailerTemplate = nullptr;
+  bool bIsOverflowNode = pFormNode->GetElementType() == XFA_Element::Overflow ||
+                         pFormNode->GetElementType() == XFA_Element::Break;
+  OverflowData overflow_data{nullptr, nullptr};
+  for (CXFA_Node* pCurNode = bIsOverflowNode ? pFormNode
+                                             : pFormNode->GetFirstChild();
+       pCurNode; pCurNode = pCurNode->GetNextSibling()) {
+    if (BreakOverflow(pCurNode, bCreatePage, &pLeaderTemplate,
+                      &pTrailerTemplate)) {
+      if (bIsOverflowNode)
+        pFormNode = pCurNode->GetParent();
+
+      CXFA_Document* pDocument = pCurNode->GetDocument();
+      CXFA_Node* pDataScope = nullptr;
+      if (pLeaderTemplate) {
+        pDataScope = XFA_DataMerge_FindDataScope(pFormNode);
+
+        overflow_data.pLeader = pDocument->DataMerge_CopyContainer(
+            pLeaderTemplate, pFormNode, pDataScope, true, true, true);
+        if (!overflow_data.pLeader)
+          return pdfium::nullopt;
+
+        pDocument->DataMerge_UpdateBindingRelations(overflow_data.pLeader);
+        SetLayoutGeneratedNodeFlag(overflow_data.pLeader);
+      }
+      if (pTrailerTemplate) {
+        if (!pDataScope)
+          pDataScope = XFA_DataMerge_FindDataScope(pFormNode);
+
+        overflow_data.pTrailer = pDocument->DataMerge_CopyContainer(
+            pTrailerTemplate, pFormNode, pDataScope, true, true, true);
+        if (!overflow_data.pTrailer)
+          return pdfium::nullopt;
+
+        pDocument->DataMerge_UpdateBindingRelations(overflow_data.pTrailer);
+        SetLayoutGeneratedNodeFlag(overflow_data.pTrailer);
+      }
+      return overflow_data;
+    }
+    if (bIsOverflowNode)
+      break;
+  }
+  return pdfium::nullopt;
+}
+
+CXFA_Node* CXFA_ViewLayoutProcessor::ResolveBookendLeaderOrTrailer(
+    const CXFA_Node* pBookendNode,
+    bool bLeader) {
+  CXFA_Node* pContainer =
+      pBookendNode->GetContainerParent()->GetTemplateNodeIfExists();
+  if (pBookendNode->GetElementType() == XFA_Element::Break) {
+    WideString leader = pBookendNode->JSObject()->GetCData(
+        bLeader ? XFA_Attribute::BookendLeader : XFA_Attribute::BookendTrailer);
+    if (leader.IsEmpty())
+      return nullptr;
+    return ResolveBreakTarget(pContainer, false, &leader);
+  }
+
+  if (pBookendNode->GetElementType() != XFA_Element::Bookend)
+    return nullptr;
+
+  WideString leader = pBookendNode->JSObject()->GetCData(
+      bLeader ? XFA_Attribute::Leader : XFA_Attribute::Trailer);
+  return ResolveBreakTarget(pContainer, true, &leader);
+}
+
+bool CXFA_ViewLayoutProcessor::FindPageAreaFromPageSet(
+    CXFA_Node* pPageSet,
+    CXFA_Node* pStartChild,
+    CXFA_Node* pTargetPageArea,
+    CXFA_Node* pTargetContentArea,
+    bool bNewPage,
+    bool bQuery) {
+  if (!pPageSet && !pStartChild)
+    return false;
+
+  if (IsPageSetRootOrderedOccurrence()) {
+    return FindPageAreaFromPageSet_Ordered(pPageSet, pStartChild,
+                                           pTargetPageArea, pTargetContentArea,
+                                           bNewPage, bQuery);
+  }
+  XFA_AttributeValue ePreferredPosition = HasCurrentViewRecord()
+                                              ? XFA_AttributeValue::Rest
+                                              : XFA_AttributeValue::First;
+  return FindPageAreaFromPageSet_SimplexDuplex(
+      pPageSet, pStartChild, pTargetPageArea, pTargetContentArea, bNewPage,
+      bQuery, ePreferredPosition);
+}
+
+bool CXFA_ViewLayoutProcessor::FindPageAreaFromPageSet_Ordered(
+    CXFA_Node* pPageSet,
+    CXFA_Node* pStartChild,
+    CXFA_Node* pTargetPageArea,
+    CXFA_Node* pTargetContentArea,
+    bool bNewPage,
+    bool bQuery) {
+  int32_t iPageSetCount = 0;
+  if (!pStartChild && !bQuery) {
+    auto it = m_pPageSetMap.find(pPageSet);
+    if (it != m_pPageSetMap.end())
+      iPageSetCount = it->second;
+    int32_t iMax = -1;
+    CXFA_Node* pOccurNode =
+        pPageSet->GetFirstChildByClass<CXFA_Occur>(XFA_Element::Occur);
+    if (pOccurNode) {
+      Optional<int32_t> ret =
+          pOccurNode->JSObject()->TryInteger(XFA_Attribute::Max, false);
+      if (ret)
+        iMax = *ret;
+    }
+    if (iMax >= 0 && iMax <= iPageSetCount)
+      return false;
+  }
+
+  bool bRes = false;
+  CXFA_Node* pCurrentNode =
+      pStartChild ? pStartChild->GetNextSibling() : pPageSet->GetFirstChild();
+  for (; pCurrentNode; pCurrentNode = pCurrentNode->GetNextSibling()) {
+    if (pCurrentNode->GetElementType() == XFA_Element::PageArea) {
+      if ((pTargetPageArea == pCurrentNode || !pTargetPageArea)) {
+        if (!pCurrentNode->GetFirstChildByClass<CXFA_ContentArea>(
+                XFA_Element::ContentArea)) {
+          if (pTargetPageArea == pCurrentNode) {
+            CreateMinPageRecord(pCurrentNode, true, false);
+            pTargetPageArea = nullptr;
+          }
+          continue;
+        }
+        if (!bQuery) {
+          CXFA_ViewRecord* pNewRecord =
+              CreateViewRecord(pCurrentNode, !pStartChild);
+          AddPageAreaLayoutItem(pNewRecord, pCurrentNode);
+          if (!pTargetContentArea) {
+            pTargetContentArea =
+                pCurrentNode->GetFirstChildByClass<CXFA_ContentArea>(
+                    XFA_Element::ContentArea);
+          }
+          AddContentAreaLayoutItem(pNewRecord, pTargetContentArea);
+        }
+        m_pCurPageArea = pCurrentNode;
+        m_nCurPageCount = 1;
+        bRes = true;
+        break;
+      }
+      if (!bQuery)
+        CreateMinPageRecord(pCurrentNode, false, false);
+    } else if (pCurrentNode->GetElementType() == XFA_Element::PageSet) {
+      if (FindPageAreaFromPageSet_Ordered(pCurrentNode, nullptr,
+                                          pTargetPageArea, pTargetContentArea,
+                                          bNewPage, bQuery)) {
+        bRes = true;
+        break;
+      }
+      if (!bQuery)
+        CreateMinPageSetRecord(pCurrentNode, true);
+    }
+  }
+  if (!pStartChild && bRes && !bQuery)
+    m_pPageSetMap[pPageSet] = ++iPageSetCount;
+  return bRes;
+}
+
+bool CXFA_ViewLayoutProcessor::FindPageAreaFromPageSet_SimplexDuplex(
+    CXFA_Node* pPageSet,
+    CXFA_Node* pStartChild,
+    CXFA_Node* pTargetPageArea,
+    CXFA_Node* pTargetContentArea,
+    bool bNewPage,
+    bool bQuery,
+    XFA_AttributeValue ePreferredPosition) {
+  const XFA_AttributeValue eFallbackPosition = XFA_AttributeValue::Any;
+  CXFA_Node* pPreferredPageArea = nullptr;
+  CXFA_Node* pFallbackPageArea = nullptr;
+  CXFA_Node* pCurrentNode = nullptr;
+  if (!pStartChild || pStartChild->GetElementType() == XFA_Element::PageArea)
+    pCurrentNode = pPageSet->GetFirstChild();
+  else
+    pCurrentNode = pStartChild->GetNextSibling();
+
+  for (; pCurrentNode; pCurrentNode = pCurrentNode->GetNextSibling()) {
+    if (pCurrentNode->GetElementType() == XFA_Element::PageArea) {
+      if (!MatchPageAreaOddOrEven(pCurrentNode))
+        continue;
+
+      XFA_AttributeValue eCurPagePosition =
+          pCurrentNode->JSObject()->GetEnum(XFA_Attribute::PagePosition);
+      if (ePreferredPosition == XFA_AttributeValue::Last) {
+        if (eCurPagePosition != ePreferredPosition)
+          continue;
+        if (m_ePageSetMode == XFA_AttributeValue::SimplexPaginated ||
+            pCurrentNode->JSObject()->GetEnum(XFA_Attribute::OddOrEven) ==
+                XFA_AttributeValue::Any) {
+          pPreferredPageArea = pCurrentNode;
+          break;
+        }
+        CXFA_ViewRecord* pNewRecord = CreateViewRecordSimple();
+        AddPageAreaLayoutItem(pNewRecord, pCurrentNode);
+        AddContentAreaLayoutItem(
+            pNewRecord, pCurrentNode->GetFirstChildByClass<CXFA_ContentArea>(
+                            XFA_Element::ContentArea));
+        return false;
+      }
+      if (ePreferredPosition == XFA_AttributeValue::Only) {
+        if (eCurPagePosition != ePreferredPosition)
+          continue;
+        if (m_ePageSetMode != XFA_AttributeValue::DuplexPaginated ||
+            pCurrentNode->JSObject()->GetEnum(XFA_Attribute::OddOrEven) ==
+                XFA_AttributeValue::Any) {
+          pPreferredPageArea = pCurrentNode;
+          break;
+        }
+        return false;
+      }
+      if ((pTargetPageArea == pCurrentNode || !pTargetPageArea)) {
+        if (!pCurrentNode->GetFirstChildByClass<CXFA_ContentArea>(
+                XFA_Element::ContentArea)) {
+          if (pTargetPageArea == pCurrentNode) {
+            CXFA_ViewRecord* pNewRecord = CreateViewRecordSimple();
+            AddPageAreaLayoutItem(pNewRecord, pCurrentNode);
+            pTargetPageArea = nullptr;
+          }
+          continue;
+        }
+        if ((ePreferredPosition == XFA_AttributeValue::Rest &&
+             eCurPagePosition == XFA_AttributeValue::Any) ||
+            eCurPagePosition == ePreferredPosition) {
+          pPreferredPageArea = pCurrentNode;
+          break;
+        }
+        if (eCurPagePosition == eFallbackPosition && !pFallbackPageArea) {
+          pFallbackPageArea = pCurrentNode;
+        }
+      } else if (pTargetPageArea && !MatchPageAreaOddOrEven(pTargetPageArea)) {
+        CXFA_ViewRecord* pNewRecord = CreateViewRecordSimple();
+        AddPageAreaLayoutItem(pNewRecord, pCurrentNode);
+        AddContentAreaLayoutItem(
+            pNewRecord, pCurrentNode->GetFirstChildByClass<CXFA_ContentArea>(
+                            XFA_Element::ContentArea));
+      }
+    } else if (pCurrentNode->GetElementType() == XFA_Element::PageSet) {
+      if (FindPageAreaFromPageSet_SimplexDuplex(
+              pCurrentNode, nullptr, pTargetPageArea, pTargetContentArea,
+              bNewPage, bQuery, ePreferredPosition)) {
+        break;
+      }
+    }
+  }
+
+  CXFA_Node* pCurPageArea = nullptr;
+  if (pPreferredPageArea)
+    pCurPageArea = pPreferredPageArea;
+  else if (pFallbackPageArea)
+    pCurPageArea = pFallbackPageArea;
+
+  if (!pCurPageArea)
+    return false;
+
+  if (!bQuery) {
+    CXFA_ViewRecord* pNewRecord = CreateViewRecordSimple();
+    AddPageAreaLayoutItem(pNewRecord, pCurPageArea);
+    if (!pTargetContentArea) {
+      pTargetContentArea = pCurPageArea->GetFirstChildByClass<CXFA_ContentArea>(
+          XFA_Element::ContentArea);
+    }
+    AddContentAreaLayoutItem(pNewRecord, pTargetContentArea);
+  }
+  m_pCurPageArea = pCurPageArea;
+  return true;
+}
+
+bool CXFA_ViewLayoutProcessor::MatchPageAreaOddOrEven(CXFA_Node* pPageArea) {
+  if (m_ePageSetMode != XFA_AttributeValue::DuplexPaginated)
+    return true;
+
+  Optional<XFA_AttributeValue> ret =
+      pPageArea->JSObject()->TryEnum(XFA_Attribute::OddOrEven, true);
+  if (!ret || *ret == XFA_AttributeValue::Any)
+    return true;
+
+  int32_t iPageLast = GetPageCount() % 2;
+  return *ret == XFA_AttributeValue::Odd ? iPageLast == 0 : iPageLast == 1;
+}
+
+CXFA_Node* CXFA_ViewLayoutProcessor::GetNextAvailPageArea(
+    CXFA_Node* pTargetPageArea,
+    CXFA_Node* pTargetContentArea,
+    bool bNewPage,
+    bool bQuery) {
+  if (!m_pCurPageArea) {
+    FindPageAreaFromPageSet(m_pPageSetNode, nullptr, pTargetPageArea,
+                            pTargetContentArea, bNewPage, bQuery);
+    return m_pCurPageArea;
+  }
+
+  if (!pTargetPageArea || pTargetPageArea == m_pCurPageArea) {
+    if (!bNewPage && GetNextContentArea(pTargetContentArea))
+      return m_pCurPageArea;
+
+    if (IsPageSetRootOrderedOccurrence()) {
+      int32_t iMax = -1;
+      CXFA_Node* pOccurNode =
+          m_pCurPageArea->GetFirstChildByClass<CXFA_Occur>(XFA_Element::Occur);
+      if (pOccurNode) {
+        Optional<int32_t> ret =
+            pOccurNode->JSObject()->TryInteger(XFA_Attribute::Max, false);
+        if (ret)
+          iMax = *ret;
+      }
+      if ((iMax < 0 || m_nCurPageCount < iMax)) {
+        if (!bQuery) {
+          CXFA_ViewRecord* pNewRecord = CreateViewRecord(m_pCurPageArea, false);
+          AddPageAreaLayoutItem(pNewRecord, m_pCurPageArea);
+          if (!pTargetContentArea) {
+            pTargetContentArea =
+                m_pCurPageArea->GetFirstChildByClass<CXFA_ContentArea>(
+                    XFA_Element::ContentArea);
+          }
+          AddContentAreaLayoutItem(pNewRecord, pTargetContentArea);
+        }
+        m_nCurPageCount++;
+        return m_pCurPageArea;
+      }
+    }
+  }
+
+  if (!bQuery && IsPageSetRootOrderedOccurrence())
+    CreateMinPageRecord(m_pCurPageArea, false, true);
+  if (FindPageAreaFromPageSet(m_pCurPageArea->GetParent(), m_pCurPageArea,
+                              pTargetPageArea, pTargetContentArea, bNewPage,
+                              bQuery)) {
+    return m_pCurPageArea;
+  }
+
+  CXFA_Node* pPageSet = m_pCurPageArea->GetParent();
+  while (pPageSet) {
+    if (FindPageAreaFromPageSet(pPageSet, nullptr, pTargetPageArea,
+                                pTargetContentArea, bNewPage, bQuery)) {
+      return m_pCurPageArea;
+    }
+    if (!bQuery && IsPageSetRootOrderedOccurrence())
+      CreateMinPageSetRecord(pPageSet, false);
+    if (FindPageAreaFromPageSet(nullptr, pPageSet, pTargetPageArea,
+                                pTargetContentArea, bNewPage, bQuery)) {
+      return m_pCurPageArea;
+    }
+    if (pPageSet == m_pPageSetNode)
+      break;
+
+    pPageSet = pPageSet->GetParent();
+  }
+  return nullptr;
+}
+
+bool CXFA_ViewLayoutProcessor::GetNextContentArea(CXFA_Node* pContentArea) {
+  CXFA_Node* pCurContentNode =
+      GetCurrentViewRecord()->pCurContentArea->GetFormNode();
+  if (!pContentArea) {
+    pContentArea = pCurContentNode->GetNextSameClassSibling<CXFA_ContentArea>(
+        XFA_Element::ContentArea);
+    if (!pContentArea)
+      return false;
+  } else {
+    if (pContentArea->GetParent() != m_pCurPageArea)
+      return false;
+
+    Optional<CXFA_ViewLayoutItem*> pContentAreaLayout = CheckContentAreaNotUsed(
+        GetCurrentViewRecord()->pCurPageArea.Get(), pContentArea);
+    if (!pContentAreaLayout.has_value())
+      return false;
+    if (pContentAreaLayout.value()) {
+      if (pContentAreaLayout.value()->GetFormNode() == pCurContentNode)
+        return false;
+
+      CXFA_ViewRecord* pNewRecord = CreateViewRecordSimple();
+      pNewRecord->pCurContentArea.Reset(pContentAreaLayout.value());
+      return true;
+    }
+  }
+
+  CXFA_ViewRecord* pNewRecord = CreateViewRecordSimple();
+  AddContentAreaLayoutItem(pNewRecord, pContentArea);
+  return true;
+}
+
+void CXFA_ViewLayoutProcessor::InitPageSetMap() {
+  if (!IsPageSetRootOrderedOccurrence())
+    return;
+
+  CXFA_NodeIterator sIterator(m_pPageSetNode);
+  for (CXFA_Node* pPageSetNode = sIterator.GetCurrent(); pPageSetNode;
+       pPageSetNode = sIterator.MoveToNext()) {
+    if (pPageSetNode->GetElementType() == XFA_Element::PageSet) {
+      XFA_AttributeValue eRelation =
+          pPageSetNode->JSObject()->GetEnum(XFA_Attribute::Relation);
+      if (eRelation == XFA_AttributeValue::OrderedOccurrence)
+        m_pPageSetMap[pPageSetNode] = 0;
+    }
+  }
+}
+
+int32_t CXFA_ViewLayoutProcessor::CreateMinPageRecord(CXFA_Node* pPageArea,
+                                                      bool bTargetPageArea,
+                                                      bool bCreateLast) {
+  if (!pPageArea)
+    return 0;
+
+  int32_t iMin = 0;
+  Optional<int32_t> ret;
+  CXFA_Node* pOccurNode =
+      pPageArea->GetFirstChildByClass<CXFA_Occur>(XFA_Element::Occur);
+  if (pOccurNode) {
+    ret = pOccurNode->JSObject()->TryInteger(XFA_Attribute::Min, false);
+    if (ret)
+      iMin = *ret;
+  }
+
+  if (!ret && !bTargetPageArea)
+    return iMin;
+
+  CXFA_Node* pContentArea = pPageArea->GetFirstChildByClass<CXFA_ContentArea>(
+      XFA_Element::ContentArea);
+  if (iMin < 1 && bTargetPageArea && !pContentArea)
+    iMin = 1;
+
+  int32_t i = 0;
+  if (bCreateLast)
+    i = m_nCurPageCount;
+
+  for (; i < iMin; i++) {
+    CXFA_ViewRecord* pNewRecord = CreateViewRecordSimple();
+    AddPageAreaLayoutItem(pNewRecord, pPageArea);
+    AddContentAreaLayoutItem(pNewRecord, pContentArea);
+  }
+  return iMin;
+}
+
+void CXFA_ViewLayoutProcessor::CreateMinPageSetRecord(CXFA_Node* pPageSet,
+                                                      bool bCreateAll) {
+  auto it = m_pPageSetMap.find(pPageSet);
+  if (it == m_pPageSetMap.end())
+    return;
+
+  int32_t iCurSetCount = it->second;
+  if (bCreateAll)
+    iCurSetCount = 0;
+
+  CXFA_Node* pOccurNode =
+      pPageSet->GetFirstChildByClass<CXFA_Occur>(XFA_Element::Occur);
+  if (!pOccurNode)
+    return;
+
+  Optional<int32_t> iMin =
+      pOccurNode->JSObject()->TryInteger(XFA_Attribute::Min, false);
+  if (!iMin || iCurSetCount >= *iMin)
+    return;
+
+  for (int32_t i = 0; i < *iMin - iCurSetCount; i++) {
+    for (CXFA_Node* node = pPageSet->GetFirstChild(); node;
+         node = node->GetNextSibling()) {
+      if (node->GetElementType() == XFA_Element::PageArea)
+        CreateMinPageRecord(node, false, false);
+      else if (node->GetElementType() == XFA_Element::PageSet)
+        CreateMinPageSetRecord(node, true);
+    }
+  }
+  m_pPageSetMap[pPageSet] = *iMin;
+}
+
+void CXFA_ViewLayoutProcessor::CreateNextMinRecord(CXFA_Node* pRecordNode) {
+  if (!pRecordNode)
+    return;
+
+  for (CXFA_Node* pCurrentNode = pRecordNode->GetNextSibling(); pCurrentNode;
+       pCurrentNode = pCurrentNode->GetNextSibling()) {
+    if (pCurrentNode->GetElementType() == XFA_Element::PageArea)
+      CreateMinPageRecord(pCurrentNode, false, false);
+    else if (pCurrentNode->GetElementType() == XFA_Element::PageSet)
+      CreateMinPageSetRecord(pCurrentNode, true);
+  }
+}
+
+void CXFA_ViewLayoutProcessor::ProcessLastPageSet() {
+  if (!m_pCurPageArea)
+    return;
+
+  CreateMinPageRecord(m_pCurPageArea, false, true);
+  CreateNextMinRecord(m_pCurPageArea);
+  CXFA_Node* pPageSet = m_pCurPageArea->GetParent();
+  while (pPageSet) {
+    CreateMinPageSetRecord(pPageSet, false);
+    if (pPageSet == m_pPageSetNode)
+      break;
+
+    CreateNextMinRecord(pPageSet);
+    pPageSet = pPageSet->GetParent();
+  }
+}
+
+bool CXFA_ViewLayoutProcessor::GetNextAvailContentHeight(float fChildHeight) {
+  CXFA_Node* pCurContentNode =
+      GetCurrentViewRecord()->pCurContentArea->GetFormNode();
+  if (!pCurContentNode)
+    return false;
+
+  pCurContentNode = pCurContentNode->GetNextSameClassSibling<CXFA_ContentArea>(
+      XFA_Element::ContentArea);
+  if (pCurContentNode) {
+    float fNextContentHeight = pCurContentNode->JSObject()->GetMeasureInUnit(
+        XFA_Attribute::H, XFA_Unit::Pt);
+    return fNextContentHeight > fChildHeight;
+  }
+
+  CXFA_Node* pPageNode = GetCurrentViewRecord()->pCurPageArea->GetFormNode();
+  CXFA_Node* pOccurNode =
+      pPageNode->GetFirstChildByClass<CXFA_Occur>(XFA_Element::Occur);
+  int32_t iMax = 0;
+  Optional<int32_t> ret;
+  if (pOccurNode) {
+    ret = pOccurNode->JSObject()->TryInteger(XFA_Attribute::Max, false);
+    if (ret)
+      iMax = *ret;
+  }
+  if (ret) {
+    if (m_nCurPageCount == iMax) {
+      CXFA_Node* pSrcPage = m_pCurPageArea;
+      int32_t nSrcPageCount = m_nCurPageCount;
+      auto psSrcIter = GetTailPosition();
+      CXFA_Node* pNextPage =
+          GetNextAvailPageArea(nullptr, nullptr, false, true);
+      m_pCurPageArea = pSrcPage;
+      m_nCurPageCount = nSrcPageCount;
+      CXFA_ViewRecord* pPrevRecord = psSrcIter->get();
+      ++psSrcIter;
+      while (psSrcIter != m_ProposedViewRecords.end()) {
+        auto psSaveIter = psSrcIter++;
+        RemoveLayoutRecord(psSaveIter->get(), pPrevRecord);
+        m_ProposedViewRecords.erase(psSaveIter);
+      }
+      if (pNextPage) {
+        CXFA_Node* pContentArea =
+            pNextPage->GetFirstChildByClass<CXFA_ContentArea>(
+                XFA_Element::ContentArea);
+        if (pContentArea) {
+          float fNextContentHeight = pContentArea->JSObject()->GetMeasureInUnit(
+              XFA_Attribute::H, XFA_Unit::Pt);
+          if (fNextContentHeight > fChildHeight)
+            return true;
+        }
+      }
+      return false;
+    }
+  }
+
+  CXFA_Node* pContentArea = pPageNode->GetFirstChildByClass<CXFA_ContentArea>(
+      XFA_Element::ContentArea);
+  if (!pContentArea)
+    return false;
+
+  float fNextContentHeight = pContentArea->JSObject()->GetMeasureInUnit(
+      XFA_Attribute::H, XFA_Unit::Pt);
+  return fNextContentHeight < kXFALayoutPrecision ||
+         fNextContentHeight > fChildHeight;
+}
+
+void CXFA_ViewLayoutProcessor::ClearData() {
+  if (!m_pPageSetNode)
+    return;
+
+  m_ProposedViewRecords.clear();
+  m_CurrentViewRecordIter = m_ProposedViewRecords.end();
+  m_pCurPageArea = nullptr;
+  m_nCurPageCount = 0;
+  m_bCreateOverFlowPage = false;
+  m_pPageSetMap.clear();
+}
+
+void CXFA_ViewLayoutProcessor::SaveLayoutItemChildren(
+    CXFA_LayoutItem* pParentLayoutItem) {
+  CXFA_Document* pDocument = m_pPageSetNode->GetDocument();
+  CXFA_FFNotify* pNotify = pDocument->GetNotify();
+  auto* pDocLayout = CXFA_LayoutProcessor::FromDocument(pDocument);
+  RetainPtr<CXFA_LayoutItem> pCurLayoutItem(pParentLayoutItem->GetFirstChild());
+  while (pCurLayoutItem) {
+    RetainPtr<CXFA_LayoutItem> pNextLayoutItem(
+        pCurLayoutItem->GetNextSibling());
+    if (pCurLayoutItem->IsContentLayoutItem()) {
+      if (pCurLayoutItem->GetFormNode()->HasRemovedChildren()) {
+        SyncRemoveLayoutItem(pCurLayoutItem.Get(), pNotify, pDocLayout);
+        pCurLayoutItem = std::move(pNextLayoutItem);
+        continue;
+      }
+      if (pCurLayoutItem->GetFormNode()->IsLayoutGeneratedNode())
+        pCurLayoutItem->GetFormNode()->SetNodeAndDescendantsUnused();
+    }
+    SaveLayoutItemChildren(pCurLayoutItem.Get());
+    pCurLayoutItem = std::move(pNextLayoutItem);
+  }
+}
+
+CXFA_Node* CXFA_ViewLayoutProcessor::QueryOverflow(CXFA_Node* pFormNode) {
+  for (CXFA_Node* pCurNode = pFormNode->GetFirstChild(); pCurNode;
+       pCurNode = pCurNode->GetNextSibling()) {
+    if (pCurNode->GetElementType() == XFA_Element::Break) {
+      WideString wsOverflowLeader =
+          pCurNode->JSObject()->GetCData(XFA_Attribute::OverflowLeader);
+      WideString wsOverflowTarget =
+          pCurNode->JSObject()->GetCData(XFA_Attribute::OverflowTarget);
+      WideString wsOverflowTrailer =
+          pCurNode->JSObject()->GetCData(XFA_Attribute::OverflowTrailer);
+
+      if (!wsOverflowLeader.IsEmpty() || !wsOverflowTrailer.IsEmpty() ||
+          !wsOverflowTarget.IsEmpty()) {
+        return pCurNode;
+      }
+      return nullptr;
+    }
+    if (pCurNode->GetElementType() == XFA_Element::Overflow)
+      return pCurNode;
+  }
+  return nullptr;
+}
+
+void CXFA_ViewLayoutProcessor::MergePageSetContents() {
+  CXFA_Document* pDocument = m_pPageSetNode->GetDocument();
+  pDocument->SetPendingNodesUnusedAndUnbound();
+
+  CXFA_FFNotify* pNotify = pDocument->GetNotify();
+  auto* pDocLayout = CXFA_LayoutProcessor::FromDocument(pDocument);
+  CXFA_ViewLayoutItem* pRootLayout = GetRootLayoutItem();
+
+  int32_t iIndex = 0;
+  for (; pRootLayout;
+       pRootLayout = ToViewLayoutItem(pRootLayout->GetNextSibling())) {
+    CXFA_Node* pPendingPageSet = nullptr;
+    ViewLayoutItemIterator iterator(pRootLayout);
+    CXFA_ViewLayoutItem* pRootPageSetViewItem = iterator.GetCurrent();
+    ASSERT(pRootPageSetViewItem->GetFormNode()->GetElementType() ==
+           XFA_Element::PageSet);
+    if (iIndex <
+        pdfium::CollectionSize<int32_t>(pDocument->m_pPendingPageSet)) {
+      pPendingPageSet = pDocument->m_pPendingPageSet[iIndex];
+      iIndex++;
+    }
+    if (!pPendingPageSet) {
+      if (pRootPageSetViewItem->GetFormNode()->GetPacketType() ==
+          XFA_PacketType::Template) {
+        pPendingPageSet =
+            pRootPageSetViewItem->GetFormNode()->CloneTemplateToForm(false);
+      } else {
+        pPendingPageSet = pRootPageSetViewItem->GetFormNode();
+      }
+    }
+    if (pRootPageSetViewItem->GetFormNode()->JSObject()->GetLayoutItem() ==
+        pRootPageSetViewItem) {
+      pRootPageSetViewItem->GetFormNode()->JSObject()->SetLayoutItem(nullptr);
+    }
+    pRootPageSetViewItem->SetFormNode(pPendingPageSet);
+    pPendingPageSet->ClearFlag(XFA_NodeFlag_UnusedNode);
+    for (CXFA_ViewLayoutItem* pViewItem = iterator.MoveToNext(); pViewItem;
+         pViewItem = iterator.MoveToNext()) {
+      CXFA_Node* pNode = pViewItem->GetFormNode();
+      if (pNode->GetPacketType() != XFA_PacketType::Template)
+        continue;
+
+      switch (pNode->GetElementType()) {
+        case XFA_Element::PageSet: {
+          CXFA_Node* pParentNode = pViewItem->GetParent()->GetFormNode();
+          CXFA_Node* pOldNode = pViewItem->GetFormNode();
+          CXFA_Node* pNewNode = XFA_NodeMerge_CloneOrMergeContainer(
+              pDocument, pParentNode, pOldNode, true, nullptr);
+          if (pOldNode != pNewNode) {
+            pOldNode->JSObject()->SetLayoutItem(nullptr);
+            pViewItem->SetFormNode(pNewNode);
+          }
+          break;
+        }
+        case XFA_Element::PageArea: {
+          CXFA_LayoutItem* pFormLayout = pViewItem;
+          CXFA_Node* pParentNode = pViewItem->GetParent()->GetFormNode();
+          bool bIsExistForm = true;
+          for (int32_t iLevel = 0; iLevel < 3; iLevel++) {
+            pFormLayout = pFormLayout->GetFirstChild();
+            if (iLevel == 2) {
+              while (pFormLayout &&
+                     !pFormLayout->GetFormNode()->PresenceRequiresSpace()) {
+                pFormLayout = pFormLayout->GetNextSibling();
+              }
+            }
+            if (!pFormLayout) {
+              bIsExistForm = false;
+              break;
+            }
+          }
+          if (bIsExistForm) {
+            CXFA_Node* pNewSubform = pFormLayout->GetFormNode();
+            if (pViewItem->m_pOldSubform &&
+                pViewItem->m_pOldSubform != pNewSubform) {
+              CXFA_Node* pExistingNode = XFA_DataMerge_FindFormDOMInstance(
+                  pDocument, pViewItem->GetFormNode()->GetElementType(),
+                  pViewItem->GetFormNode()->GetNameHash(), pParentNode);
+              CXFA_ContainerIterator sIterator(pExistingNode);
+              for (CXFA_Node* pIter = sIterator.GetCurrent(); pIter;
+                   pIter = sIterator.MoveToNext()) {
+                if (pIter->GetElementType() != XFA_Element::ContentArea) {
+                  RetainPtr<CXFA_LayoutItem> pLayoutItem(
+                      pIter->JSObject()->GetLayoutItem());
+                  if (pLayoutItem) {
+                    pNotify->OnLayoutItemRemoving(pDocLayout,
+                                                  pLayoutItem.Get());
+                    pLayoutItem->RemoveSelfIfParented();
+                  }
+                }
+              }
+              if (pExistingNode) {
+                pParentNode->RemoveChildAndNotify(pExistingNode, true);
+              }
+            }
+            pViewItem->m_pOldSubform = pNewSubform;
+          }
+          CXFA_Node* pOldNode = pViewItem->GetFormNode();
+          CXFA_Node* pNewNode = pDocument->DataMerge_CopyContainer(
+              pOldNode, pParentNode,
+              ToNode(pDocument->GetXFAObject(XFA_HASHCODE_Record)), true, true,
+              true);
+          if (pOldNode != pNewNode) {
+            pOldNode->JSObject()->SetLayoutItem(nullptr);
+            pViewItem->SetFormNode(pNewNode);
+          }
+          break;
+        }
+        case XFA_Element::ContentArea: {
+          CXFA_Node* pParentNode = pViewItem->GetParent()->GetFormNode();
+          for (CXFA_Node* pChildNode = pParentNode->GetFirstChild(); pChildNode;
+               pChildNode = pChildNode->GetNextSibling()) {
+            if (pChildNode->GetTemplateNodeIfExists() !=
+                pViewItem->GetFormNode()) {
+              continue;
+            }
+            pViewItem->SetFormNode(pChildNode);
+            break;
+          }
+          break;
+        }
+        default:
+          break;
+      }
+    }
+    if (!pPendingPageSet->GetParent()) {
+      CXFA_Node* pNode = ToNode(pDocument->GetXFAObject(XFA_HASHCODE_Form));
+      if (pNode) {
+        CXFA_Node* pFormToplevelSubform =
+            pNode->GetFirstChildByClass<CXFA_Subform>(XFA_Element::Subform);
+        if (pFormToplevelSubform)
+          pFormToplevelSubform->InsertChildAndNotify(pPendingPageSet, nullptr);
+      }
+    }
+    pDocument->DataMerge_UpdateBindingRelations(pPendingPageSet);
+    pPendingPageSet->SetFlagAndNotify(XFA_NodeFlag_Initialized);
+  }
+
+  CXFA_Node* pPageSet = GetRootLayoutItem()->GetFormNode();
+  while (pPageSet) {
+    CXFA_Node* pNextPageSet =
+        pPageSet->GetNextSameClassSibling<CXFA_PageSet>(XFA_Element::PageSet);
+    CXFA_NodeIteratorTemplate<CXFA_Node, CXFA_TraverseStrategy_XFANode>
+        sIterator(pPageSet);
+    CXFA_Node* pNode = sIterator.GetCurrent();
+    while (pNode) {
+      if (pNode->IsUnusedNode()) {
+        if (pNode->IsContainerNode()) {
+          XFA_Element eType = pNode->GetElementType();
+          if (eType == XFA_Element::PageArea || eType == XFA_Element::PageSet) {
+            CXFA_ContainerIterator iteChild(pNode);
+            CXFA_Node* pChildNode = iteChild.MoveToNext();
+            for (; pChildNode; pChildNode = iteChild.MoveToNext()) {
+              RetainPtr<CXFA_LayoutItem> pLayoutItem(
+                  pChildNode->JSObject()->GetLayoutItem());
+              if (pLayoutItem) {
+                pNotify->OnLayoutItemRemoving(pDocLayout, pLayoutItem.Get());
+                pLayoutItem->RemoveSelfIfParented();
+              }
+            }
+          } else if (eType != XFA_Element::ContentArea) {
+            RetainPtr<CXFA_LayoutItem> pLayoutItem(
+                pNode->JSObject()->GetLayoutItem());
+            if (pLayoutItem) {
+              pNotify->OnLayoutItemRemoving(pDocLayout, pLayoutItem.Get());
+              pLayoutItem->RemoveSelfIfParented();
+            }
+          }
+          CXFA_Node* pNext = sIterator.SkipChildrenAndMoveToNext();
+          pNode->GetParent()->RemoveChildAndNotify(pNode, true);
+          pNode = pNext;
+        } else {
+          pNode->ClearFlag(XFA_NodeFlag_UnusedNode);
+          pNode->SetFlagAndNotify(XFA_NodeFlag_Initialized);
+          pNode = sIterator.MoveToNext();
+        }
+      } else {
+        pNode->SetFlagAndNotify(XFA_NodeFlag_Initialized);
+        pNode = sIterator.MoveToNext();
+      }
+    }
+    pPageSet = pNextPageSet;
+  }
+}
+
+void CXFA_ViewLayoutProcessor::LayoutPageSetContents() {
+  for (CXFA_ViewLayoutItem* pRootLayoutItem = GetRootLayoutItem();
+       pRootLayoutItem;
+       pRootLayoutItem = ToViewLayoutItem(pRootLayoutItem->GetNextSibling())) {
+    ViewLayoutItemIterator iterator(pRootLayoutItem);
+    for (CXFA_ViewLayoutItem* pViewItem = iterator.GetCurrent(); pViewItem;
+         pViewItem = iterator.MoveToNext()) {
+      XFA_Element type = pViewItem->GetFormNode()->GetElementType();
+      if (type != XFA_Element::PageArea)
+        continue;
+
+      m_pLayoutProcessor->GetRootContentLayoutProcessor()->DoLayoutPageArea(
+          pViewItem);
+    }
+  }
+}
+
+void CXFA_ViewLayoutProcessor::SyncLayoutData() {
+  MergePageSetContents();
+  LayoutPageSetContents();
+  CXFA_FFNotify* pNotify = m_pPageSetNode->GetDocument()->GetNotify();
+  int32_t nPageIdx = -1;
+  for (CXFA_ViewLayoutItem* pRootLayoutItem = GetRootLayoutItem();
+       pRootLayoutItem;
+       pRootLayoutItem = ToViewLayoutItem(pRootLayoutItem->GetNextSibling())) {
+    ViewLayoutItemIterator iteratorParent(pRootLayoutItem);
+    for (CXFA_ViewLayoutItem* pViewItem = iteratorParent.GetCurrent();
+         pViewItem; pViewItem = iteratorParent.MoveToNext()) {
+      XFA_Element type = pViewItem->GetFormNode()->GetElementType();
+      if (type != XFA_Element::PageArea)
+        continue;
+
+      nPageIdx++;
+      uint32_t dwRelevant =
+          XFA_WidgetStatus_Viewable | XFA_WidgetStatus_Printable;
+      CXFA_LayoutItemIterator iterator(pViewItem);
+      CXFA_LayoutItem* pChildLayoutItem = iterator.GetCurrent();
+      while (pChildLayoutItem) {
+        CXFA_ContentLayoutItem* pContentItem =
+            pChildLayoutItem->AsContentLayoutItem();
+        if (!pContentItem) {
+          pChildLayoutItem = iterator.MoveToNext();
+          continue;
+        }
+
+        XFA_AttributeValue presence =
+            pContentItem->GetFormNode()
+                ->JSObject()
+                ->TryEnum(XFA_Attribute::Presence, true)
+                .value_or(XFA_AttributeValue::Visible);
+        bool bVisible = presence == XFA_AttributeValue::Visible;
+        uint32_t dwRelevantChild =
+            GetRelevant(pContentItem->GetFormNode(), dwRelevant);
+        SyncContainer(pNotify, m_pLayoutProcessor, pContentItem,
+                      dwRelevantChild, bVisible, nPageIdx);
+        pChildLayoutItem = iterator.SkipChildrenAndMoveToNext();
+      }
+    }
+  }
+
+  int32_t nPage = pdfium::CollectionSize<int32_t>(m_PageArray);
+  for (int32_t i = nPage - 1; i >= m_nAvailPages; i--) {
+    RetainPtr<CXFA_ViewLayoutItem> pPage = m_PageArray[i];
+    m_PageArray.erase(m_PageArray.begin() + i);
+    pNotify->OnPageEvent(pPage.Get(), XFA_PAGEVIEWEVENT_PostRemoved);
+  }
+  ClearData();
+}
+
+void CXFA_ViewLayoutProcessor::PrepareLayout() {
+  m_pPageSetCurLayoutItem = nullptr;
+  m_ePageSetMode = XFA_AttributeValue::OrderedOccurrence;
+  m_nAvailPages = 0;
+  ClearData();
+  if (!m_pPageSetRootLayoutItem)
+    return;
+
+  RetainPtr<CXFA_ViewLayoutItem> pRootLayoutItem = m_pPageSetRootLayoutItem;
+  if (pRootLayoutItem &&
+      pRootLayoutItem->GetFormNode()->GetPacketType() == XFA_PacketType::Form) {
+    CXFA_Node* pPageSetFormNode = pRootLayoutItem->GetFormNode();
+    pRootLayoutItem->GetFormNode()->GetDocument()->m_pPendingPageSet.clear();
+    if (pPageSetFormNode->HasRemovedChildren()) {
+      XFA_ReleaseLayoutItem(pRootLayoutItem);
+      m_pPageSetRootLayoutItem = nullptr;
+      pRootLayoutItem = nullptr;
+      pPageSetFormNode = nullptr;
+      m_PageArray.clear();
+    }
+    while (pPageSetFormNode) {
+      CXFA_Node* pNextPageSet =
+          pPageSetFormNode->GetNextSameClassSibling<CXFA_PageSet>(
+              XFA_Element::PageSet);
+      pPageSetFormNode->GetParent()->RemoveChildAndNotify(pPageSetFormNode,
+                                                          false);
+      pRootLayoutItem->GetFormNode()
+          ->GetDocument()
+          ->m_pPendingPageSet.push_back(pPageSetFormNode);
+      pPageSetFormNode = pNextPageSet;
+    }
+  }
+  pRootLayoutItem = m_pPageSetRootLayoutItem;
+  CXFA_ViewLayoutItem* pNextLayout = nullptr;
+  for (; pRootLayoutItem; pRootLayoutItem.Reset(pNextLayout)) {
+    pNextLayout = ToViewLayoutItem(pRootLayoutItem->GetNextSibling());
+    SaveLayoutItemChildren(pRootLayoutItem.Get());
+    pRootLayoutItem->RemoveSelfIfParented();
+  }
+  m_pPageSetRootLayoutItem = nullptr;
+}
+
+void CXFA_ViewLayoutProcessor::ProcessSimplexOrDuplexPageSets(
+    CXFA_ViewLayoutItem* pPageSetLayoutItem,
+    bool bIsSimplex) {
+  size_t nPageAreaCount;
+  CXFA_LayoutItem* pLastPageAreaLayoutItem;
+  std::tie(nPageAreaCount, pLastPageAreaLayoutItem) =
+      GetPageAreaCountAndLastPageAreaFromPageSet(pPageSetLayoutItem);
+  if (!pLastPageAreaLayoutItem)
+    return;
+
+  if (!FindPageAreaFromPageSet_SimplexDuplex(
+          pPageSetLayoutItem->GetFormNode(), nullptr, nullptr, nullptr, true,
+          true,
+          nPageAreaCount == 1 ? XFA_AttributeValue::Only
+                              : XFA_AttributeValue::Last) &&
+      (nPageAreaCount == 1 &&
+       !FindPageAreaFromPageSet_SimplexDuplex(
+           pPageSetLayoutItem->GetFormNode(), nullptr, nullptr, nullptr, true,
+           true, XFA_AttributeValue::Last))) {
+    return;
+  }
+
+  CXFA_Node* pNode = m_pCurPageArea;
+  XFA_AttributeValue eCurChoice =
+      pNode->JSObject()->GetEnum(XFA_Attribute::PagePosition);
+  if (eCurChoice == XFA_AttributeValue::Last) {
+    XFA_AttributeValue eOddOrEven =
+        pNode->JSObject()->GetEnum(XFA_Attribute::OddOrEven);
+    XFA_AttributeValue eLastChoice =
+        pLastPageAreaLayoutItem->GetFormNode()->JSObject()->GetEnum(
+            XFA_Attribute::PagePosition);
+    if (eLastChoice == XFA_AttributeValue::First &&
+        (bIsSimplex || eOddOrEven != XFA_AttributeValue::Odd)) {
+      CXFA_ViewRecord* pRecord = CreateViewRecordSimple();
+      AddPageAreaLayoutItem(pRecord, pNode);
+      return;
+    }
+  }
+
+  std::vector<float> rgUsedHeights =
+      GetHeightsForContentAreas(pLastPageAreaLayoutItem);
+  if (ContentAreasFitInPageAreas(pNode, rgUsedHeights)) {
+    CXFA_LayoutItem* pChildLayoutItem =
+        pLastPageAreaLayoutItem->GetFirstChild();
+    CXFA_Node* pContentAreaNode = pNode->GetFirstChild();
+    pLastPageAreaLayoutItem->SetFormNode(pNode);
+    while (pChildLayoutItem && pContentAreaNode) {
+      if (pChildLayoutItem->GetFormNode()->GetElementType() !=
+          XFA_Element::ContentArea) {
+        pChildLayoutItem = pChildLayoutItem->GetNextSibling();
+        continue;
+      }
+      if (pContentAreaNode->GetElementType() != XFA_Element::ContentArea) {
+        pContentAreaNode = pContentAreaNode->GetNextSibling();
+        continue;
+      }
+      pChildLayoutItem->SetFormNode(pContentAreaNode);
+      pChildLayoutItem = pChildLayoutItem->GetNextSibling();
+      pContentAreaNode = pContentAreaNode->GetNextSibling();
+    }
+    return;
+  }
+
+  if (pNode->JSObject()->GetEnum(XFA_Attribute::PagePosition) ==
+      XFA_AttributeValue::Last) {
+    CXFA_ViewRecord* pRecord = CreateViewRecordSimple();
+    AddPageAreaLayoutItem(pRecord, pNode);
+  }
+}
diff --git a/xfa/fxfa/layout/cxfa_viewlayoutprocessor.h b/xfa/fxfa/layout/cxfa_viewlayoutprocessor.h
new file mode 100644
index 0000000..e623285
--- /dev/null
+++ b/xfa/fxfa/layout/cxfa_viewlayoutprocessor.h
@@ -0,0 +1,178 @@
+// Copyright 2014 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_LAYOUT_CXFA_VIEWLAYOUTPROCESSOR_H_
+#define XFA_FXFA_LAYOUT_CXFA_VIEWLAYOUTPROCESSOR_H_
+
+#include <iterator>
+#include <list>
+#include <map>
+#include <memory>
+#include <vector>
+
+#include "core/fxcrt/retain_ptr.h"
+#include "third_party/base/optional.h"
+#include "xfa/fxfa/layout/cxfa_contentlayoutprocessor.h"
+
+class CXFA_LayoutItem;
+class CXFA_Node;
+
+class CXFA_ViewLayoutProcessor {
+ public:
+  struct BreakData {
+    CXFA_Node* pLeader;
+    CXFA_Node* pTrailer;
+    bool bCreatePage;
+  };
+
+  struct OverflowData {
+    CXFA_Node* pLeader;
+    CXFA_Node* pTrailer;
+  };
+
+  explicit CXFA_ViewLayoutProcessor(CXFA_LayoutProcessor* pLayoutProcessor);
+  ~CXFA_ViewLayoutProcessor();
+
+  bool InitLayoutPage(CXFA_Node* pFormNode);
+  bool PrepareFirstPage(CXFA_Node* pRootSubform);
+  float GetAvailHeight();
+  bool GetNextAvailContentHeight(float fChildHeight);
+  void SubmitContentItem(
+      const RetainPtr<CXFA_ContentLayoutItem>& pContentLayoutItem,
+      CXFA_ContentLayoutProcessor::Result eStatus);
+  void FinishPaginatedPageSets();
+  void SyncLayoutData();
+  int32_t GetPageCount() const;
+  CXFA_ViewLayoutItem* GetPage(int32_t index) const;
+  int32_t GetPageIndex(const CXFA_ViewLayoutItem* pPage) const;
+  CXFA_ViewLayoutItem* GetRootLayoutItem() const {
+    return m_pPageSetRootLayoutItem.Get();
+  }
+  Optional<BreakData> ProcessBreakBefore(const CXFA_Node* pBreakNode);
+  Optional<BreakData> ProcessBreakAfter(const CXFA_Node* pBreakNode);
+  Optional<OverflowData> ProcessOverflow(CXFA_Node* pFormNode,
+                                         bool bCreatePage);
+  CXFA_Node* QueryOverflow(CXFA_Node* pFormNode);
+  CXFA_Node* ProcessBookendLeader(const CXFA_Node* pBookendNode);
+  CXFA_Node* ProcessBookendTrailer(const CXFA_Node* pBookendNode);
+
+ private:
+  struct CXFA_ViewRecord {
+    CXFA_ViewRecord();
+    ~CXFA_ViewRecord();
+
+    RetainPtr<CXFA_ViewLayoutItem> pCurPageSet;
+    RetainPtr<CXFA_ViewLayoutItem> pCurPageArea;
+    RetainPtr<CXFA_ViewLayoutItem> pCurContentArea;
+  };
+
+  using RecordList = std::list<std::unique_ptr<CXFA_ViewRecord>>;
+
+  bool AppendNewPage(bool bFirstTemPage);
+  void ReorderPendingLayoutRecordToTail(CXFA_ViewRecord* pNewRecord,
+                                        CXFA_ViewRecord* pPrevRecord);
+  void RemoveLayoutRecord(CXFA_ViewRecord* pNewRecord,
+                          CXFA_ViewRecord* pPrevRecord);
+  bool HasCurrentViewRecord() const {
+    return m_CurrentViewRecordIter != m_ProposedViewRecords.end();
+  }
+  CXFA_ViewRecord* GetCurrentViewRecord() {
+    return m_CurrentViewRecordIter->get();
+  }
+  const CXFA_ViewRecord* GetCurrentViewRecord() const {
+    return m_CurrentViewRecordIter->get();
+  }
+  void ResetToFirstViewRecord() {
+    m_CurrentViewRecordIter = m_ProposedViewRecords.begin();
+  }
+  RecordList::iterator GetTailPosition() {
+    auto iter = m_ProposedViewRecords.end();
+    return !m_ProposedViewRecords.empty() ? std::prev(iter) : iter;
+  }
+  CXFA_ViewRecord* AppendNewRecord(std::unique_ptr<CXFA_ViewRecord> pNewRecord);
+  CXFA_ViewRecord* CreateViewRecord(CXFA_Node* pPageNode, bool bCreateNew);
+  CXFA_ViewRecord* CreateViewRecordSimple();
+  void AddPageAreaLayoutItem(CXFA_ViewRecord* pNewRecord,
+                             CXFA_Node* pNewPageArea);
+  void AddContentAreaLayoutItem(CXFA_ViewRecord* pNewRecord,
+                                CXFA_Node* pContentArea);
+  bool RunBreak(XFA_Element eBreakType,
+                XFA_AttributeValue eTargetType,
+                CXFA_Node* pTarget,
+                bool bStartNew);
+  bool ShouldGetNextPageArea(CXFA_Node* pTarget, bool bStartNew) const;
+  bool BreakOverflow(const CXFA_Node* pOverflowNode,
+                     bool bCreatePage,
+                     CXFA_Node** pLeaderTemplate,
+                     CXFA_Node** pTrailerTemplate);
+  CXFA_Node* ProcessBookendLeaderOrTrailer(const CXFA_Node* pBookendNode,
+                                           bool bLeader);
+  CXFA_Node* ResolveBookendLeaderOrTrailer(const CXFA_Node* pBookendNode,
+                                           bool bLeader);
+  Optional<BreakData> ProcessBreakBeforeOrAfter(const CXFA_Node* pBreakNode,
+                                                bool bBefore);
+  BreakData ExecuteBreakBeforeOrAfter(const CXFA_Node* pCurNode, bool bBefore);
+
+  int32_t CreateMinPageRecord(CXFA_Node* pPageArea,
+                              bool bTargetPageArea,
+                              bool bCreateLast);
+  void CreateMinPageSetRecord(CXFA_Node* pPageSet, bool bCreateAll);
+  void CreateNextMinRecord(CXFA_Node* pRecordNode);
+  bool FindPageAreaFromPageSet(CXFA_Node* pPageSet,
+                               CXFA_Node* pStartChild,
+                               CXFA_Node* pTargetPageArea,
+                               CXFA_Node* pTargetContentArea,
+                               bool bNewPage,
+                               bool bQuery);
+  bool FindPageAreaFromPageSet_Ordered(CXFA_Node* pPageSet,
+                                       CXFA_Node* pStartChild,
+                                       CXFA_Node* pTargetPageArea,
+                                       CXFA_Node* pTargetContentArea,
+                                       bool bNewPage,
+                                       bool bQuery);
+  bool FindPageAreaFromPageSet_SimplexDuplex(
+      CXFA_Node* pPageSet,
+      CXFA_Node* pStartChild,
+      CXFA_Node* pTargetPageArea,
+      CXFA_Node* pTargetContentArea,
+      bool bNewPage,
+      bool bQuery,
+      XFA_AttributeValue ePreferredPosition);
+  bool MatchPageAreaOddOrEven(CXFA_Node* pPageArea);
+  CXFA_Node* GetNextAvailPageArea(CXFA_Node* pTargetPageArea,
+                                  CXFA_Node* pTargetContentArea,
+                                  bool bNewPage,
+                                  bool bQuery);
+  bool GetNextContentArea(CXFA_Node* pTargetContentArea);
+  void InitPageSetMap();
+  void ProcessLastPageSet();
+  bool IsPageSetRootOrderedOccurrence() const {
+    return m_ePageSetMode == XFA_AttributeValue::OrderedOccurrence;
+  }
+  void ClearData();
+  void MergePageSetContents();
+  void LayoutPageSetContents();
+  void PrepareLayout();
+  void SaveLayoutItemChildren(CXFA_LayoutItem* pParentLayoutItem);
+  void ProcessSimplexOrDuplexPageSets(CXFA_ViewLayoutItem* pPageSetLayoutItem,
+                                      bool bIsSimplex);
+
+  CXFA_LayoutProcessor* m_pLayoutProcessor = nullptr;
+  CXFA_Node* m_pPageSetNode = nullptr;
+  RetainPtr<CXFA_ViewLayoutItem> m_pPageSetRootLayoutItem;
+  RetainPtr<CXFA_ViewLayoutItem> m_pPageSetCurLayoutItem;
+  RecordList m_ProposedViewRecords;
+  RecordList::iterator m_CurrentViewRecordIter;
+  CXFA_Node* m_pCurPageArea = nullptr;
+  int32_t m_nAvailPages = 0;
+  int32_t m_nCurPageCount = 0;
+  XFA_AttributeValue m_ePageSetMode = XFA_AttributeValue::OrderedOccurrence;
+  bool m_bCreateOverFlowPage = false;
+  std::map<CXFA_Node*, int32_t> m_pPageSetMap;
+  std::vector<RetainPtr<CXFA_ViewLayoutItem>> m_PageArray;
+};
+
+#endif  // XFA_FXFA_LAYOUT_CXFA_VIEWLAYOUTPROCESSOR_H_
diff --git a/xfa/fxfa/parser/BUILD.gn b/xfa/fxfa/parser/BUILD.gn
new file mode 100644
index 0000000..c6f6d55
--- /dev/null
+++ b/xfa/fxfa/parser/BUILD.gn
@@ -0,0 +1,721 @@
+# Copyright 2018 The 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.
+
+import("../../../pdfium.gni")
+import("../../../testing/test.gni")
+
+assert(pdf_enable_xfa)
+
+source_set("parser") {
+  sources = [
+    "cscript_datawindow.cpp",
+    "cscript_datawindow.h",
+    "cscript_eventpseudomodel.cpp",
+    "cscript_eventpseudomodel.h",
+    "cscript_hostpseudomodel.cpp",
+    "cscript_hostpseudomodel.h",
+    "cscript_layoutpseudomodel.cpp",
+    "cscript_layoutpseudomodel.h",
+    "cscript_logpseudomodel.cpp",
+    "cscript_logpseudomodel.h",
+    "cscript_signaturepseudomodel.cpp",
+    "cscript_signaturepseudomodel.h",
+    "cxfa_accessiblecontent.cpp",
+    "cxfa_accessiblecontent.h",
+    "cxfa_acrobat.cpp",
+    "cxfa_acrobat.h",
+    "cxfa_acrobat7.cpp",
+    "cxfa_acrobat7.h",
+    "cxfa_adbe_jsconsole.cpp",
+    "cxfa_adbe_jsconsole.h",
+    "cxfa_adbe_jsdebugger.cpp",
+    "cxfa_adbe_jsdebugger.h",
+    "cxfa_addsilentprint.cpp",
+    "cxfa_addsilentprint.h",
+    "cxfa_addviewerpreferences.cpp",
+    "cxfa_addviewerpreferences.h",
+    "cxfa_adjustdata.cpp",
+    "cxfa_adjustdata.h",
+    "cxfa_adobeextensionlevel.cpp",
+    "cxfa_adobeextensionlevel.h",
+    "cxfa_agent.cpp",
+    "cxfa_agent.h",
+    "cxfa_alwaysembed.cpp",
+    "cxfa_alwaysembed.h",
+    "cxfa_amd.cpp",
+    "cxfa_amd.h",
+    "cxfa_appearancefilter.cpp",
+    "cxfa_appearancefilter.h",
+    "cxfa_arc.cpp",
+    "cxfa_arc.h",
+    "cxfa_area.cpp",
+    "cxfa_area.h",
+    "cxfa_arraynodelist.cpp",
+    "cxfa_arraynodelist.h",
+    "cxfa_assist.cpp",
+    "cxfa_assist.h",
+    "cxfa_attachnodelist.cpp",
+    "cxfa_attachnodelist.h",
+    "cxfa_attributes.cpp",
+    "cxfa_attributes.h",
+    "cxfa_autosave.cpp",
+    "cxfa_autosave.h",
+    "cxfa_barcode.cpp",
+    "cxfa_barcode.h",
+    "cxfa_base.cpp",
+    "cxfa_base.h",
+    "cxfa_batchoutput.cpp",
+    "cxfa_batchoutput.h",
+    "cxfa_behavioroverride.cpp",
+    "cxfa_behavioroverride.h",
+    "cxfa_bind.cpp",
+    "cxfa_bind.h",
+    "cxfa_binditems.cpp",
+    "cxfa_binditems.h",
+    "cxfa_bookend.cpp",
+    "cxfa_bookend.h",
+    "cxfa_boolean.cpp",
+    "cxfa_boolean.h",
+    "cxfa_border.cpp",
+    "cxfa_border.h",
+    "cxfa_box.cpp",
+    "cxfa_box.h",
+    "cxfa_break.cpp",
+    "cxfa_break.h",
+    "cxfa_breakafter.cpp",
+    "cxfa_breakafter.h",
+    "cxfa_breakbefore.cpp",
+    "cxfa_breakbefore.h",
+    "cxfa_button.cpp",
+    "cxfa_button.h",
+    "cxfa_cache.cpp",
+    "cxfa_cache.h",
+    "cxfa_calculate.cpp",
+    "cxfa_calculate.h",
+    "cxfa_calendarsymbols.cpp",
+    "cxfa_calendarsymbols.h",
+    "cxfa_caption.cpp",
+    "cxfa_caption.h",
+    "cxfa_certificate.cpp",
+    "cxfa_certificate.h",
+    "cxfa_certificates.cpp",
+    "cxfa_certificates.h",
+    "cxfa_change.cpp",
+    "cxfa_change.h",
+    "cxfa_checkbutton.cpp",
+    "cxfa_checkbutton.h",
+    "cxfa_choicelist.cpp",
+    "cxfa_choicelist.h",
+    "cxfa_color.cpp",
+    "cxfa_color.h",
+    "cxfa_comb.cpp",
+    "cxfa_comb.h",
+    "cxfa_command.cpp",
+    "cxfa_command.h",
+    "cxfa_common.cpp",
+    "cxfa_common.h",
+    "cxfa_compress.cpp",
+    "cxfa_compress.h",
+    "cxfa_compression.cpp",
+    "cxfa_compression.h",
+    "cxfa_compresslogicalstructure.cpp",
+    "cxfa_compresslogicalstructure.h",
+    "cxfa_compressobjectstream.cpp",
+    "cxfa_compressobjectstream.h",
+    "cxfa_config.cpp",
+    "cxfa_config.h",
+    "cxfa_conformance.cpp",
+    "cxfa_conformance.h",
+    "cxfa_connect.cpp",
+    "cxfa_connect.h",
+    "cxfa_connectionset.cpp",
+    "cxfa_connectionset.h",
+    "cxfa_connectstring.cpp",
+    "cxfa_connectstring.h",
+    "cxfa_contentarea.cpp",
+    "cxfa_contentarea.h",
+    "cxfa_contentcopy.cpp",
+    "cxfa_contentcopy.h",
+    "cxfa_copies.cpp",
+    "cxfa_copies.h",
+    "cxfa_corner.cpp",
+    "cxfa_corner.h",
+    "cxfa_creator.cpp",
+    "cxfa_creator.h",
+    "cxfa_currencysymbol.cpp",
+    "cxfa_currencysymbol.h",
+    "cxfa_currencysymbols.cpp",
+    "cxfa_currencysymbols.h",
+    "cxfa_currentpage.cpp",
+    "cxfa_currentpage.h",
+    "cxfa_data.cpp",
+    "cxfa_data.h",
+    "cxfa_dataexporter.cpp",
+    "cxfa_dataexporter.h",
+    "cxfa_datagroup.cpp",
+    "cxfa_datagroup.h",
+    "cxfa_datamodel.cpp",
+    "cxfa_datamodel.h",
+    "cxfa_datavalue.cpp",
+    "cxfa_datavalue.h",
+    "cxfa_date.cpp",
+    "cxfa_date.h",
+    "cxfa_datepattern.cpp",
+    "cxfa_datepattern.h",
+    "cxfa_datepatterns.cpp",
+    "cxfa_datepatterns.h",
+    "cxfa_datetime.cpp",
+    "cxfa_datetime.h",
+    "cxfa_datetimeedit.cpp",
+    "cxfa_datetimeedit.h",
+    "cxfa_datetimesymbols.cpp",
+    "cxfa_datetimesymbols.h",
+    "cxfa_day.cpp",
+    "cxfa_day.h",
+    "cxfa_daynames.cpp",
+    "cxfa_daynames.h",
+    "cxfa_debug.cpp",
+    "cxfa_debug.h",
+    "cxfa_decimal.cpp",
+    "cxfa_decimal.h",
+    "cxfa_defaulttypeface.cpp",
+    "cxfa_defaulttypeface.h",
+    "cxfa_defaultui.cpp",
+    "cxfa_defaultui.h",
+    "cxfa_delete.cpp",
+    "cxfa_delete.h",
+    "cxfa_delta.cpp",
+    "cxfa_delta.h",
+    "cxfa_deltas.cpp",
+    "cxfa_deltas.h",
+    "cxfa_desc.cpp",
+    "cxfa_desc.h",
+    "cxfa_destination.cpp",
+    "cxfa_destination.h",
+    "cxfa_digestmethod.cpp",
+    "cxfa_digestmethod.h",
+    "cxfa_digestmethods.cpp",
+    "cxfa_digestmethods.h",
+    "cxfa_document.cpp",
+    "cxfa_document.h",
+    "cxfa_document_parser.cpp",
+    "cxfa_document_parser.h",
+    "cxfa_documentassembly.cpp",
+    "cxfa_documentassembly.h",
+    "cxfa_draw.cpp",
+    "cxfa_draw.h",
+    "cxfa_driver.cpp",
+    "cxfa_driver.h",
+    "cxfa_dsigdata.cpp",
+    "cxfa_dsigdata.h",
+    "cxfa_duplexoption.cpp",
+    "cxfa_duplexoption.h",
+    "cxfa_dynamicrender.cpp",
+    "cxfa_dynamicrender.h",
+    "cxfa_edge.cpp",
+    "cxfa_edge.h",
+    "cxfa_effectiveinputpolicy.cpp",
+    "cxfa_effectiveinputpolicy.h",
+    "cxfa_effectiveoutputpolicy.cpp",
+    "cxfa_effectiveoutputpolicy.h",
+    "cxfa_embed.cpp",
+    "cxfa_embed.h",
+    "cxfa_encoding.cpp",
+    "cxfa_encoding.h",
+    "cxfa_encodings.cpp",
+    "cxfa_encodings.h",
+    "cxfa_encrypt.cpp",
+    "cxfa_encrypt.h",
+    "cxfa_encryption.cpp",
+    "cxfa_encryption.h",
+    "cxfa_encryptionlevel.cpp",
+    "cxfa_encryptionlevel.h",
+    "cxfa_encryptionmethod.cpp",
+    "cxfa_encryptionmethod.h",
+    "cxfa_encryptionmethods.cpp",
+    "cxfa_encryptionmethods.h",
+    "cxfa_enforce.cpp",
+    "cxfa_enforce.h",
+    "cxfa_equate.cpp",
+    "cxfa_equate.h",
+    "cxfa_equaterange.cpp",
+    "cxfa_equaterange.h",
+    "cxfa_era.cpp",
+    "cxfa_era.h",
+    "cxfa_eranames.cpp",
+    "cxfa_eranames.h",
+    "cxfa_event.cpp",
+    "cxfa_event.h",
+    "cxfa_exclgroup.cpp",
+    "cxfa_exclgroup.h",
+    "cxfa_exclude.cpp",
+    "cxfa_exclude.h",
+    "cxfa_excludens.cpp",
+    "cxfa_excludens.h",
+    "cxfa_exdata.cpp",
+    "cxfa_exdata.h",
+    "cxfa_execute.cpp",
+    "cxfa_execute.h",
+    "cxfa_exobject.cpp",
+    "cxfa_exobject.h",
+    "cxfa_extras.cpp",
+    "cxfa_extras.h",
+    "cxfa_field.cpp",
+    "cxfa_field.h",
+    "cxfa_fill.cpp",
+    "cxfa_fill.h",
+    "cxfa_filter.cpp",
+    "cxfa_filter.h",
+    "cxfa_fliplabel.cpp",
+    "cxfa_fliplabel.h",
+    "cxfa_float.cpp",
+    "cxfa_float.h",
+    "cxfa_font.cpp",
+    "cxfa_font.h",
+    "cxfa_fontinfo.cpp",
+    "cxfa_fontinfo.h",
+    "cxfa_form.cpp",
+    "cxfa_form.h",
+    "cxfa_format.cpp",
+    "cxfa_format.h",
+    "cxfa_formfieldfilling.cpp",
+    "cxfa_formfieldfilling.h",
+    "cxfa_groupparent.cpp",
+    "cxfa_groupparent.h",
+    "cxfa_handler.cpp",
+    "cxfa_handler.h",
+    "cxfa_hyphenation.cpp",
+    "cxfa_hyphenation.h",
+    "cxfa_ifempty.cpp",
+    "cxfa_ifempty.h",
+    "cxfa_image.cpp",
+    "cxfa_image.h",
+    "cxfa_imageedit.cpp",
+    "cxfa_imageedit.h",
+    "cxfa_includexdpcontent.cpp",
+    "cxfa_includexdpcontent.h",
+    "cxfa_incrementalload.cpp",
+    "cxfa_incrementalload.h",
+    "cxfa_incrementalmerge.cpp",
+    "cxfa_incrementalmerge.h",
+    "cxfa_insert.cpp",
+    "cxfa_insert.h",
+    "cxfa_instancemanager.cpp",
+    "cxfa_instancemanager.h",
+    "cxfa_integer.cpp",
+    "cxfa_integer.h",
+    "cxfa_interactive.cpp",
+    "cxfa_interactive.h",
+    "cxfa_issuers.cpp",
+    "cxfa_issuers.h",
+    "cxfa_items.cpp",
+    "cxfa_items.h",
+    "cxfa_jog.cpp",
+    "cxfa_jog.h",
+    "cxfa_keep.cpp",
+    "cxfa_keep.h",
+    "cxfa_keyusage.cpp",
+    "cxfa_keyusage.h",
+    "cxfa_labelprinter.cpp",
+    "cxfa_labelprinter.h",
+    "cxfa_layout.cpp",
+    "cxfa_layout.h",
+    "cxfa_level.cpp",
+    "cxfa_level.h",
+    "cxfa_line.cpp",
+    "cxfa_line.h",
+    "cxfa_linear.cpp",
+    "cxfa_linear.h",
+    "cxfa_linearized.cpp",
+    "cxfa_linearized.h",
+    "cxfa_list.cpp",
+    "cxfa_list.h",
+    "cxfa_locale.cpp",
+    "cxfa_locale.h",
+    "cxfa_localemgr.cpp",
+    "cxfa_localemgr.h",
+    "cxfa_localeset.cpp",
+    "cxfa_localeset.h",
+    "cxfa_localevalue.cpp",
+    "cxfa_localevalue.h",
+    "cxfa_lockdocument.cpp",
+    "cxfa_lockdocument.h",
+    "cxfa_log.cpp",
+    "cxfa_log.h",
+    "cxfa_manifest.cpp",
+    "cxfa_manifest.h",
+    "cxfa_map.cpp",
+    "cxfa_map.h",
+    "cxfa_margin.cpp",
+    "cxfa_margin.h",
+    "cxfa_mdp.cpp",
+    "cxfa_mdp.h",
+    "cxfa_measurement.cpp",
+    "cxfa_measurement.h",
+    "cxfa_medium.cpp",
+    "cxfa_medium.h",
+    "cxfa_mediuminfo.cpp",
+    "cxfa_mediuminfo.h",
+    "cxfa_meridiem.cpp",
+    "cxfa_meridiem.h",
+    "cxfa_meridiemnames.cpp",
+    "cxfa_meridiemnames.h",
+    "cxfa_message.cpp",
+    "cxfa_message.h",
+    "cxfa_messaging.cpp",
+    "cxfa_messaging.h",
+    "cxfa_mode.cpp",
+    "cxfa_mode.h",
+    "cxfa_modifyannots.cpp",
+    "cxfa_modifyannots.h",
+    "cxfa_month.cpp",
+    "cxfa_month.h",
+    "cxfa_monthnames.cpp",
+    "cxfa_monthnames.h",
+    "cxfa_msgid.cpp",
+    "cxfa_msgid.h",
+    "cxfa_nameattr.cpp",
+    "cxfa_nameattr.h",
+    "cxfa_neverembed.cpp",
+    "cxfa_neverembed.h",
+    "cxfa_node.cpp",
+    "cxfa_node.h",
+    "cxfa_nodehelper.cpp",
+    "cxfa_nodehelper.h",
+    "cxfa_nodeiteratortemplate.h",
+    "cxfa_nodelocale.cpp",
+    "cxfa_nodelocale.h",
+    "cxfa_nodeowner.cpp",
+    "cxfa_nodeowner.h",
+    "cxfa_numberofcopies.cpp",
+    "cxfa_numberofcopies.h",
+    "cxfa_numberpattern.cpp",
+    "cxfa_numberpattern.h",
+    "cxfa_numberpatterns.cpp",
+    "cxfa_numberpatterns.h",
+    "cxfa_numbersymbol.cpp",
+    "cxfa_numbersymbol.h",
+    "cxfa_numbersymbols.cpp",
+    "cxfa_numbersymbols.h",
+    "cxfa_numericedit.cpp",
+    "cxfa_numericedit.h",
+    "cxfa_object.cpp",
+    "cxfa_object.h",
+    "cxfa_occur.cpp",
+    "cxfa_occur.h",
+    "cxfa_oid.cpp",
+    "cxfa_oid.h",
+    "cxfa_oids.cpp",
+    "cxfa_oids.h",
+    "cxfa_openaction.cpp",
+    "cxfa_openaction.h",
+    "cxfa_operation.cpp",
+    "cxfa_operation.h",
+    "cxfa_output.cpp",
+    "cxfa_output.h",
+    "cxfa_outputbin.cpp",
+    "cxfa_outputbin.h",
+    "cxfa_outputxsl.cpp",
+    "cxfa_outputxsl.h",
+    "cxfa_overflow.cpp",
+    "cxfa_overflow.h",
+    "cxfa_overprint.cpp",
+    "cxfa_overprint.h",
+    "cxfa_packet.cpp",
+    "cxfa_packet.h",
+    "cxfa_packets.cpp",
+    "cxfa_packets.h",
+    "cxfa_pagearea.cpp",
+    "cxfa_pagearea.h",
+    "cxfa_pageoffset.cpp",
+    "cxfa_pageoffset.h",
+    "cxfa_pagerange.cpp",
+    "cxfa_pagerange.h",
+    "cxfa_pageset.cpp",
+    "cxfa_pageset.h",
+    "cxfa_pagination.cpp",
+    "cxfa_pagination.h",
+    "cxfa_paginationoverride.cpp",
+    "cxfa_paginationoverride.h",
+    "cxfa_para.cpp",
+    "cxfa_para.h",
+    "cxfa_part.cpp",
+    "cxfa_part.h",
+    "cxfa_password.cpp",
+    "cxfa_password.h",
+    "cxfa_passwordedit.cpp",
+    "cxfa_passwordedit.h",
+    "cxfa_pattern.cpp",
+    "cxfa_pattern.h",
+    "cxfa_pcl.cpp",
+    "cxfa_pcl.h",
+    "cxfa_pdf.cpp",
+    "cxfa_pdf.h",
+    "cxfa_pdfa.cpp",
+    "cxfa_pdfa.h",
+    "cxfa_permissions.cpp",
+    "cxfa_permissions.h",
+    "cxfa_picktraybypdfsize.cpp",
+    "cxfa_picktraybypdfsize.h",
+    "cxfa_picture.cpp",
+    "cxfa_picture.h",
+    "cxfa_plaintextmetadata.cpp",
+    "cxfa_plaintextmetadata.h",
+    "cxfa_presence.cpp",
+    "cxfa_presence.h",
+    "cxfa_present.cpp",
+    "cxfa_present.h",
+    "cxfa_print.cpp",
+    "cxfa_print.h",
+    "cxfa_printername.cpp",
+    "cxfa_printername.h",
+    "cxfa_printhighquality.cpp",
+    "cxfa_printhighquality.h",
+    "cxfa_printscaling.cpp",
+    "cxfa_printscaling.h",
+    "cxfa_producer.cpp",
+    "cxfa_producer.h",
+    "cxfa_proto.cpp",
+    "cxfa_proto.h",
+    "cxfa_ps.cpp",
+    "cxfa_ps.h",
+    "cxfa_psmap.cpp",
+    "cxfa_psmap.h",
+    "cxfa_query.cpp",
+    "cxfa_query.h",
+    "cxfa_radial.cpp",
+    "cxfa_radial.h",
+    "cxfa_range.cpp",
+    "cxfa_range.h",
+    "cxfa_reason.cpp",
+    "cxfa_reason.h",
+    "cxfa_reasons.cpp",
+    "cxfa_reasons.h",
+    "cxfa_record.cpp",
+    "cxfa_record.h",
+    "cxfa_recordset.cpp",
+    "cxfa_recordset.h",
+    "cxfa_rectangle.cpp",
+    "cxfa_rectangle.h",
+    "cxfa_ref.cpp",
+    "cxfa_ref.h",
+    "cxfa_relevant.cpp",
+    "cxfa_relevant.h",
+    "cxfa_rename.cpp",
+    "cxfa_rename.h",
+    "cxfa_renderpolicy.cpp",
+    "cxfa_renderpolicy.h",
+    "cxfa_rootelement.cpp",
+    "cxfa_rootelement.h",
+    "cxfa_runscripts.cpp",
+    "cxfa_runscripts.h",
+    "cxfa_script.cpp",
+    "cxfa_script.h",
+    "cxfa_scriptmodel.cpp",
+    "cxfa_scriptmodel.h",
+    "cxfa_select.cpp",
+    "cxfa_select.h",
+    "cxfa_setproperty.cpp",
+    "cxfa_setproperty.h",
+    "cxfa_severity.cpp",
+    "cxfa_severity.h",
+    "cxfa_sharptext.cpp",
+    "cxfa_sharptext.h",
+    "cxfa_sharpxhtml.cpp",
+    "cxfa_sharpxhtml.h",
+    "cxfa_sharpxml.cpp",
+    "cxfa_sharpxml.h",
+    "cxfa_signature.cpp",
+    "cxfa_signature.h",
+    "cxfa_signatureproperties.cpp",
+    "cxfa_signatureproperties.h",
+    "cxfa_signdata.cpp",
+    "cxfa_signdata.h",
+    "cxfa_signing.cpp",
+    "cxfa_signing.h",
+    "cxfa_silentprint.cpp",
+    "cxfa_silentprint.h",
+    "cxfa_soapaction.cpp",
+    "cxfa_soapaction.h",
+    "cxfa_soapaddress.cpp",
+    "cxfa_soapaddress.h",
+    "cxfa_solid.cpp",
+    "cxfa_solid.h",
+    "cxfa_source.cpp",
+    "cxfa_source.h",
+    "cxfa_sourceset.cpp",
+    "cxfa_sourceset.h",
+    "cxfa_speak.cpp",
+    "cxfa_speak.h",
+    "cxfa_staple.cpp",
+    "cxfa_staple.h",
+    "cxfa_startnode.cpp",
+    "cxfa_startnode.h",
+    "cxfa_startpage.cpp",
+    "cxfa_startpage.h",
+    "cxfa_stipple.cpp",
+    "cxfa_stipple.h",
+    "cxfa_stroke.cpp",
+    "cxfa_stroke.h",
+    "cxfa_subform.cpp",
+    "cxfa_subform.h",
+    "cxfa_subformset.cpp",
+    "cxfa_subformset.h",
+    "cxfa_subjectdn.cpp",
+    "cxfa_subjectdn.h",
+    "cxfa_subjectdns.cpp",
+    "cxfa_subjectdns.h",
+    "cxfa_submit.cpp",
+    "cxfa_submit.h",
+    "cxfa_submitformat.cpp",
+    "cxfa_submitformat.h",
+    "cxfa_submiturl.cpp",
+    "cxfa_submiturl.h",
+    "cxfa_subsetbelow.cpp",
+    "cxfa_subsetbelow.h",
+    "cxfa_suppressbanner.cpp",
+    "cxfa_suppressbanner.h",
+    "cxfa_tagged.cpp",
+    "cxfa_tagged.h",
+    "cxfa_template.cpp",
+    "cxfa_template.h",
+    "cxfa_templatecache.cpp",
+    "cxfa_templatecache.h",
+    "cxfa_text.cpp",
+    "cxfa_text.h",
+    "cxfa_textedit.cpp",
+    "cxfa_textedit.h",
+    "cxfa_thisproxy.cpp",
+    "cxfa_thisproxy.h",
+    "cxfa_threshold.cpp",
+    "cxfa_threshold.h",
+    "cxfa_time.cpp",
+    "cxfa_time.h",
+    "cxfa_timepattern.cpp",
+    "cxfa_timepattern.h",
+    "cxfa_timepatterns.cpp",
+    "cxfa_timepatterns.h",
+    "cxfa_timestamp.cpp",
+    "cxfa_timestamp.h",
+    "cxfa_timezoneprovider.cpp",
+    "cxfa_timezoneprovider.h",
+    "cxfa_to.cpp",
+    "cxfa_to.h",
+    "cxfa_tooltip.cpp",
+    "cxfa_tooltip.h",
+    "cxfa_trace.cpp",
+    "cxfa_trace.h",
+    "cxfa_transform.cpp",
+    "cxfa_transform.h",
+    "cxfa_traversal.cpp",
+    "cxfa_traversal.h",
+    "cxfa_traverse.cpp",
+    "cxfa_traverse.h",
+    "cxfa_traversestrategy_xfacontainernode.h",
+    "cxfa_traversestrategy_xfanode.h",
+    "cxfa_treelist.cpp",
+    "cxfa_treelist.h",
+    "cxfa_type.cpp",
+    "cxfa_type.h",
+    "cxfa_typeface.cpp",
+    "cxfa_typeface.h",
+    "cxfa_typefaces.cpp",
+    "cxfa_typefaces.h",
+    "cxfa_ui.cpp",
+    "cxfa_ui.h",
+    "cxfa_update.cpp",
+    "cxfa_update.h",
+    "cxfa_uri.cpp",
+    "cxfa_uri.h",
+    "cxfa_user.cpp",
+    "cxfa_user.h",
+    "cxfa_validate.cpp",
+    "cxfa_validate.h",
+    "cxfa_validateapprovalsignatures.cpp",
+    "cxfa_validateapprovalsignatures.h",
+    "cxfa_validationmessaging.cpp",
+    "cxfa_validationmessaging.h",
+    "cxfa_value.cpp",
+    "cxfa_value.h",
+    "cxfa_variables.cpp",
+    "cxfa_variables.h",
+    "cxfa_version.cpp",
+    "cxfa_version.h",
+    "cxfa_versioncontrol.cpp",
+    "cxfa_versioncontrol.h",
+    "cxfa_viewerpreferences.cpp",
+    "cxfa_viewerpreferences.h",
+    "cxfa_webclient.cpp",
+    "cxfa_webclient.h",
+    "cxfa_whitespace.cpp",
+    "cxfa_whitespace.h",
+    "cxfa_window.cpp",
+    "cxfa_window.h",
+    "cxfa_wsdladdress.cpp",
+    "cxfa_wsdladdress.h",
+    "cxfa_wsdlconnection.cpp",
+    "cxfa_wsdlconnection.h",
+    "cxfa_xdc.cpp",
+    "cxfa_xdc.h",
+    "cxfa_xdp.cpp",
+    "cxfa_xdp.h",
+    "cxfa_xfa.cpp",
+    "cxfa_xfa.h",
+    "cxfa_xmlconnection.cpp",
+    "cxfa_xmlconnection.h",
+    "cxfa_xmllocale.cpp",
+    "cxfa_xmllocale.h",
+    "cxfa_xsdconnection.cpp",
+    "cxfa_xsdconnection.h",
+    "cxfa_xsl.cpp",
+    "cxfa_xsl.h",
+    "cxfa_zpl.cpp",
+    "cxfa_zpl.h",
+    "xfa_basic_data.cpp",
+    "xfa_basic_data.h",
+    "xfa_document_datamerger_imp.cpp",
+    "xfa_document_datamerger_imp.h",
+    "xfa_resolvenode_rs.h",
+    "xfa_utils.cpp",
+    "xfa_utils.h",
+  ]
+  deps = [
+    "../../../core/fxcodec",
+    "../../../core/fxcrt",
+    "../../../core/fxge",
+    "../../../fxjs",
+    "../../fde",
+    "../../fgas",
+    "../../fxgraphics",
+  ]
+  allow_circular_includes_from = [ "../../../fxjs" ]
+  configs += [
+    "../../../:pdfium_core_config",
+    "../../:xfa_warnings",
+  ]
+  visibility = [ "../../../*" ]
+}
+
+pdfium_unittest_source_set("unittests") {
+  sources = [
+    "cxfa_document_parser_unittest.cpp",
+    "cxfa_localevalue_unittest.cpp",
+    "cxfa_measurement_unittest.cpp",
+    "cxfa_node_unittest.cpp",
+    "cxfa_nodeiteratortemplate_unittest.cpp",
+    "cxfa_xmllocale_unittest.cpp",
+    "xfa_basic_data_unittest.cpp",
+    "xfa_utils_unittest.cpp",
+  ]
+  deps = [
+    ":parser",
+    "../../../fxjs",
+  ]
+  pdfium_root_dir = "../../../"
+}
+
+pdfium_embeddertest_source_set("embeddertests") {
+  sources = [ "cxfa_document_parser_embeddertest.cpp" ]
+  pdfium_root_dir = "../../../"
+}
diff --git a/xfa/fxfa/parser/DEPS b/xfa/fxfa/parser/DEPS
new file mode 100644
index 0000000..22337ef
--- /dev/null
+++ b/xfa/fxfa/parser/DEPS
@@ -0,0 +1,5 @@
+include_rules = [
+  # xfa/fwl should be standalone. https://crbug.com/pdfium/507
+  '-xfa/fwl',
+]
+
diff --git a/xfa/fxfa/parser/attribute_values.inc b/xfa/fxfa/parser/attribute_values.inc
new file mode 100644
index 0000000..6cfdadf
--- /dev/null
+++ b/xfa/fxfa/parser/attribute_values.inc
@@ -0,0 +1,272 @@
+// Copyright 2018 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
+
+VALUE____(0x0000002au, "*", Asterisk)
+VALUE____(0x0000002fu, "/", Slash)
+VALUE____(0x0000005cu, "\\", Backslash)
+VALUE____(0x000239bdu, "on", On)
+VALUE____(0x00025356u, "tb", Tb)
+VALUE____(0x00025885u, "up", Up)
+VALUE____(0x0091b281u, "metaData", MetaData)
+VALUE____(0x01f8dedbu, "delegate", Delegate)
+VALUE____(0x02a6c55au, "postSubmit", PostSubmit)
+VALUE____(0x031b19c1u, "name", Name)
+VALUE____(0x0378a38au, "cross", Cross)
+VALUE____(0x03848b3fu, "next", Next)
+VALUE____(0x048b6670u, "none", None)
+VALUE____(0x051aafe5u, "shortEdge", ShortEdge)
+VALUE____(0x055264c4u, "1mod10_1mod11", Checksum_1mod10_1mod11)
+VALUE____(0x05a5c519u, "height", Height)
+VALUE____(0x089ce549u, "crossDiagonal", CrossDiagonal)
+VALUE____(0x09f9d0f9u, "all", All)
+VALUE____(0x09f9db48u, "any", Any)
+VALUE____(0x0a126261u, "toRight", ToRight)
+VALUE____(0x0a36de29u, "matchTemplate", MatchTemplate)
+VALUE____(0x0a48d040u, "dpl", Dpl)
+VALUE____(0x0a559c05u, "invisible", Invisible)
+VALUE____(0x0a7d48e3u, "fit", Fit)
+VALUE____(0x0a8a8f80u, "width", Width)
+VALUE____(0x0ab466bbu, "preSubmit", PreSubmit)
+VALUE____(0x0acc5785u, "ipl", Ipl)
+VALUE____(0x0afab0f8u, "flateCompress", FlateCompress)
+VALUE____(0x0b355816u, "med", Med)
+VALUE____(0x0b69ef77u, "odd", Odd)
+VALUE____(0x0b69f9bbu, "off", Off)
+VALUE____(0x0b843dbau, "pdf", Pdf)
+VALUE____(0x0bb912b8u, "row", Row)
+VALUE____(0x0bedaf33u, "top", Top)
+VALUE____(0x0c56afccu, "xdp", Xdp)
+VALUE____(0x0c56ba02u, "xfd", Xfd)
+VALUE____(0x0c56ddf1u, "xml", Xml)
+VALUE____(0x0c8b65f3u, "zip", Zip)
+VALUE____(0x0c8b89d6u, "zpl", Zpl)
+VALUE____(0x0f55d7eeu, "visible", Visible)
+VALUE____(0x0fe3596au, "exclude", Exclude)
+VALUE____(0x109d7ce7u, "mouseEnter", MouseEnter)
+VALUE____(0x10f1bc0cu, "pair", Pair)
+VALUE____(0x1154efe6u, "filter", Filter)
+VALUE____(0x125bc94bu, "moveLast", MoveLast)
+VALUE____(0x12e1f1f0u, "exportAndImport", ExportAndImport)
+VALUE____(0x13000c60u, "push", Push)
+VALUE____(0x138ee315u, "portrait", Portrait)
+VALUE____(0x14da2125u, "default", Default)
+VALUE____(0x157749a5u, "storedProc", StoredProc)
+VALUE____(0x16641198u, "stayBOF", StayBOF)
+VALUE____(0x16b2fc5bu, "stayEOF", StayEOF)
+VALUE____(0x17fad373u, "postPrint", PostPrint)
+VALUE____(0x193207d0u, "usCarrier", UsCarrier)
+VALUE____(0x193ade3eu, "right", Right)
+VALUE____(0x1bfc72d9u, "preOpen", PreOpen)
+VALUE____(0x1cc9317au, "actual", Actual)
+VALUE____(0x1f31df1eu, "rest", Rest)
+VALUE____(0x1fb1bf14u, "topCenter", TopCenter)
+VALUE____(0x207de667u, "standardSymbol", StandardSymbol)
+VALUE____(0x2196a452u, "initialize", Initialize)
+VALUE____(0x23bd40c7u, "justifyAll", JustifyAll)
+VALUE____(0x247cf3e9u, "normal", Normal)
+VALUE____(0x25aa946bu, "landscape", Landscape)
+VALUE____(0x2739b5c9u, "nonInteractive", NonInteractive)
+VALUE____(0x27410f03u, "mouseExit", MouseExit)
+VALUE____(0x2854e62cu, "minus", Minus)
+VALUE____(0x287e936au, "diagonalLeft", DiagonalLeft)
+VALUE____(0x2972a98fu, "simplexPaginated", SimplexPaginated)
+VALUE____(0x29d8225fu, "document", Document)
+VALUE____(0x2a9d3016u, "warning", Warning)
+VALUE____(0x2b35b6d9u, "auto", Auto)
+VALUE____(0x2c1653d9u, "below", Below)
+VALUE____(0x2c1f0540u, "bottomLeft", BottomLeft)
+VALUE____(0x2c44e816u, "bottomCenter", BottomCenter)
+VALUE____(0x2cd3e9f3u, "tcpl", Tcpl)
+VALUE____(0x2d08af85u, "text", Text)
+VALUE____(0x2dc478ebu, "grouping", Grouping)
+VALUE____(0x2ef3afddu, "secureSymbol", SecureSymbol)
+VALUE____(0x2f2dd29au, "preExecute", PreExecute)
+VALUE____(0x33c43decu, "docClose", DocClose)
+VALUE____(0x33f25bb5u, "keyset", Keyset)
+VALUE____(0x34e363dau, "vertical", Vertical)
+VALUE____(0x361fa1b6u, "preSave", PreSave)
+VALUE____(0x36f1c6d8u, "preSign", PreSign)
+VALUE____(0x399f02b5u, "bottom", Bottom)
+VALUE____(0x3b0ab096u, "toTop", ToTop)
+VALUE____(0x3c752495u, "verify", Verify)
+VALUE____(0x3ce05d68u, "first", First)
+VALUE____(0x3ecead94u, "contentArea", ContentArea)
+VALUE____(0x40623b5bu, "solid", Solid)
+VALUE____(0x42c6cd8du, "pessimistic", Pessimistic)
+VALUE____(0x43ddc6bfu, "duplexPaginated", DuplexPaginated)
+VALUE____(0x442f68c8u, "round", Round)
+VALUE____(0x45efb847u, "remerge", Remerge)
+VALUE____(0x46972265u, "ordered", Ordered)
+VALUE____(0x46f95531u, "percent", Percent)
+VALUE____(0x46fd25aeu, "even", Even)
+VALUE____(0x4731d6bau, "exit", Exit)
+VALUE____(0x4977356bu, "toolTip", ToolTip)
+VALUE____(0x49b980eeu, "orderedOccurrence", OrderedOccurrence)
+VALUE____(0x4a7e2dfeu, "readOnly", ReadOnly)
+VALUE____(0x4c4e8acbu, "currency", Currency)
+VALUE____(0x4dcf25f8u, "concat", Concat)
+VALUE____(0x4febb826u, "Thai", Thai)
+VALUE____(0x50ef95b2u, "embossed", Embossed)
+VALUE____(0x516e35ceu, "formdata", Formdata)
+VALUE____(0x52fa6f0eu, "Greek", Greek)
+VALUE____(0x54034c2fu, "decimal", Decimal)
+VALUE____(0x542c7300u, "select", Select)
+VALUE____(0x551f0ae5u, "longEdge", LongEdge)
+VALUE____(0x55520a8au, "protected", Protected)
+VALUE____(0x559f76f3u, "bottomRight", BottomRight)
+VALUE____(0x568cb500u, "zero", Zero)
+VALUE____(0x56bcecb7u, "forwardOnly", ForwardOnly)
+VALUE____(0x56bf456bu, "docReady", DocReady)
+VALUE____(0x573cb40cu, "hidden", Hidden)
+VALUE____(0x582e3424u, "include", Include)
+VALUE____(0x58a3dd29u, "dashed", Dashed)
+VALUE____(0x5955b22bu, "multiSelect", MultiSelect)
+VALUE____(0x598d5c53u, "inactive", Inactive)
+VALUE____(0x59c8f27du, "embed", Embed)
+VALUE____(0x5e7555e8u, "static", Static)
+VALUE____(0x606d4defu, "onEntry", OnEntry)
+VALUE____(0x6195eafbu, "Cyrillic", Cyrillic)
+VALUE____(0x6491b0f3u, "nonBlank", NonBlank)
+VALUE____(0x67bef031u, "topRight", TopRight)
+VALUE____(0x67df5ebdu, "Hebrew", Hebrew)
+VALUE____(0x6aea98beu, "topLeft", TopLeft)
+VALUE____(0x6c51afc1u, "center", Center)
+VALUE____(0x7145e6bfu, "moveFirst", MoveFirst)
+VALUE____(0x7375465cu, "diamond", Diamond)
+VALUE____(0x7461aef4u, "pageOdd", PageOdd)
+VALUE____(0x75f8aeb2u, "1mod10", Checksum_1mod10)
+VALUE____(0x76d708e0u, "Korean", Korean)
+VALUE____(0x789f14d7u, "aboveEmbedded", AboveEmbedded)
+VALUE____(0x792ea39fu, "zipCompress", ZipCompress)
+VALUE____(0x7a5b7193u, "numeric", Numeric)
+VALUE____(0x7abec0d2u, "circle", Circle)
+VALUE____(0x7afbba38u, "toBottom", ToBottom)
+VALUE____(0x7b95e661u, "inverted", Inverted)
+VALUE____(0x7baca2e3u, "update", Update)
+VALUE____(0x7eb5da2cu, "isoname", Isoname)
+VALUE____(0x7f6fd3d7u, "server", Server)
+VALUE____(0x814f82b5u, "position", Position)
+VALUE____(0x82deacf0u, "middleCenter", MiddleCenter)
+VALUE____(0x83a49dc6u, "optional", Optional)
+VALUE____(0x861a116fu, "usePrinterSetting", UsePrinterSetting)
+VALUE____(0x86701ce0u, "outline", Outline)
+VALUE____(0x8808385eu, "indexChange", IndexChange)
+VALUE____(0x891f4606u, "change", Change)
+VALUE____(0x89939f36u, "pageArea", PageArea)
+VALUE____(0x8b5c3b25u, "once", Once)
+VALUE____(0x8b5c6962u, "only", Only)
+VALUE____(0x8b90e1f2u, "open", Open)
+VALUE____(0x8bcfe96eu, "caption", Caption)
+VALUE____(0x8ce83ef8u, "raised", Raised)
+VALUE____(0x8d269caeu, "justify", Justify)
+VALUE____(0x8fd520dcu, "refAndDescendants", RefAndDescendants)
+VALUE____(0x9041d4b0u, "short", Short)
+VALUE____(0x90c94426u, "pageFront", PageFront)
+VALUE____(0x936beee5u, "monospace", Monospace)
+VALUE____(0x947fa00fu, "middle", Middle)
+VALUE____(0x9528a7b4u, "prePrint", PrePrint)
+VALUE____(0x959ab231u, "always", Always)
+VALUE____(0x96d61bf0u, "unknown", Unknown)
+VALUE____(0x997194eeu, "toLeft", ToLeft)
+VALUE____(0x9a83a3cdu, "above", Above)
+VALUE____(0x9d0d71c7u, "dashDot", DashDot)
+VALUE____(0x9df56f3eu, "gregorian", Gregorian)
+VALUE____(0x9f6723fdu, "Roman", Roman)
+VALUE____(0x9f693b21u, "mouseDown", MouseDown)
+VALUE____(0xa1429b36u, "symbol", Symbol)
+VALUE____(0xa5aa45cbu, "pageEven", PageEven)
+VALUE____(0xa68635f1u, "sign", Sign)
+VALUE____(0xa7315093u, "addNew", AddNew)
+VALUE____(0xa7a773fau, "star", Star)
+VALUE____(0xa7d57b45u, "optimistic", Optimistic)
+VALUE____(0xa8077321u, "rl-tb", Rl_tb)
+VALUE____(0xa8f1468du, "middleRight", MiddleRight)
+VALUE____(0xaa84a1f1u, "maintain", Maintain)
+VALUE____(0xab40b12cu, "package", Package)
+VALUE____(0xac8b4d85u, "SimplifiedChinese", SimplifiedChinese)
+VALUE____(0xadae6744u, "toCenter", ToCenter)
+VALUE____(0xb0129df1u, "back", Back)
+VALUE____(0xb0f088cfu, "unspecified", Unspecified)
+VALUE____(0xb1271067u, "batchOptimistic", BatchOptimistic)
+VALUE____(0xb18313a1u, "bold", Bold)
+VALUE____(0xb1833cadu, "both", Both)
+VALUE____(0xb221123fu, "butt", Butt)
+VALUE____(0xb40c36bfu, "client", Client)
+VALUE____(0xb56c7053u, "2mod10", Checksum_2mod10)
+VALUE____(0xb683a345u, "imageOnly", ImageOnly)
+VALUE____(0xb7732deau, "horizontal", Horizontal)
+VALUE____(0xb88652a4u, "dotted", Dotted)
+VALUE____(0xbb2f2880u, "userControl", UserControl)
+VALUE____(0xbbb79c5du, "diagonalRight", DiagonalRight)
+VALUE____(0xbd077154u, "consumeData", ConsumeData)
+VALUE____(0xbd3fb11eu, "check", Check)
+VALUE____(0xbde9abdau, "data", Data)
+VALUE____(0xbf5a02d8u, "down", Down)
+VALUE____(0xbf7450eeu, "sansSerif", SansSerif)
+VALUE____(0xc02d649fu, "inline", Inline)
+VALUE____(0xc11a9e3au, "TraditionalChinese", TraditionalChinese)
+VALUE____(0xc16169d8u, "warn", Warn)
+VALUE____(0xc16f071fu, "refOnly", RefOnly)
+VALUE____(0xc27c8ba5u, "interactiveForms", InteractiveForms)
+VALUE____(0xc2d1b15cu, "word", Word)
+VALUE____(0xc3621288u, "unordered", Unordered)
+VALUE____(0xc5251981u, "required", Required)
+VALUE____(0xc7088e7du, "importOnly", ImportOnly)
+VALUE____(0xc72cf0e3u, "belowEmbedded", BelowEmbedded)
+VALUE____(0xc819cf07u, "Japanese", Japanese)
+VALUE____(0xcdce56b3u, "full", Full)
+VALUE____(0xce0122e3u, "rl-row", Rl_row)
+VALUE____(0xcf7d71f1u, "Vietnamese", Vietnamese)
+VALUE____(0xcfde3e09u, "EastEuropeanRoman", EastEuropeanRoman)
+VALUE____(0xd576d08eu, "mouseUp", MouseUp)
+VALUE____(0xd7a92904u, "exportOnly", ExportOnly)
+VALUE____(0xd8ed1467u, "clear", Clear)
+VALUE____(0xd95657a6u, "click", Click)
+VALUE____(0xd96c7de5u, "base64", Base64)
+VALUE____(0xd9f47f36u, "close", Close)
+VALUE____(0xdb075bdeu, "host", Host)
+VALUE____(0xdb103411u, "global", Global)
+VALUE____(0xdb647188u, "blank", Blank)
+VALUE____(0xdb9be968u, "table", Table)
+VALUE____(0xdf590fbbu, "import", Import)
+VALUE____(0xe0e573fbu, "custom", Custom)
+VALUE____(0xe0ecc79au, "middleLeft", MiddleLeft)
+VALUE____(0xe1452019u, "postExecute", PostExecute)
+VALUE____(0xe1911d98u, "radix", Radix)
+VALUE____(0xe25fa7b8u, "postOpen", PostOpen)
+VALUE____(0xe28dce7eu, "enter", Enter)
+VALUE____(0xe2c44de4u, "ignore", Ignore)
+VALUE____(0xe2cd8c61u, "lr-tb", Lr_tb)
+VALUE____(0xe2da8336u, "fantasy", Fantasy)
+VALUE____(0xe31d5396u, "italic", Italic)
+VALUE____(0xe7ada113u, "author", Author)
+VALUE____(0xe8e7cc18u, "toEdge", ToEdge)
+VALUE____(0xe97aa98bu, "choice", Choice)
+VALUE____(0xeafd2a38u, "disabled", Disabled)
+VALUE____(0xeb2b7972u, "crossHatch", CrossHatch)
+VALUE____(0xeb2db2d7u, "dataRef", DataRef)
+VALUE____(0xec35dc6eu, "dashDotDot", DashDotDot)
+VALUE____(0xef85d351u, "square", Square)
+VALUE____(0xf2102445u, "dynamic", Dynamic)
+VALUE____(0xf272c7beu, "manual", Manual)
+VALUE____(0xf2bbb64du, "etched", Etched)
+VALUE____(0xf3b8fc6cu, "validationState", ValidationState)
+VALUE____(0xf42f2b81u, "cursive", Cursive)
+VALUE____(0xf54481d4u, "last", Last)
+VALUE____(0xf5ad782bu, "left", Left)
+VALUE____(0xf616da2eu, "link", Link)
+VALUE____(0xf6b4afb0u, "long", Long)
+VALUE____(0xf8636460u, "internationalCarrier", InternationalCarrier)
+VALUE____(0xf9fb37acu, "PDF1.3", PDF1_3)
+VALUE____(0xf9fb37afu, "PDF1.6", PDF1_6)
+VALUE____(0xfbce7f19u, "serif", Serif)
+VALUE____(0xfc82d695u, "postSave", PostSave)
+VALUE____(0xfcef86b5u, "ready", Ready)
+VALUE____(0xfd54fbb7u, "postSign", PostSign)
+VALUE____(0xfdc0aae2u, "Arabic", Arabic)
+VALUE____(0xfe06d2cau, "error", Error)
+VALUE____(0xfefc4885u, "urlencoded", Urlencoded)
+VALUE____(0xff795ad2u, "lowered", Lowered)
diff --git a/xfa/fxfa/parser/attributes.inc b/xfa/fxfa/parser/attributes.inc
new file mode 100644
index 0000000..7cc28e4
--- /dev/null
+++ b/xfa/fxfa/parser/attributes.inc
@@ -0,0 +1,318 @@
+// Copyright 2018 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
+
+ATTR____(0x00000068u, "h", H, Basic)
+ATTR____(0x00000077u, "w", W, Basic)
+ATTR____(0x00000078u, "x", X, Basic)
+ATTR____(0x00000079u, "y", Y, Basic)
+ATTR____(0x00020146u, "db", Db, Basic)
+ATTR____(0x00021aedu, "id", Id, Basic)
+ATTR____(0x000234a1u, "ns", Ns, Basic)
+ATTR____(0x00025363u, "to", To, Basic)
+ATTR____(0x00cb0ac9u, "lineThrough", LineThrough, Basic)
+ATTR____(0x02282c73u, "hAlign", HAlign, Basic)
+ATTR____(0x02c1c7f1u, "typeface", Typeface, Basic)
+ATTR____(0x03106c3au, "beforeTarget", BeforeTarget, Basic)
+ATTR____(0x031b19c1u, "name", Name, Basic)
+ATTR____(0x03848b3fu, "next", Next, Basic)
+ATTR____(0x043e349bu, "dataRowCount", DataRowCount, Basic)
+ATTR____(0x05518c25u, "break", Break, Basic)
+ATTR____(0x05ce6195u, "vScrollPolicy", VScrollPolicy, Basic)
+ATTR____(0x066c1ae9u, "validationsEnabled", ValidationsEnabled, Basic)
+ATTR____(0x08c74ae9u, "fontHorizontalScale", FontHorizontalScale, Basic)
+ATTR____(0x08d4f1c7u, "textIndent", TextIndent, Basic)
+ATTR____(0x097be91bu, "content", Content, Basic)
+ATTR____(0x097c1c65u, "context", Context, Object)
+ATTR____(0x09876578u, "trayOut", TrayOut, Basic)
+ATTR____(0x09f9d0f9u, "all", All, Object)
+ATTR____(0x0a2e3514u, "cap", Cap, Basic)
+ATTR____(0x0b3543a6u, "max", Max, Basic)
+ATTR____(0x0b356ca4u, "min", Min, Basic)
+ATTR____(0x0bb8df5du, "ref", Ref, Basic)
+ATTR____(0x0bb8f3dfu, "rid", Rid, Basic)
+ATTR____(0x0c080cd3u, "url", Url, Basic)
+ATTR____(0x0c0811edu, "use", Use, Basic)
+ATTR____(0x0cfea02eu, "leftInset", LeftInset, Basic)
+ATTR____(0x0d843798u, "fullText", FullText, Basic)
+ATTR____(0x0f23332fu, "errorText", ErrorText, Basic)
+ATTR____(0x0fb67185u, "recordsBefore", RecordsBefore, Basic)
+ATTR____(0x1026c59du, "widows", Widows, Basic)
+ATTR____(0x1059ec18u, "level", Level, Basic)
+ATTR____(0x1356caf8u, "bottomInset", BottomInset, Basic)
+ATTR____(0x13a08bdbu, "overflowTarget", OverflowTarget, Basic)
+ATTR____(0x1414d431u, "allowMacro", AllowMacro, Basic)
+ATTR____(0x14a32d52u, "pagePosition", PagePosition, Basic)
+ATTR____(0x14d04502u, "title", Title, Basic)
+ATTR____(0x1517dfa1u, "columnWidths", ColumnWidths, Basic)
+ATTR____(0x169134a1u, "overflowLeader", OverflowLeader, Basic)
+ATTR____(0x1abbd7e0u, "dataNode", DataNode, Object)
+ATTR____(0x1b6d1cf5u, "reenter", Reenter, Basic)
+ATTR____(0x1b8dce3eu, "action", Action, Basic)
+ATTR____(0x1e459b8fu, "nonRepudiation", NonRepudiation, Basic)
+ATTR____(0x1e6ffa9au, "prevContentType", PrevContentType, Basic)
+ATTR____(0x1ec8ab2cu, "rate", Rate, Basic)
+ATTR____(0x1ee2d24du, "instanceIndex", InstanceIndex, Basic)
+ATTR____(0x1ef3a64au, "allowRichText", AllowRichText, Basic)
+ATTR____(0x2038c9b2u, "role", Role, Basic)
+ATTR____(0x20914367u, "overflowTrailer", OverflowTrailer, Basic)
+ATTR____(0x21d5dfcbu, "currentRecordNumber", CurrentRecordNumber, Basic)
+ATTR____(0x226ca8f1u, "operation", Operation, Basic)
+ATTR____(0x24d85167u, "timeout", Timeout, Basic)
+ATTR____(0x25764436u, "topInset", TopInset, Basic)
+ATTR____(0x25839852u, "access", Access, Basic)
+ATTR____(0x25a3c206u, "soapFaultString", SoapFaultString, Basic)
+ATTR____(0x268b7ec1u, "commandType", CommandType, Basic)
+ATTR____(0x28dee6e9u, "format", Format, Basic)
+ATTR____(0x28e17e91u, "dataPrep", DataPrep, Basic)
+ATTR____(0x292b88feu, "widgetData", WidgetData, Basic)
+ATTR____(0x29418bb7u, "abbr", Abbr, Basic)
+ATTR____(0x2a82d99cu, "marginRight", MarginRight, Basic)
+ATTR____(0x2b5df51eu, "dataDescription", DataDescription, Basic)
+ATTR____(0x2bb3f470u, "encipherOnly", EncipherOnly, Basic)
+ATTR____(0x2cd79033u, "kerningMode", KerningMode, Basic)
+ATTR____(0x2d574d58u, "this", ThisValue, Object)
+ATTR____(0x2e00c007u, "newContentType", NewContentType, Basic)
+ATTR____(0x2ee7678fu, "rotate", Rotate, Basic)
+ATTR____(0x2f105f72u, "wordCharacterCount", WordCharacterCount, Basic)
+ATTR____(0x2f16a382u, "type", Type, Basic)
+ATTR____(0x312af044u, "recordsAfter", RecordsAfter, Basic)
+ATTR____(0x34ae103cu, "reserve", Reserve, Basic)
+ATTR____(0x3650557eu, "textLocation", TextLocation, Basic)
+ATTR____(0x392ae445u, "platform", Platform, Basic)
+ATTR____(0x39cdb0a2u, "priority", Priority, Basic)
+ATTR____(0x3a0273a6u, "underline", Underline, Basic)
+ATTR____(0x3b1ddd06u, "fillColor", FillColor, Basic)
+ATTR____(0x3b582286u, "moduleWidth", ModuleWidth, Basic)
+ATTR____(0x3d123c26u, "hyphenate", Hyphenate, Basic)
+ATTR____(0x3e7af94fu, "listen", Listen, Basic)
+ATTR____(0x4156ee3fu, "delimiter", Delimiter, Basic)
+ATTR____(0x42fed1fdu, "contentType", ContentType, Basic)
+ATTR____(0x453eaf38u, "startNew", StartNew, Basic)
+ATTR____(0x4570500fu, "modifier", Modifier, Basic)
+ATTR____(0x45a6daf8u, "eofAction", EofAction, Basic)
+ATTR____(0x47cfa43au, "allowNeutral", AllowNeutral, Basic)
+ATTR____(0x47d03490u, "connection", Connection, Basic)
+ATTR____(0x4873c601u, "baselineShift", BaselineShift, Basic)
+ATTR____(0x4b319767u, "overlinePeriod", OverlinePeriod, Basic)
+ATTR____(0x4b8bc840u, "fracDigits", FracDigits, Basic)
+ATTR____(0x4df15659u, "nodes", Nodes, Object)
+ATTR____(0x4ef3d02cu, "orientation", Orientation, Basic)
+ATTR____(0x4fdc3454u, "timeStamp", TimeStamp, Basic)
+ATTR____(0x50d1a9d1u, "model", Model, Object)
+ATTR____(0x50e2e33bu, "selEnd", SelEnd, Basic)
+ATTR____(0x52666f1cu, "printCheckDigit", PrintCheckDigit, Basic)
+ATTR____(0x534729c9u, "marginLeft", MarginLeft, Basic)
+ATTR____(0x5392ea58u, "stroke", Stroke, Basic)
+ATTR____(0x5404d6dfu, "moduleHeight", ModuleHeight, Basic)
+ATTR____(0x54c399e3u, "formattedValue", FormattedValue, Basic)
+ATTR____(0x54fa722cu, "transferEncoding", TransferEncoding, Basic)
+ATTR____(0x552d9ad5u, "usage", Usage, Basic)
+ATTR____(0x570ce835u, "presence", Presence, Basic)
+ATTR____(0x5739d1ffu, "radixOffset", RadixOffset, Basic)
+ATTR____(0x577682acu, "preserve", Preserve, Basic)
+ATTR____(0x57de87c2u, "prevText", PrevText, Basic)
+ATTR____(0x58be2870u, "aliasNode", AliasNode, Object)
+ATTR____(0x5a32e493u, "multiLine", MultiLine, Basic)
+ATTR____(0x5a3b375du, "borderColor", BorderColor, Basic)
+ATTR____(0x5a50e9e6u, "version", Version, Basic)
+ATTR____(0x5ab23b6cu, "startChar", StartChar, Basic)
+ATTR____(0x5b707a35u, "scriptTest", ScriptTest, Basic)
+ATTR____(0x5c054755u, "startAngle", StartAngle, Basic)
+ATTR____(0x5e936ed6u, "fontColor", FontColor, Basic)
+ATTR____(0x5ec958c0u, "cursorType", CursorType, Basic)
+ATTR____(0x5f760b50u, "digitalSignature", DigitalSignature, Basic)
+ATTR____(0x60a61eddu, "codeType", CodeType, Basic)
+ATTR____(0x60d4c8b1u, "output", Output, Basic)
+ATTR____(0x64110ab5u, "bookendTrailer", BookendTrailer, Basic)
+ATTR____(0x65e30c67u, "imagingBBox", ImagingBBox, Basic)
+ATTR____(0x66539c48u, "excludeInitialCap", ExcludeInitialCap, Basic)
+ATTR____(0x66642f8fu, "force", Force, Basic)
+ATTR____(0x66cb1eedu, "variation", Variation, Basic)
+ATTR____(0x6826c408u, "parentSubform", ParentSubform, Basic)
+ATTR____(0x69aa2292u, "crlSign", CrlSign, Basic)
+ATTR____(0x6a3405ddu, "previous", Previous, Basic)
+ATTR____(0x6a95c976u, "pushCharacterCount", PushCharacterCount, Basic)
+ATTR____(0x6aab37cbu, "isDefined", IsDefined, Basic)
+ATTR____(0x6b6ddcfbu, "nullTest", NullTest, Basic)
+ATTR____(0x6c0d9600u, "currentValue", CurrentValue, Basic)
+ATTR____(0x6cfa828au, "runAt", RunAt, Basic)
+ATTR____(0x6ea04e0au, "soapFaultCode", SoapFaultCode, Basic)
+ATTR____(0x6f544d49u, "count", Count, Basic)
+ATTR____(0x6f6556cfu, "newText", NewText, Basic)
+ATTR____(0x731e0665u, "spaceBelow", SpaceBelow, Basic)
+ATTR____(0x74788f8bu, "sweepAngle", SweepAngle, Basic)
+ATTR____(0x7717cbc4u, "language", Language, Basic)
+ATTR____(0x78a8d6cfu, "classAll", ClassAll, Object)
+ATTR____(0x78bff531u, "numberOfCells", NumberOfCells, Basic)
+ATTR____(0x79543055u, "letterSpacing", LetterSpacing, Basic)
+ATTR____(0x79975f2bu, "lockType", LockType, Basic)
+ATTR____(0x79b67434u, "mandatoryMessage", MandatoryMessage, Basic)
+ATTR____(0x7a0cc471u, "passwordChar", PasswordChar, Basic)
+ATTR____(0x7a7cc341u, "vAlign", VAlign, Basic)
+ATTR____(0x7b29630au, "sourceBelow", SourceBelow, Basic)
+ATTR____(0x7b95e661u, "inverted", Inverted, Basic)
+ATTR____(0x7c2fd80bu, "mark", Mark, Basic)
+ATTR____(0x7c2ff6aeu, "maxH", MaxH, Basic)
+ATTR____(0x7c2ff6bdu, "maxW", MaxW, Basic)
+ATTR____(0x7c732a66u, "truncate", Truncate, Basic)
+ATTR____(0x7d02356cu, "minH", MinH, Basic)
+ATTR____(0x7d02357bu, "minW", MinW, Basic)
+ATTR____(0x7d0b5fcau, "initial", Initial, Basic)
+ATTR____(0x7d9fd7c5u, "mode", Mode, Basic)
+ATTR____(0x7e7e845eu, "layout", Layout, Basic)
+ATTR____(0x7f6fd3d7u, "server", Server, Basic)
+ATTR____(0x824f21b7u, "embedPDF", EmbedPDF, Basic)
+ATTR____(0x8340ea66u, "oddOrEven", OddOrEven, Basic)
+ATTR____(0x836d4d7cu, "tabDefault", TabDefault, Basic)
+ATTR____(0x846599f8u, "transient", Transient, Basic)
+ATTR____(0x85fd6fafu, "mandatory", Mandatory, Basic)
+ATTR____(0x86698963u, "appType", AppType, Basic)
+ATTR____(0x8855805fu, "contains", Contains, Basic)
+ATTR____(0x891f4606u, "change", Change, Basic)
+ATTR____(0x8a692521u, "rightInset", RightInset, Basic)
+ATTR____(0x8af2e657u, "maxChars", MaxChars, Basic)
+ATTR____(0x8b90e1f2u, "open", Open, Basic)
+ATTR____(0x8c99377eu, "relation", Relation, Basic)
+ATTR____(0x8d181d61u, "wideNarrowRatio", WideNarrowRatio, Basic)
+ATTR____(0x8e1c2921u, "relevant", Relevant, Basic)
+ATTR____(0x8e29d794u, "signatureType", SignatureType, Basic)
+ATTR____(0x8ec6204cu, "lineThroughPeriod", LineThroughPeriod, Basic)
+ATTR____(0x8ed182d1u, "shape", Shape, Basic)
+ATTR____(0x8fa01790u, "tabStops", TabStops, Basic)
+ATTR____(0x8fa3c19eu, "shift", Shift, Basic)
+ATTR____(0x8fc36c0au, "outputBelow", OutputBelow, Basic)
+ATTR____(0x9041d4b0u, "short", Short, Basic)
+ATTR____(0x907c7719u, "fontVerticalScale", FontVerticalScale, Basic)
+ATTR____(0x942643f0u, "savedValue", SavedValue, Basic)
+ATTR____(0x94446dccu, "thickness", Thickness, Basic)
+ATTR____(0x94ff9e8du, "calculationsEnabled", CalculationsEnabled, Basic)
+ATTR____(0x957fa006u, "commitOn", CommitOn, Basic)
+ATTR____(0x964fb42eu, "formatMessage", FormatMessage, Basic)
+ATTR____(0x982bd892u, "remainCharacterCount", RemainCharacterCount, Basic)
+ATTR____(0x98fd4d81u, "keyAgreement", KeyAgreement, Basic)
+ATTR____(0x99800d7au, "errorCorrectionLevel", ErrorCorrectionLevel, Basic)
+ATTR____(0x9a63da3du, "upsMode", UpsMode, Basic)
+ATTR____(0x9cc17d75u, "mergeMode", MergeMode, Basic)
+ATTR____(0x9d833d75u, "circular", Circular, Basic)
+ATTR____(0x9d8ee204u, "psName", PsName, Basic)
+ATTR____(0x9dcc3ab3u, "trailer", Trailer, Basic)
+ATTR____(0x9f3e9510u, "instanceManager", InstanceManager, Object)
+ATTR____(0xa021b738u, "stateless", Stateless, Basic)
+ATTR____(0xa03cf627u, "rawValue", RawValue, Basic)
+ATTR____(0xa0933954u, "unicodeRange", UnicodeRange, Basic)
+ATTR____(0xa1b0d2f5u, "executeType", ExecuteType, Basic)
+ATTR____(0xa25a883du, "duplexImposition", DuplexImposition, Basic)
+ATTR____(0xa42ca1b7u, "trayIn", TrayIn, Basic)
+ATTR____(0xa433f001u, "bindingNode", BindingNode, Basic)
+ATTR____(0xa52682bdu, "{default}", DefaultValue, Basic)
+ATTR____(0xa5340ff5u, "bofAction", BofAction, Basic)
+ATTR____(0xa5b410cfu, "save", Save, Basic)
+ATTR____(0xa60dd202u, "length", Length, Basic)
+ATTR____(0xa6118c89u, "targetType", TargetType, Basic)
+ATTR____(0xa66404cbu, "keyEncipherment", KeyEncipherment, Basic)
+ATTR____(0xa6710262u, "credentialServerPolicy", CredentialServerPolicy, Basic)
+ATTR____(0xa686975bu, "size", Size, Basic)
+ATTR____(0xa85e74f3u, "initialNumber", InitialNumber, Basic)
+ATTR____(0xa9d9b2e1u, "keyDown", keyDown, Basic)
+ATTR____(0xabef37e3u, "slope", Slope, Basic)
+ATTR____(0xabfa6c4fu, "cSpace", CSpace, Basic)
+ATTR____(0xac06e2b0u, "colSpan", ColSpan, Basic)
+ATTR____(0xacb4823fu, "isContainer", IsContainer, Basic)
+ATTR____(0xadc4c77bu, "binding", Binding, Basic)
+ATTR____(0xaf754613u, "checksum", Checksum, Basic)
+ATTR____(0xb045fbc5u, "charEncoding", CharEncoding, Basic)
+ATTR____(0xb0e5485du, "bind", Bind, Basic)
+ATTR____(0xb12128b7u, "textEntry", TextEntry, Basic)
+ATTR____(0xb2c80857u, "className", ClassName, Basic)
+ATTR____(0xb373a862u, "archive", Archive, Basic)
+ATTR____(0xb598a1f7u, "uuid", Uuid, Basic)
+ATTR____(0xb5e49bf2u, "posture", Posture, Basic)
+ATTR____(0xb6b44172u, "after", After, Basic)
+ATTR____(0xb716467bu, "orphans", Orphans, Basic)
+ATTR____(0xbc0c4695u, "qualifiedName", QualifiedName, Basic)
+ATTR____(0xbc254332u, "usehref", Usehref, Basic)
+ATTR____(0xbc8fa350u, "locale", Locale, Basic)
+ATTR____(0xbcd44940u, "currentPage", CurrentPage, Basic)
+ATTR____(0xbd6e1d88u, "weight", Weight, Basic)
+ATTR____(0xbd96a0e9u, "underlinePeriod", UnderlinePeriod, Basic)
+ATTR____(0xbde9abdau, "data", Data, Basic)
+ATTR____(0xbe52dfbfu, "desc", Desc, Basic)
+ATTR____(0xbe9ba472u, "numbered", Numbered, Basic)
+ATTR____(0xbfc89db2u, "selStart", selStart, Basic)
+ATTR____(0xc035c6b1u, "dataColumnCount", DataColumnCount, Basic)
+ATTR____(0xc0ec9fa4u, "overline", Overline, Basic)
+ATTR____(0xc2ba0923u, "urlPolicy", UrlPolicy, Basic)
+ATTR____(0xc2bd40fdu, "anchorType", AnchorType, Basic)
+ATTR____(0xc32a5812u, "commitKey", CommitKey, Basic)
+ATTR____(0xc39a88bdu, "labelRef", LabelRef, Basic)
+ATTR____(0xc3c1442fu, "bookendLeader", BookendLeader, Basic)
+ATTR____(0xc4547a08u, "maxLength", MaxLength, Basic)
+ATTR____(0xc4fed09bu, "accessKey", AccessKey, Basic)
+ATTR____(0xc5762157u, "cursorLocation", CursorLocation, Basic)
+ATTR____(0xc860f30au, "delayedOpen", DelayedOpen, Basic)
+ATTR____(0xc8da4da7u, "target", Target, Basic)
+ATTR____(0xca5dc27cu, "dataEncipherment", DataEncipherment, Basic)
+ATTR____(0xcabfa3d0u, "validationMessage", ValidationMessage, Basic)
+ATTR____(0xcad6d8cau, "parent", Parent, Object)
+ATTR____(0xcb150479u, "afterTarget", AfterTarget, Basic)
+ATTR____(0xcbcaf66du, "leader", Leader, Basic)
+ATTR____(0xcca7897eu, "picker", Picker, Basic)
+ATTR____(0xcd7f7b54u, "from", From, Basic)
+ATTR____(0xcea5e62cu, "baseProfile", BaseProfile, Basic)
+ATTR____(0xd171b240u, "aspect", Aspect, Basic)
+ATTR____(0xd3c84d25u, "rowColumnRatio", RowColumnRatio, Basic)
+ATTR____(0xd4b01921u, "lineHeight", LineHeight, Basic)
+ATTR____(0xd4cc53f8u, "highlight", Highlight, Basic)
+ATTR____(0xd50f903au, "valueRef", ValueRef, Basic)
+ATTR____(0xd52482e0u, "maxEntries", MaxEntries, Basic)
+ATTR____(0xd5679c78u, "index", Index, Basic)
+ATTR____(0xd57c513cu, "dataLength", DataLength, Basic)
+ATTR____(0xd592b920u, "numPages", NumPages, Basic)
+ATTR____(0xd6128d8du, "activity", Activity, Basic)
+ATTR____(0xd6a39990u, "input", Input, Basic)
+ATTR____(0xd6e27f1du, "value", Value, Basic)
+ATTR____(0xd70798c2u, "blankOrNotBlank", BlankOrNotBlank, Basic)
+ATTR____(0xd861f8afu, "addRevocationInfo", AddRevocationInfo, Basic)
+ATTR____(0xd8624e04u, "cancelAction", cancelAction, Basic)
+ATTR____(0xd8f982bfu, "genericFamily", GenericFamily, Basic)
+ATTR____(0xd996fa9bu, "hand", Hand, Basic)
+ATTR____(0xdb55fec5u, "href", Href, Basic)
+ATTR____(0xdb5b4bceu, "classIndex", ClassIndex, Basic)
+ATTR____(0xdc75676cu, "textEncoding", TextEncoding, Basic)
+ATTR____(0xdcecd663u, "editValue", EditValue, Basic)
+ATTR____(0xde7f92bau, "leadDigits", LeadDigits, Basic)
+ATTR____(0xe07e5061u, "selectedIndex", SelectedIndex, Basic)
+ATTR____(0xe11a2cbcu, "permissions", Permissions, Basic)
+ATTR____(0xe18b5659u, "spaceAbove", SpaceAbove, Basic)
+ATTR____(0xe1a26b56u, "codeBase", CodeBase, Basic)
+ATTR____(0xe349d044u, "stock", Stock, Basic)
+ATTR____(0xe372ae97u, "isNull", IsNull, Basic)
+ATTR____(0xe4989adfu, "somExpression", SomExpression, Basic)
+ATTR____(0xe4c3a5e5u, "restoreState", RestoreState, Basic)
+ATTR____(0xe5c96d6au, "excludeAllCaps", ExcludeAllCaps, Basic)
+ATTR____(0xe64b1129u, "formatTest", FormatTest, Basic)
+ATTR____(0xe6f99487u, "hScrollPolicy", HScrollPolicy, Basic)
+ATTR____(0xe8dddf50u, "join", Join, Basic)
+ATTR____(0xe8f118a8u, "keyCertSign", KeyCertSign, Basic)
+ATTR____(0xe948b9a8u, "radius", Radius, Basic)
+ATTR____(0xe996b2feu, "sourceAbove", SourceAbove, Basic)
+ATTR____(0xea7090a0u, "override", Override, Basic)
+ATTR____(0xeb091003u, "classId", ClassId, Basic)
+ATTR____(0xeb511b54u, "disable", Disable, Basic)
+ATTR____(0xeda9017au, "scope", Scope, Basic)
+ATTR____(0xf197844du, "match", Match, Basic)
+ATTR____(0xf2009339u, "placement", Placement, Basic)
+ATTR____(0xf4ffce73u, "before", Before, Basic)
+ATTR____(0xf531b059u, "writingScript", WritingScript, Basic)
+ATTR____(0xf575ca75u, "endChar", EndChar, Basic)
+ATTR____(0xf65e34beu, "borderWidth", BorderWidth, Basic)
+ATTR____(0xf6b47749u, "lock", Lock, Basic)
+ATTR____(0xf6b4afb0u, "long", Long, Basic)
+ATTR____(0xf6b59543u, "intact", Intact, Basic)
+ATTR____(0xf889e747u, "xdpContent", XdpContent, Basic)
+ATTR____(0xfcef86b5u, "ready", Ready, Basic)
+ATTR____(0xfe612a5bu, "oneOfChild", OneOfChild, Object)
+ATTR____(0xfea53ec6u, "decipherOnly", DecipherOnly, Basic)
diff --git a/xfa/fxfa/parser/cscript_datawindow.cpp b/xfa/fxfa/parser/cscript_datawindow.cpp
index 0bf17e5..1328dba 100644
--- a/xfa/fxfa/parser/cscript_datawindow.cpp
+++ b/xfa/fxfa/parser/cscript_datawindow.cpp
@@ -16,7 +16,6 @@
     : CXFA_Object(pDocument,
                   XFA_ObjectType::Object,
                   XFA_Element::DataWindow,
-                  WideStringView(L"dataWindow"),
                   pdfium::MakeUnique<CJX_DataWindow>(this)) {}
 
 CScript_DataWindow::~CScript_DataWindow() {}
diff --git a/xfa/fxfa/parser/cscript_datawindow.h b/xfa/fxfa/parser/cscript_datawindow.h
index 819e8fe..ceed58e 100644
--- a/xfa/fxfa/parser/cscript_datawindow.h
+++ b/xfa/fxfa/parser/cscript_datawindow.h
@@ -7,17 +7,14 @@
 #ifndef XFA_FXFA_PARSER_CSCRIPT_DATAWINDOW_H_
 #define XFA_FXFA_PARSER_CSCRIPT_DATAWINDOW_H_
 
-#include "fxjs/xfa/cjx_datawindow.h"
 #include "xfa/fxfa/parser/cxfa_object.h"
 
-class CScript_DataWindow : public CXFA_Object {
+class CXFA_Document;
+
+class CScript_DataWindow final : public CXFA_Object {
  public:
   explicit CScript_DataWindow(CXFA_Document* pDocument);
   ~CScript_DataWindow() override;
-
-  CJX_DataWindow* JSDataWindow() {
-    return static_cast<CJX_DataWindow*>(JSObject());
-  }
 };
 
 #endif  // XFA_FXFA_PARSER_CSCRIPT_DATAWINDOW_H_
diff --git a/xfa/fxfa/parser/cscript_eventpseudomodel.cpp b/xfa/fxfa/parser/cscript_eventpseudomodel.cpp
index da7fcb4..b4953af 100644
--- a/xfa/fxfa/parser/cscript_eventpseudomodel.cpp
+++ b/xfa/fxfa/parser/cscript_eventpseudomodel.cpp
@@ -6,14 +6,13 @@
 
 #include "xfa/fxfa/parser/cscript_eventpseudomodel.h"
 
-#include "fxjs/xfa/cjx_object.h"
+#include "fxjs/xfa/cjx_eventpseudomodel.h"
 #include "third_party/base/ptr_util.h"
 
 CScript_EventPseudoModel::CScript_EventPseudoModel(CXFA_Document* pDocument)
     : CXFA_Object(pDocument,
                   XFA_ObjectType::Object,
                   XFA_Element::EventPseudoModel,
-                  WideStringView(L"eventPseudoModel"),
                   pdfium::MakeUnique<CJX_EventPseudoModel>(this)) {}
 
-CScript_EventPseudoModel::~CScript_EventPseudoModel() {}
+CScript_EventPseudoModel::~CScript_EventPseudoModel() = default;
diff --git a/xfa/fxfa/parser/cscript_eventpseudomodel.h b/xfa/fxfa/parser/cscript_eventpseudomodel.h
index efb4df0..8104162 100644
--- a/xfa/fxfa/parser/cscript_eventpseudomodel.h
+++ b/xfa/fxfa/parser/cscript_eventpseudomodel.h
@@ -7,17 +7,14 @@
 #ifndef XFA_FXFA_PARSER_CSCRIPT_EVENTPSEUDOMODEL_H_
 #define XFA_FXFA_PARSER_CSCRIPT_EVENTPSEUDOMODEL_H_
 
-#include "fxjs/xfa/cjx_eventpseudomodel.h"
 #include "xfa/fxfa/parser/cxfa_object.h"
 
-class CScript_EventPseudoModel : public CXFA_Object {
+class CXFA_Document;
+
+class CScript_EventPseudoModel final : public CXFA_Object {
  public:
   explicit CScript_EventPseudoModel(CXFA_Document* pDocument);
   ~CScript_EventPseudoModel() override;
-
-  CJX_EventPseudoModel* JSEventPseudoModel() {
-    return static_cast<CJX_EventPseudoModel*>(JSObject());
-  }
 };
 
 #endif  // XFA_FXFA_PARSER_CSCRIPT_EVENTPSEUDOMODEL_H_
diff --git a/xfa/fxfa/parser/cscript_hostpseudomodel.cpp b/xfa/fxfa/parser/cscript_hostpseudomodel.cpp
index 8122aa3..4501633 100644
--- a/xfa/fxfa/parser/cscript_hostpseudomodel.cpp
+++ b/xfa/fxfa/parser/cscript_hostpseudomodel.cpp
@@ -6,13 +6,13 @@
 
 #include "xfa/fxfa/parser/cscript_hostpseudomodel.h"
 
+#include "fxjs/xfa/cjx_hostpseudomodel.h"
 #include "third_party/base/ptr_util.h"
 
 CScript_HostPseudoModel::CScript_HostPseudoModel(CXFA_Document* pDocument)
     : CXFA_Object(pDocument,
                   XFA_ObjectType::Object,
                   XFA_Element::HostPseudoModel,
-                  WideStringView(L"hostPseudoModel"),
                   pdfium::MakeUnique<CJX_HostPseudoModel>(this)) {}
 
-CScript_HostPseudoModel::~CScript_HostPseudoModel() {}
+CScript_HostPseudoModel::~CScript_HostPseudoModel() = default;
diff --git a/xfa/fxfa/parser/cscript_hostpseudomodel.h b/xfa/fxfa/parser/cscript_hostpseudomodel.h
index 7e4a37d..c8af249 100644
--- a/xfa/fxfa/parser/cscript_hostpseudomodel.h
+++ b/xfa/fxfa/parser/cscript_hostpseudomodel.h
@@ -7,19 +7,14 @@
 #ifndef XFA_FXFA_PARSER_CSCRIPT_HOSTPSEUDOMODEL_H_
 #define XFA_FXFA_PARSER_CSCRIPT_HOSTPSEUDOMODEL_H_
 
-#include "fxjs/xfa/cjx_hostpseudomodel.h"
 #include "xfa/fxfa/parser/cxfa_object.h"
 
 class CXFA_Document;
 
-class CScript_HostPseudoModel : public CXFA_Object {
+class CScript_HostPseudoModel final : public CXFA_Object {
  public:
   explicit CScript_HostPseudoModel(CXFA_Document* pDocument);
   ~CScript_HostPseudoModel() override;
-
-  CJX_HostPseudoModel* JSHostPseudoModel() {
-    return static_cast<CJX_HostPseudoModel*>(JSObject());
-  }
 };
 
 #endif  // XFA_FXFA_PARSER_CSCRIPT_HOSTPSEUDOMODEL_H_
diff --git a/xfa/fxfa/parser/cscript_layoutpseudomodel.cpp b/xfa/fxfa/parser/cscript_layoutpseudomodel.cpp
index 73033d5..4dfad07 100644
--- a/xfa/fxfa/parser/cscript_layoutpseudomodel.cpp
+++ b/xfa/fxfa/parser/cscript_layoutpseudomodel.cpp
@@ -6,13 +6,13 @@
 
 #include "xfa/fxfa/parser/cscript_layoutpseudomodel.h"
 
+#include "fxjs/xfa/cjx_layoutpseudomodel.h"
 #include "third_party/base/ptr_util.h"
 
 CScript_LayoutPseudoModel::CScript_LayoutPseudoModel(CXFA_Document* pDocument)
     : CXFA_Object(pDocument,
                   XFA_ObjectType::Object,
                   XFA_Element::LayoutPseudoModel,
-                  WideStringView(L"layoutPseudoModel"),
                   pdfium::MakeUnique<CJX_LayoutPseudoModel>(this)) {}
 
-CScript_LayoutPseudoModel::~CScript_LayoutPseudoModel() {}
+CScript_LayoutPseudoModel::~CScript_LayoutPseudoModel() = default;
diff --git a/xfa/fxfa/parser/cscript_layoutpseudomodel.h b/xfa/fxfa/parser/cscript_layoutpseudomodel.h
index d76013a..e88a6aa 100644
--- a/xfa/fxfa/parser/cscript_layoutpseudomodel.h
+++ b/xfa/fxfa/parser/cscript_layoutpseudomodel.h
@@ -7,19 +7,14 @@
 #ifndef XFA_FXFA_PARSER_CSCRIPT_LAYOUTPSEUDOMODEL_H_
 #define XFA_FXFA_PARSER_CSCRIPT_LAYOUTPSEUDOMODEL_H_
 
-#include "fxjs/xfa/cjx_layoutpseudomodel.h"
 #include "xfa/fxfa/parser/cxfa_object.h"
 
-class CXFA_LayoutProcessor;
+class CXFA_Document;
 
-class CScript_LayoutPseudoModel : public CXFA_Object {
+class CScript_LayoutPseudoModel final : public CXFA_Object {
  public:
   explicit CScript_LayoutPseudoModel(CXFA_Document* pDocument);
   ~CScript_LayoutPseudoModel() override;
-
-  CJX_LayoutPseudoModel* JSLayoutPseudoModel() {
-    return static_cast<CJX_LayoutPseudoModel*>(JSObject());
-  }
 };
 
 #endif  // XFA_FXFA_PARSER_CSCRIPT_LAYOUTPSEUDOMODEL_H_
diff --git a/xfa/fxfa/parser/cscript_logpseudomodel.cpp b/xfa/fxfa/parser/cscript_logpseudomodel.cpp
index 1c2d802..185ac80 100644
--- a/xfa/fxfa/parser/cscript_logpseudomodel.cpp
+++ b/xfa/fxfa/parser/cscript_logpseudomodel.cpp
@@ -6,13 +6,13 @@
 
 #include "xfa/fxfa/parser/cscript_logpseudomodel.h"
 
+#include "fxjs/xfa/cjx_logpseudomodel.h"
 #include "third_party/base/ptr_util.h"
 
 CScript_LogPseudoModel::CScript_LogPseudoModel(CXFA_Document* pDocument)
     : CXFA_Object(pDocument,
                   XFA_ObjectType::Object,
                   XFA_Element::LogPseudoModel,
-                  WideStringView(L"logPseudoModel"),
                   pdfium::MakeUnique<CJX_LogPseudoModel>(this)) {}
 
 CScript_LogPseudoModel::~CScript_LogPseudoModel() {}
diff --git a/xfa/fxfa/parser/cscript_logpseudomodel.h b/xfa/fxfa/parser/cscript_logpseudomodel.h
index 9344f20..aa11bea 100644
--- a/xfa/fxfa/parser/cscript_logpseudomodel.h
+++ b/xfa/fxfa/parser/cscript_logpseudomodel.h
@@ -7,17 +7,14 @@
 #ifndef XFA_FXFA_PARSER_CSCRIPT_LOGPSEUDOMODEL_H_
 #define XFA_FXFA_PARSER_CSCRIPT_LOGPSEUDOMODEL_H_
 
-#include "fxjs/xfa/cjx_logpseudomodel.h"
 #include "xfa/fxfa/parser/cxfa_object.h"
 
-class CScript_LogPseudoModel : public CXFA_Object {
+class CXFA_Document;
+
+class CScript_LogPseudoModel final : public CXFA_Object {
  public:
   explicit CScript_LogPseudoModel(CXFA_Document* pDocument);
   ~CScript_LogPseudoModel() override;
-
-  CJX_LogPseudoModel* JSLogPseudoModel() {
-    return static_cast<CJX_LogPseudoModel*>(JSObject());
-  }
 };
 
 #endif  // XFA_FXFA_PARSER_CSCRIPT_LOGPSEUDOMODEL_H_
diff --git a/xfa/fxfa/parser/cscript_signaturepseudomodel.cpp b/xfa/fxfa/parser/cscript_signaturepseudomodel.cpp
index c5f4e64..1f92369 100644
--- a/xfa/fxfa/parser/cscript_signaturepseudomodel.cpp
+++ b/xfa/fxfa/parser/cscript_signaturepseudomodel.cpp
@@ -6,6 +6,7 @@
 
 #include "xfa/fxfa/parser/cscript_signaturepseudomodel.h"
 
+#include "fxjs/xfa/cjx_signaturepseudomodel.h"
 #include "third_party/base/ptr_util.h"
 
 CScript_SignaturePseudoModel::CScript_SignaturePseudoModel(
@@ -13,7 +14,6 @@
     : CXFA_Object(pDocument,
                   XFA_ObjectType::Object,
                   XFA_Element::SignaturePseudoModel,
-                  WideStringView(L"signaturePseudoModel"),
                   pdfium::MakeUnique<CJX_SignaturePseudoModel>(this)) {}
 
-CScript_SignaturePseudoModel::~CScript_SignaturePseudoModel() {}
+CScript_SignaturePseudoModel::~CScript_SignaturePseudoModel() = default;
diff --git a/xfa/fxfa/parser/cscript_signaturepseudomodel.h b/xfa/fxfa/parser/cscript_signaturepseudomodel.h
index 276c1df..532a767 100644
--- a/xfa/fxfa/parser/cscript_signaturepseudomodel.h
+++ b/xfa/fxfa/parser/cscript_signaturepseudomodel.h
@@ -7,17 +7,14 @@
 #ifndef XFA_FXFA_PARSER_CSCRIPT_SIGNATUREPSEUDOMODEL_H_
 #define XFA_FXFA_PARSER_CSCRIPT_SIGNATUREPSEUDOMODEL_H_
 
-#include "fxjs/xfa/cjx_signaturepseudomodel.h"
 #include "xfa/fxfa/parser/cxfa_object.h"
 
-class CScript_SignaturePseudoModel : public CXFA_Object {
+class CXFA_Document;
+
+class CScript_SignaturePseudoModel final : public CXFA_Object {
  public:
   explicit CScript_SignaturePseudoModel(CXFA_Document* pDocument);
   ~CScript_SignaturePseudoModel() override;
-
-  CJX_SignaturePseudoModel* JSSignaturePseudoModel() {
-    return static_cast<CJX_SignaturePseudoModel*>(JSObject());
-  }
 };
 
 #endif  // XFA_FXFA_PARSER_CSCRIPT_SIGNATUREPSEUDOMODEL_H_
diff --git a/xfa/fxfa/parser/cxfa_accessiblecontent.cpp b/xfa/fxfa/parser/cxfa_accessiblecontent.cpp
index 0a24615..4840fbb 100644
--- a/xfa/fxfa/parser/cxfa_accessiblecontent.cpp
+++ b/xfa/fxfa/parser/cxfa_accessiblecontent.cpp
@@ -6,14 +6,15 @@
 
 #include "xfa/fxfa/parser/cxfa_accessiblecontent.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kAccessibleContentAttributeData[] = {
     {XFA_Attribute::Desc, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Lock, XFA_AttributeType::Integer, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"accessibleContent";
+};
 
 }  // namespace
 
@@ -24,8 +25,8 @@
                 XFA_XDPPACKET_Config,
                 XFA_ObjectType::ContentNode,
                 XFA_Element::AccessibleContent,
-                nullptr,
-                kAttributeData,
-                kName) {}
+                {},
+                kAccessibleContentAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_AccessibleContent::~CXFA_AccessibleContent() {}
+CXFA_AccessibleContent::~CXFA_AccessibleContent() = default;
diff --git a/xfa/fxfa/parser/cxfa_accessiblecontent.h b/xfa/fxfa/parser/cxfa_accessiblecontent.h
index 84ad8fc..2aea151 100644
--- a/xfa/fxfa/parser/cxfa_accessiblecontent.h
+++ b/xfa/fxfa/parser/cxfa_accessiblecontent.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_AccessibleContent : public CXFA_Node {
+class CXFA_AccessibleContent final : public CXFA_Node {
  public:
   CXFA_AccessibleContent(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_AccessibleContent() override;
diff --git a/xfa/fxfa/parser/cxfa_acrobat.cpp b/xfa/fxfa/parser/cxfa_acrobat.cpp
index 2327c08..301c056 100644
--- a/xfa/fxfa/parser/cxfa_acrobat.cpp
+++ b/xfa/fxfa/parser/cxfa_acrobat.cpp
@@ -6,21 +6,23 @@
 
 #include "xfa/fxfa/parser/cxfa_acrobat.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::PropertyData kPropertyData[] = {
+const CXFA_Node::PropertyData kAcrobatPropertyData[] = {
     {XFA_Element::AutoSave, 1, 0},
     {XFA_Element::Validate, 1, 0},
     {XFA_Element::ValidateApprovalSignatures, 1, 0},
     {XFA_Element::Acrobat7, 1, 0},
     {XFA_Element::Common, 1, 0},
-    {XFA_Element::Unknown, 0, 0}};
-const CXFA_Node::AttributeData kAttributeData[] = {
+};
+
+const CXFA_Node::AttributeData kAcrobatAttributeData[] = {
     {XFA_Attribute::Desc, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Lock, XFA_AttributeType::Integer, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"acrobat";
+};
 
 }  // namespace
 
@@ -30,8 +32,8 @@
                 XFA_XDPPACKET_Config,
                 XFA_ObjectType::Node,
                 XFA_Element::Acrobat,
-                kPropertyData,
-                kAttributeData,
-                kName) {}
+                kAcrobatPropertyData,
+                kAcrobatAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_Acrobat::~CXFA_Acrobat() {}
+CXFA_Acrobat::~CXFA_Acrobat() = default;
diff --git a/xfa/fxfa/parser/cxfa_acrobat.h b/xfa/fxfa/parser/cxfa_acrobat.h
index 3701d59..5711178 100644
--- a/xfa/fxfa/parser/cxfa_acrobat.h
+++ b/xfa/fxfa/parser/cxfa_acrobat.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Acrobat : public CXFA_Node {
+class CXFA_Acrobat final : public CXFA_Node {
  public:
   CXFA_Acrobat(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Acrobat() override;
diff --git a/xfa/fxfa/parser/cxfa_acrobat7.cpp b/xfa/fxfa/parser/cxfa_acrobat7.cpp
index 089ab60..8b8afa4 100644
--- a/xfa/fxfa/parser/cxfa_acrobat7.cpp
+++ b/xfa/fxfa/parser/cxfa_acrobat7.cpp
@@ -6,17 +6,19 @@
 
 #include "xfa/fxfa/parser/cxfa_acrobat7.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::PropertyData kPropertyData[] = {
+const CXFA_Node::PropertyData kAcrobat7PropertyData[] = {
     {XFA_Element::DynamicRender, 1, 0},
-    {XFA_Element::Unknown, 0, 0}};
-const CXFA_Node::AttributeData kAttributeData[] = {
+};
+
+const CXFA_Node::AttributeData kAcrobat7AttributeData[] = {
     {XFA_Attribute::Desc, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Lock, XFA_AttributeType::Integer, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"acrobat7";
+};
 
 }  // namespace
 
@@ -26,8 +28,8 @@
                 XFA_XDPPACKET_Config,
                 XFA_ObjectType::Node,
                 XFA_Element::Acrobat7,
-                kPropertyData,
-                kAttributeData,
-                kName) {}
+                kAcrobat7PropertyData,
+                kAcrobat7AttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_Acrobat7::~CXFA_Acrobat7() {}
+CXFA_Acrobat7::~CXFA_Acrobat7() = default;
diff --git a/xfa/fxfa/parser/cxfa_acrobat7.h b/xfa/fxfa/parser/cxfa_acrobat7.h
index 579864a..8f64044 100644
--- a/xfa/fxfa/parser/cxfa_acrobat7.h
+++ b/xfa/fxfa/parser/cxfa_acrobat7.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Acrobat7 : public CXFA_Node {
+class CXFA_Acrobat7 final : public CXFA_Node {
  public:
   CXFA_Acrobat7(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Acrobat7() override;
diff --git a/xfa/fxfa/parser/cxfa_adbe_jsconsole.cpp b/xfa/fxfa/parser/cxfa_adbe_jsconsole.cpp
index af33636..cab9d62 100644
--- a/xfa/fxfa/parser/cxfa_adbe_jsconsole.cpp
+++ b/xfa/fxfa/parser/cxfa_adbe_jsconsole.cpp
@@ -6,26 +6,27 @@
 
 #include "xfa/fxfa/parser/cxfa_adbe_jsconsole.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kADBE_JSConsoleAttributeData[] = {
     {XFA_Attribute::Desc, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Lock, XFA_AttributeType::Integer, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"ADBE_JSConsole";
+};
 
 }  // namespace
 
-CXFA_aDBE_JSConsole::CXFA_aDBE_JSConsole(CXFA_Document* doc,
+CXFA_ADBE_JSConsole::CXFA_ADBE_JSConsole(CXFA_Document* doc,
                                          XFA_PacketType packet)
     : CXFA_Node(doc,
                 packet,
                 XFA_XDPPACKET_Config,
                 XFA_ObjectType::ContentNode,
                 XFA_Element::ADBE_JSConsole,
-                nullptr,
-                kAttributeData,
-                kName) {}
+                {},
+                kADBE_JSConsoleAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_aDBE_JSConsole::~CXFA_aDBE_JSConsole() {}
+CXFA_ADBE_JSConsole::~CXFA_ADBE_JSConsole() = default;
diff --git a/xfa/fxfa/parser/cxfa_adbe_jsconsole.h b/xfa/fxfa/parser/cxfa_adbe_jsconsole.h
index 9fab6a1..2fef074 100644
--- a/xfa/fxfa/parser/cxfa_adbe_jsconsole.h
+++ b/xfa/fxfa/parser/cxfa_adbe_jsconsole.h
@@ -9,10 +9,10 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_aDBE_JSConsole : public CXFA_Node {
+class CXFA_ADBE_JSConsole final : public CXFA_Node {
  public:
-  CXFA_aDBE_JSConsole(CXFA_Document* doc, XFA_PacketType packet);
-  ~CXFA_aDBE_JSConsole() override;
+  CXFA_ADBE_JSConsole(CXFA_Document* doc, XFA_PacketType packet);
+  ~CXFA_ADBE_JSConsole() override;
 };
 
 #endif  // XFA_FXFA_PARSER_CXFA_ADBE_JSCONSOLE_H_
diff --git a/xfa/fxfa/parser/cxfa_adbe_jsdebugger.cpp b/xfa/fxfa/parser/cxfa_adbe_jsdebugger.cpp
index bcb62eb..01775e0 100644
--- a/xfa/fxfa/parser/cxfa_adbe_jsdebugger.cpp
+++ b/xfa/fxfa/parser/cxfa_adbe_jsdebugger.cpp
@@ -6,26 +6,27 @@
 
 #include "xfa/fxfa/parser/cxfa_adbe_jsdebugger.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kADBE_JSDebuggerAttributeData[] = {
     {XFA_Attribute::Desc, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Lock, XFA_AttributeType::Integer, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"ADBE_JSDebugger";
+};
 
 }  // namespace
 
-CXFA_aDBE_JSDebugger::CXFA_aDBE_JSDebugger(CXFA_Document* doc,
+CXFA_ADBE_JSDebugger::CXFA_ADBE_JSDebugger(CXFA_Document* doc,
                                            XFA_PacketType packet)
     : CXFA_Node(doc,
                 packet,
                 XFA_XDPPACKET_Config,
                 XFA_ObjectType::ContentNode,
                 XFA_Element::ADBE_JSDebugger,
-                nullptr,
-                kAttributeData,
-                kName) {}
+                {},
+                kADBE_JSDebuggerAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_aDBE_JSDebugger::~CXFA_aDBE_JSDebugger() {}
+CXFA_ADBE_JSDebugger::~CXFA_ADBE_JSDebugger() = default;
diff --git a/xfa/fxfa/parser/cxfa_adbe_jsdebugger.h b/xfa/fxfa/parser/cxfa_adbe_jsdebugger.h
index ed821d4..34fcb0c 100644
--- a/xfa/fxfa/parser/cxfa_adbe_jsdebugger.h
+++ b/xfa/fxfa/parser/cxfa_adbe_jsdebugger.h
@@ -9,10 +9,10 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_aDBE_JSDebugger : public CXFA_Node {
+class CXFA_ADBE_JSDebugger final : public CXFA_Node {
  public:
-  CXFA_aDBE_JSDebugger(CXFA_Document* doc, XFA_PacketType packet);
-  ~CXFA_aDBE_JSDebugger() override;
+  CXFA_ADBE_JSDebugger(CXFA_Document* doc, XFA_PacketType packet);
+  ~CXFA_ADBE_JSDebugger() override;
 };
 
 #endif  // XFA_FXFA_PARSER_CXFA_ADBE_JSDEBUGGER_H_
diff --git a/xfa/fxfa/parser/cxfa_addsilentprint.cpp b/xfa/fxfa/parser/cxfa_addsilentprint.cpp
index 13f7f83..26b7315 100644
--- a/xfa/fxfa/parser/cxfa_addsilentprint.cpp
+++ b/xfa/fxfa/parser/cxfa_addsilentprint.cpp
@@ -6,14 +6,15 @@
 
 #include "xfa/fxfa/parser/cxfa_addsilentprint.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kAddSilentPrintAttributeData[] = {
     {XFA_Attribute::Desc, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Lock, XFA_AttributeType::Integer, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"addSilentPrint";
+};
 
 }  // namespace
 
@@ -24,8 +25,8 @@
                 XFA_XDPPACKET_Config,
                 XFA_ObjectType::ContentNode,
                 XFA_Element::AddSilentPrint,
-                nullptr,
-                kAttributeData,
-                kName) {}
+                {},
+                kAddSilentPrintAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_AddSilentPrint::~CXFA_AddSilentPrint() {}
+CXFA_AddSilentPrint::~CXFA_AddSilentPrint() = default;
diff --git a/xfa/fxfa/parser/cxfa_addsilentprint.h b/xfa/fxfa/parser/cxfa_addsilentprint.h
index a251969..abfff47 100644
--- a/xfa/fxfa/parser/cxfa_addsilentprint.h
+++ b/xfa/fxfa/parser/cxfa_addsilentprint.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_AddSilentPrint : public CXFA_Node {
+class CXFA_AddSilentPrint final : public CXFA_Node {
  public:
   CXFA_AddSilentPrint(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_AddSilentPrint() override;
diff --git a/xfa/fxfa/parser/cxfa_addviewerpreferences.cpp b/xfa/fxfa/parser/cxfa_addviewerpreferences.cpp
index 3e3d060..d07fda2 100644
--- a/xfa/fxfa/parser/cxfa_addviewerpreferences.cpp
+++ b/xfa/fxfa/parser/cxfa_addviewerpreferences.cpp
@@ -6,14 +6,15 @@
 
 #include "xfa/fxfa/parser/cxfa_addviewerpreferences.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kAddViewerPreferencesAttributeData[] = {
     {XFA_Attribute::Desc, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Lock, XFA_AttributeType::Integer, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"addViewerPreferences";
+};
 
 }  // namespace
 
@@ -24,8 +25,8 @@
                 XFA_XDPPACKET_Config,
                 XFA_ObjectType::ContentNode,
                 XFA_Element::AddViewerPreferences,
-                nullptr,
-                kAttributeData,
-                kName) {}
+                {},
+                kAddViewerPreferencesAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_AddViewerPreferences::~CXFA_AddViewerPreferences() {}
+CXFA_AddViewerPreferences::~CXFA_AddViewerPreferences() = default;
diff --git a/xfa/fxfa/parser/cxfa_addviewerpreferences.h b/xfa/fxfa/parser/cxfa_addviewerpreferences.h
index cf10868..62fd6e3 100644
--- a/xfa/fxfa/parser/cxfa_addviewerpreferences.h
+++ b/xfa/fxfa/parser/cxfa_addviewerpreferences.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_AddViewerPreferences : public CXFA_Node {
+class CXFA_AddViewerPreferences final : public CXFA_Node {
  public:
   CXFA_AddViewerPreferences(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_AddViewerPreferences() override;
diff --git a/xfa/fxfa/parser/cxfa_adjustdata.cpp b/xfa/fxfa/parser/cxfa_adjustdata.cpp
index 60a4f2c..6dbb3d4 100644
--- a/xfa/fxfa/parser/cxfa_adjustdata.cpp
+++ b/xfa/fxfa/parser/cxfa_adjustdata.cpp
@@ -6,14 +6,15 @@
 
 #include "xfa/fxfa/parser/cxfa_adjustdata.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kAdjustDataAttributeData[] = {
     {XFA_Attribute::Desc, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Lock, XFA_AttributeType::Integer, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"adjustData";
+};
 
 }  // namespace
 
@@ -23,8 +24,8 @@
                 XFA_XDPPACKET_Config,
                 XFA_ObjectType::NodeV,
                 XFA_Element::AdjustData,
-                nullptr,
-                kAttributeData,
-                kName) {}
+                {},
+                kAdjustDataAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_AdjustData::~CXFA_AdjustData() {}
+CXFA_AdjustData::~CXFA_AdjustData() = default;
diff --git a/xfa/fxfa/parser/cxfa_adjustdata.h b/xfa/fxfa/parser/cxfa_adjustdata.h
index 3c004c2..463f2e6 100644
--- a/xfa/fxfa/parser/cxfa_adjustdata.h
+++ b/xfa/fxfa/parser/cxfa_adjustdata.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_AdjustData : public CXFA_Node {
+class CXFA_AdjustData final : public CXFA_Node {
  public:
   CXFA_AdjustData(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_AdjustData() override;
diff --git a/xfa/fxfa/parser/cxfa_adobeextensionlevel.cpp b/xfa/fxfa/parser/cxfa_adobeextensionlevel.cpp
index d253f8b..dce1399 100644
--- a/xfa/fxfa/parser/cxfa_adobeextensionlevel.cpp
+++ b/xfa/fxfa/parser/cxfa_adobeextensionlevel.cpp
@@ -6,14 +6,15 @@
 
 #include "xfa/fxfa/parser/cxfa_adobeextensionlevel.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kAdobeExtensionLevelAttributeData[] = {
     {XFA_Attribute::Desc, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Lock, XFA_AttributeType::Integer, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"adobeExtensionLevel";
+};
 
 }  // namespace
 
@@ -24,8 +25,8 @@
                 XFA_XDPPACKET_Config,
                 XFA_ObjectType::ContentNode,
                 XFA_Element::AdobeExtensionLevel,
-                nullptr,
-                kAttributeData,
-                kName) {}
+                {},
+                kAdobeExtensionLevelAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_AdobeExtensionLevel::~CXFA_AdobeExtensionLevel() {}
+CXFA_AdobeExtensionLevel::~CXFA_AdobeExtensionLevel() = default;
diff --git a/xfa/fxfa/parser/cxfa_adobeextensionlevel.h b/xfa/fxfa/parser/cxfa_adobeextensionlevel.h
index 91a830f..5e0a507 100644
--- a/xfa/fxfa/parser/cxfa_adobeextensionlevel.h
+++ b/xfa/fxfa/parser/cxfa_adobeextensionlevel.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_AdobeExtensionLevel : public CXFA_Node {
+class CXFA_AdobeExtensionLevel final : public CXFA_Node {
  public:
   CXFA_AdobeExtensionLevel(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_AdobeExtensionLevel() override;
diff --git a/xfa/fxfa/parser/cxfa_agent.cpp b/xfa/fxfa/parser/cxfa_agent.cpp
index 468b938..f55b7bb 100644
--- a/xfa/fxfa/parser/cxfa_agent.cpp
+++ b/xfa/fxfa/parser/cxfa_agent.cpp
@@ -6,15 +6,16 @@
 
 #include "xfa/fxfa/parser/cxfa_agent.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kAgentAttributeData[] = {
     {XFA_Attribute::Name, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Desc, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Lock, XFA_AttributeType::Integer, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"agent";
+};
 
 }  // namespace
 
@@ -24,8 +25,8 @@
                 XFA_XDPPACKET_Config,
                 XFA_ObjectType::Node,
                 XFA_Element::Agent,
-                nullptr,
-                kAttributeData,
-                kName) {}
+                {},
+                kAgentAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_Agent::~CXFA_Agent() {}
+CXFA_Agent::~CXFA_Agent() = default;
diff --git a/xfa/fxfa/parser/cxfa_agent.h b/xfa/fxfa/parser/cxfa_agent.h
index 65d826d..a84d2ac 100644
--- a/xfa/fxfa/parser/cxfa_agent.h
+++ b/xfa/fxfa/parser/cxfa_agent.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Agent : public CXFA_Node {
+class CXFA_Agent final : public CXFA_Node {
  public:
   CXFA_Agent(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Agent() override;
diff --git a/xfa/fxfa/parser/cxfa_alwaysembed.cpp b/xfa/fxfa/parser/cxfa_alwaysembed.cpp
index 13f9717..afbb4a0 100644
--- a/xfa/fxfa/parser/cxfa_alwaysembed.cpp
+++ b/xfa/fxfa/parser/cxfa_alwaysembed.cpp
@@ -6,14 +6,15 @@
 
 #include "xfa/fxfa/parser/cxfa_alwaysembed.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kAlwaysEmbedAttributeData[] = {
     {XFA_Attribute::Desc, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Lock, XFA_AttributeType::Integer, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"alwaysEmbed";
+};
 
 }  // namespace
 
@@ -23,8 +24,8 @@
                 XFA_XDPPACKET_Config,
                 XFA_ObjectType::NodeV,
                 XFA_Element::AlwaysEmbed,
-                nullptr,
-                kAttributeData,
-                kName) {}
+                {},
+                kAlwaysEmbedAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_AlwaysEmbed::~CXFA_AlwaysEmbed() {}
+CXFA_AlwaysEmbed::~CXFA_AlwaysEmbed() = default;
diff --git a/xfa/fxfa/parser/cxfa_alwaysembed.h b/xfa/fxfa/parser/cxfa_alwaysembed.h
index 1780976..754fd89 100644
--- a/xfa/fxfa/parser/cxfa_alwaysembed.h
+++ b/xfa/fxfa/parser/cxfa_alwaysembed.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_AlwaysEmbed : public CXFA_Node {
+class CXFA_AlwaysEmbed final : public CXFA_Node {
  public:
   CXFA_AlwaysEmbed(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_AlwaysEmbed() override;
diff --git a/xfa/fxfa/parser/cxfa_amd.cpp b/xfa/fxfa/parser/cxfa_amd.cpp
index 7580304..0f6c9ef 100644
--- a/xfa/fxfa/parser/cxfa_amd.cpp
+++ b/xfa/fxfa/parser/cxfa_amd.cpp
@@ -6,14 +6,15 @@
 
 #include "xfa/fxfa/parser/cxfa_amd.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kAmdAttributeData[] = {
     {XFA_Attribute::Desc, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Lock, XFA_AttributeType::Integer, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"amd";
+};
 
 }  // namespace
 
@@ -23,8 +24,8 @@
                 XFA_XDPPACKET_Config,
                 XFA_ObjectType::ContentNode,
                 XFA_Element::Amd,
-                nullptr,
-                kAttributeData,
-                kName) {}
+                {},
+                kAmdAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_Amd::~CXFA_Amd() {}
+CXFA_Amd::~CXFA_Amd() = default;
diff --git a/xfa/fxfa/parser/cxfa_amd.h b/xfa/fxfa/parser/cxfa_amd.h
index 951c6ca..6d6562c 100644
--- a/xfa/fxfa/parser/cxfa_amd.h
+++ b/xfa/fxfa/parser/cxfa_amd.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Amd : public CXFA_Node {
+class CXFA_Amd final : public CXFA_Node {
  public:
   CXFA_Amd(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Amd() override;
diff --git a/xfa/fxfa/parser/cxfa_appearancefilter.cpp b/xfa/fxfa/parser/cxfa_appearancefilter.cpp
index 9b3e9fb..6d076da 100644
--- a/xfa/fxfa/parser/cxfa_appearancefilter.cpp
+++ b/xfa/fxfa/parser/cxfa_appearancefilter.cpp
@@ -6,17 +6,18 @@
 
 #include "xfa/fxfa/parser/cxfa_appearancefilter.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kAppearanceFilterAttributeData[] = {
     {XFA_Attribute::Id, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Use, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Type, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::Optional},
+     (void*)XFA_AttributeValue::Optional},
     {XFA_Attribute::Usehref, XFA_AttributeType::CData, nullptr},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"appearanceFilter";
+};
 
 }  // namespace
 
@@ -27,8 +28,8 @@
                 (XFA_XDPPACKET_Template | XFA_XDPPACKET_Form),
                 XFA_ObjectType::NodeC,
                 XFA_Element::AppearanceFilter,
-                nullptr,
-                kAttributeData,
-                kName) {}
+                {},
+                kAppearanceFilterAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_AppearanceFilter::~CXFA_AppearanceFilter() {}
+CXFA_AppearanceFilter::~CXFA_AppearanceFilter() = default;
diff --git a/xfa/fxfa/parser/cxfa_appearancefilter.h b/xfa/fxfa/parser/cxfa_appearancefilter.h
index 341232e..80b0ba4 100644
--- a/xfa/fxfa/parser/cxfa_appearancefilter.h
+++ b/xfa/fxfa/parser/cxfa_appearancefilter.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_AppearanceFilter : public CXFA_Node {
+class CXFA_AppearanceFilter final : public CXFA_Node {
  public:
   CXFA_AppearanceFilter(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_AppearanceFilter() override;
diff --git a/xfa/fxfa/parser/cxfa_arc.cpp b/xfa/fxfa/parser/cxfa_arc.cpp
index 9fb89a5..f9e2720 100644
--- a/xfa/fxfa/parser/cxfa_arc.cpp
+++ b/xfa/fxfa/parser/cxfa_arc.cpp
@@ -6,15 +6,17 @@
 
 #include "xfa/fxfa/parser/cxfa_arc.h"
 
-#include "fxjs/xfa/cjx_arc.h"
+#include "fxjs/xfa/cjx_node.h"
 #include "third_party/base/ptr_util.h"
 
 namespace {
 
-const CXFA_Node::PropertyData kPropertyData[] = {{XFA_Element::Edge, 1, 0},
-                                                 {XFA_Element::Fill, 1, 0},
-                                                 {XFA_Element::Unknown, 0, 0}};
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::PropertyData kArcPropertyData[] = {
+    {XFA_Element::Edge, 1, 0},
+    {XFA_Element::Fill, 1, 0},
+};
+
+const CXFA_Node::AttributeData kArcAttributeData[] = {
     {XFA_Attribute::Id, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Use, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::StartAngle, XFA_AttributeType::Integer, (void*)0},
@@ -22,10 +24,8 @@
     {XFA_Attribute::Circular, XFA_AttributeType::Boolean, (void*)0},
     {XFA_Attribute::Usehref, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Hand, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::Even},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"arc";
+     (void*)XFA_AttributeValue::Even},
+};
 
 }  // namespace
 
@@ -35,9 +35,8 @@
                (XFA_XDPPACKET_Template | XFA_XDPPACKET_Form),
                XFA_ObjectType::Node,
                XFA_Element::Arc,
-               kPropertyData,
-               kAttributeData,
-               kName,
-               pdfium::MakeUnique<CJX_Arc>(this)) {}
+               kArcPropertyData,
+               kArcAttributeData,
+               pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_Arc::~CXFA_Arc() {}
+CXFA_Arc::~CXFA_Arc() = default;
diff --git a/xfa/fxfa/parser/cxfa_arc.h b/xfa/fxfa/parser/cxfa_arc.h
index fd903aa..70d1b00 100644
--- a/xfa/fxfa/parser/cxfa_arc.h
+++ b/xfa/fxfa/parser/cxfa_arc.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_box.h"
 
-class CXFA_Arc : public CXFA_Box {
+class CXFA_Arc final : public CXFA_Box {
  public:
   CXFA_Arc(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Arc() override;
diff --git a/xfa/fxfa/parser/cxfa_area.cpp b/xfa/fxfa/parser/cxfa_area.cpp
index 7fd8aa6..16fa014 100644
--- a/xfa/fxfa/parser/cxfa_area.cpp
+++ b/xfa/fxfa/parser/cxfa_area.cpp
@@ -6,15 +6,17 @@
 
 #include "xfa/fxfa/parser/cxfa_area.h"
 
-#include "fxjs/xfa/cjx_area.h"
+#include "fxjs/xfa/cjx_container.h"
 #include "third_party/base/ptr_util.h"
 
 namespace {
 
-const CXFA_Node::PropertyData kPropertyData[] = {{XFA_Element::Desc, 1, 0},
-                                                 {XFA_Element::Extras, 1, 0},
-                                                 {XFA_Element::Unknown, 0, 0}};
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::PropertyData kAreaPropertyData[] = {
+    {XFA_Element::Desc, 1, 0},
+    {XFA_Element::Extras, 1, 0},
+};
+
+const CXFA_Node::AttributeData kAreaAttributeData[] = {
     {XFA_Attribute::X, XFA_AttributeType::Measure, (void*)L"0in"},
     {XFA_Attribute::Y, XFA_AttributeType::Measure, (void*)L"0in"},
     {XFA_Attribute::Id, XFA_AttributeType::CData, nullptr},
@@ -25,9 +27,7 @@
     {XFA_Attribute::ColSpan, XFA_AttributeType::Integer, (void*)1},
     {XFA_Attribute::Usehref, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Lock, XFA_AttributeType::Integer, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"area";
+};
 
 }  // namespace
 
@@ -38,9 +38,8 @@
           (XFA_XDPPACKET_Config | XFA_XDPPACKET_Template | XFA_XDPPACKET_Form),
           XFA_ObjectType::ContainerNode,
           XFA_Element::Area,
-          kPropertyData,
-          kAttributeData,
-          kName,
-          pdfium::MakeUnique<CJX_Area>(this)) {}
+          kAreaPropertyData,
+          kAreaAttributeData,
+          pdfium::MakeUnique<CJX_Container>(this)) {}
 
-CXFA_Area::~CXFA_Area() {}
+CXFA_Area::~CXFA_Area() = default;
diff --git a/xfa/fxfa/parser/cxfa_area.h b/xfa/fxfa/parser/cxfa_area.h
index 6568e73..cf1ff87 100644
--- a/xfa/fxfa/parser/cxfa_area.h
+++ b/xfa/fxfa/parser/cxfa_area.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Area : public CXFA_Node {
+class CXFA_Area final : public CXFA_Node {
  public:
   CXFA_Area(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Area() override;
diff --git a/xfa/fxfa/parser/cxfa_arraynodelist.cpp b/xfa/fxfa/parser/cxfa_arraynodelist.cpp
index 9eaf9a6..db36dca 100644
--- a/xfa/fxfa/parser/cxfa_arraynodelist.cpp
+++ b/xfa/fxfa/parser/cxfa_arraynodelist.cpp
@@ -6,46 +6,45 @@
 
 #include "xfa/fxfa/parser/cxfa_arraynodelist.h"
 
+#include <utility>
 #include <vector>
 
-#include "third_party/base/stl_util.h"
-
 CXFA_ArrayNodeList::CXFA_ArrayNodeList(CXFA_Document* pDocument)
     : CXFA_TreeList(pDocument) {}
 
 CXFA_ArrayNodeList::~CXFA_ArrayNodeList() {}
 
-void CXFA_ArrayNodeList::SetArrayNodeList(
-    const std::vector<CXFA_Node*>& srcArray) {
+void CXFA_ArrayNodeList::SetArrayNodeList(std::vector<CXFA_Node*> srcArray) {
   if (!srcArray.empty())
-    m_array = srcArray;
+    m_array = std::move(srcArray);
 }
 
 size_t CXFA_ArrayNodeList::GetLength() {
   return m_array.size();
 }
 
-bool CXFA_ArrayNodeList::Append(CXFA_Node* pNode) {
+void CXFA_ArrayNodeList::Append(CXFA_Node* pNode) {
   m_array.push_back(pNode);
-  return true;
 }
 
 bool CXFA_ArrayNodeList::Insert(CXFA_Node* pNewNode, CXFA_Node* pBeforeNode) {
   if (!pBeforeNode) {
     m_array.push_back(pNewNode);
-  } else {
-    auto it = std::find(m_array.begin(), m_array.end(), pBeforeNode);
-    if (it != m_array.end())
-      m_array.insert(it, pNewNode);
+    return true;
   }
+
+  auto it = std::find(m_array.begin(), m_array.end(), pBeforeNode);
+  if (it == m_array.end())
+    return false;
+
+  m_array.insert(it, pNewNode);
   return true;
 }
 
-bool CXFA_ArrayNodeList::Remove(CXFA_Node* pNode) {
+void CXFA_ArrayNodeList::Remove(CXFA_Node* pNode) {
   auto it = std::find(m_array.begin(), m_array.end(), pNode);
   if (it != m_array.end())
     m_array.erase(it);
-  return true;
 }
 
 CXFA_Node* CXFA_ArrayNodeList::Item(size_t index) {
diff --git a/xfa/fxfa/parser/cxfa_arraynodelist.h b/xfa/fxfa/parser/cxfa_arraynodelist.h
index 346b206..238c52c 100644
--- a/xfa/fxfa/parser/cxfa_arraynodelist.h
+++ b/xfa/fxfa/parser/cxfa_arraynodelist.h
@@ -14,19 +14,19 @@
 class CXFA_Document;
 class CXFA_Node;
 
-class CXFA_ArrayNodeList : public CXFA_TreeList {
+class CXFA_ArrayNodeList final : public CXFA_TreeList {
  public:
   explicit CXFA_ArrayNodeList(CXFA_Document* pDocument);
   ~CXFA_ArrayNodeList() override;
 
-  // From CXFA_TreeList.
+  // CXFA_TreeList:
   size_t GetLength() override;
-  bool Append(CXFA_Node* pNode) override;
+  void Append(CXFA_Node* pNode) override;
   bool Insert(CXFA_Node* pNewNode, CXFA_Node* pBeforeNode) override;
-  bool Remove(CXFA_Node* pNode) override;
+  void Remove(CXFA_Node* pNode) override;
   CXFA_Node* Item(size_t iIndex) override;
 
-  void SetArrayNodeList(const std::vector<CXFA_Node*>& srcArray);
+  void SetArrayNodeList(std::vector<CXFA_Node*> srcArray);
 
  private:
   std::vector<CXFA_Node*> m_array;
diff --git a/xfa/fxfa/parser/cxfa_assist.cpp b/xfa/fxfa/parser/cxfa_assist.cpp
index 4286211..cac0bc6 100644
--- a/xfa/fxfa/parser/cxfa_assist.cpp
+++ b/xfa/fxfa/parser/cxfa_assist.cpp
@@ -6,22 +6,22 @@
 
 #include "xfa/fxfa/parser/cxfa_assist.h"
 
-#include "fxjs/xfa/cjx_assist.h"
+#include "fxjs/xfa/cjx_node.h"
 #include "third_party/base/ptr_util.h"
 
 namespace {
 
-const CXFA_Node::PropertyData kPropertyData[] = {{XFA_Element::ToolTip, 1, 0},
-                                                 {XFA_Element::Speak, 1, 0},
-                                                 {XFA_Element::Unknown, 0, 0}};
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::PropertyData kAssistPropertyData[] = {
+    {XFA_Element::ToolTip, 1, 0},
+    {XFA_Element::Speak, 1, 0},
+};
+
+const CXFA_Node::AttributeData kAssistAttributeData[] = {
     {XFA_Attribute::Id, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Use, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Role, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Usehref, XFA_AttributeType::CData, nullptr},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"assist";
+};
 
 }  // namespace
 
@@ -31,9 +31,8 @@
                 (XFA_XDPPACKET_Template | XFA_XDPPACKET_Form),
                 XFA_ObjectType::Node,
                 XFA_Element::Assist,
-                kPropertyData,
-                kAttributeData,
-                kName,
-                pdfium::MakeUnique<CJX_Assist>(this)) {}
+                kAssistPropertyData,
+                kAssistAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_Assist::~CXFA_Assist() {}
+CXFA_Assist::~CXFA_Assist() = default;
diff --git a/xfa/fxfa/parser/cxfa_assist.h b/xfa/fxfa/parser/cxfa_assist.h
index d0e9020..77643cf 100644
--- a/xfa/fxfa/parser/cxfa_assist.h
+++ b/xfa/fxfa/parser/cxfa_assist.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Assist : public CXFA_Node {
+class CXFA_Assist final : public CXFA_Node {
  public:
   CXFA_Assist(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Assist() override;
diff --git a/xfa/fxfa/parser/cxfa_attachnodelist.cpp b/xfa/fxfa/parser/cxfa_attachnodelist.cpp
index f1fbfa7..6d8e5c3 100644
--- a/xfa/fxfa/parser/cxfa_attachnodelist.cpp
+++ b/xfa/fxfa/parser/cxfa_attachnodelist.cpp
@@ -11,9 +11,9 @@
 
 CXFA_AttachNodeList::CXFA_AttachNodeList(CXFA_Document* pDocument,
                                          CXFA_Node* pAttachNode)
-    : CXFA_TreeList(pDocument) {
-  m_pAttachNode = pAttachNode;
-}
+    : CXFA_TreeList(pDocument), m_pAttachNode(pAttachNode) {}
+
+CXFA_AttachNodeList::~CXFA_AttachNodeList() = default;
 
 size_t CXFA_AttachNodeList::GetLength() {
   return m_pAttachNode->CountChildren(
@@ -21,24 +21,28 @@
       m_pAttachNode->GetElementType() == XFA_Element::Subform);
 }
 
-bool CXFA_AttachNodeList::Append(CXFA_Node* pNode) {
+void CXFA_AttachNodeList::Append(CXFA_Node* pNode) {
   CXFA_Node* pParent = pNode->GetParent();
   if (pParent)
-    pParent->RemoveChild(pNode, true);
+    pParent->RemoveChildAndNotify(pNode, true);
 
-  return m_pAttachNode->InsertChild(pNode, nullptr);
+  m_pAttachNode->InsertChildAndNotify(pNode, nullptr);
 }
 
 bool CXFA_AttachNodeList::Insert(CXFA_Node* pNewNode, CXFA_Node* pBeforeNode) {
+  if (pBeforeNode && pBeforeNode->GetParent() != m_pAttachNode)
+    return false;
+
   CXFA_Node* pParent = pNewNode->GetParent();
   if (pParent)
-    pParent->RemoveChild(pNewNode, true);
+    pParent->RemoveChildAndNotify(pNewNode, true);
 
-  return m_pAttachNode->InsertChild(pNewNode, pBeforeNode);
+  m_pAttachNode->InsertChildAndNotify(pNewNode, pBeforeNode);
+  return true;
 }
 
-bool CXFA_AttachNodeList::Remove(CXFA_Node* pNode) {
-  return m_pAttachNode->RemoveChild(pNode, true);
+void CXFA_AttachNodeList::Remove(CXFA_Node* pNode) {
+  m_pAttachNode->RemoveChildAndNotify(pNode, true);
 }
 
 CXFA_Node* CXFA_AttachNodeList::Item(size_t index) {
diff --git a/xfa/fxfa/parser/cxfa_attachnodelist.h b/xfa/fxfa/parser/cxfa_attachnodelist.h
index f0df2bb..2b20d70 100644
--- a/xfa/fxfa/parser/cxfa_attachnodelist.h
+++ b/xfa/fxfa/parser/cxfa_attachnodelist.h
@@ -12,19 +12,20 @@
 class CXFA_Document;
 class CXFA_Node;
 
-class CXFA_AttachNodeList : public CXFA_TreeList {
+class CXFA_AttachNodeList final : public CXFA_TreeList {
  public:
   CXFA_AttachNodeList(CXFA_Document* pDocument, CXFA_Node* pAttachNode);
+  ~CXFA_AttachNodeList() override;
 
-  // From CXFA_TreeList.
+  // CXFA_TreeList:
   size_t GetLength() override;
-  bool Append(CXFA_Node* pNode) override;
+  void Append(CXFA_Node* pNode) override;
   bool Insert(CXFA_Node* pNewNode, CXFA_Node* pBeforeNode) override;
-  bool Remove(CXFA_Node* pNode) override;
+  void Remove(CXFA_Node* pNode) override;
   CXFA_Node* Item(size_t iIndex) override;
 
  private:
-  CXFA_Node* m_pAttachNode;
+  UnownedPtr<CXFA_Node> const m_pAttachNode;
 };
 
 #endif  // XFA_FXFA_PARSER_CXFA_ATTACHNODELIST_H_
diff --git a/xfa/fxfa/parser/cxfa_attributes.cpp b/xfa/fxfa/parser/cxfa_attributes.cpp
index 80e58bd..aeaf8cf 100644
--- a/xfa/fxfa/parser/cxfa_attributes.cpp
+++ b/xfa/fxfa/parser/cxfa_attributes.cpp
@@ -6,14 +6,15 @@
 
 #include "xfa/fxfa/parser/cxfa_attributes.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kAttributesAttributeData[] = {
     {XFA_Attribute::Desc, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Lock, XFA_AttributeType::Integer, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"attributes";
+};
 
 }  // namespace
 
@@ -23,8 +24,8 @@
                 XFA_XDPPACKET_Config,
                 XFA_ObjectType::NodeV,
                 XFA_Element::Attributes,
-                nullptr,
-                kAttributeData,
-                kName) {}
+                {},
+                kAttributesAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_Attributes::~CXFA_Attributes() {}
+CXFA_Attributes::~CXFA_Attributes() = default;
diff --git a/xfa/fxfa/parser/cxfa_attributes.h b/xfa/fxfa/parser/cxfa_attributes.h
index fd73da8..099ecea 100644
--- a/xfa/fxfa/parser/cxfa_attributes.h
+++ b/xfa/fxfa/parser/cxfa_attributes.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Attributes : public CXFA_Node {
+class CXFA_Attributes final : public CXFA_Node {
  public:
   CXFA_Attributes(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Attributes() override;
diff --git a/xfa/fxfa/parser/cxfa_autosave.cpp b/xfa/fxfa/parser/cxfa_autosave.cpp
index d77c252..978cd56 100644
--- a/xfa/fxfa/parser/cxfa_autosave.cpp
+++ b/xfa/fxfa/parser/cxfa_autosave.cpp
@@ -6,14 +6,15 @@
 
 #include "xfa/fxfa/parser/cxfa_autosave.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kAutoSaveAttributeData[] = {
     {XFA_Attribute::Desc, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Lock, XFA_AttributeType::Integer, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"autoSave";
+};
 
 }  // namespace
 
@@ -23,8 +24,8 @@
                 XFA_XDPPACKET_Config,
                 XFA_ObjectType::NodeV,
                 XFA_Element::AutoSave,
-                nullptr,
-                kAttributeData,
-                kName) {}
+                {},
+                kAutoSaveAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_AutoSave::~CXFA_AutoSave() {}
+CXFA_AutoSave::~CXFA_AutoSave() = default;
diff --git a/xfa/fxfa/parser/cxfa_autosave.h b/xfa/fxfa/parser/cxfa_autosave.h
index b58ccf1..5324351 100644
--- a/xfa/fxfa/parser/cxfa_autosave.h
+++ b/xfa/fxfa/parser/cxfa_autosave.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_AutoSave : public CXFA_Node {
+class CXFA_AutoSave final : public CXFA_Node {
  public:
   CXFA_AutoSave(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_AutoSave() override;
diff --git a/xfa/fxfa/parser/cxfa_barcode.cpp b/xfa/fxfa/parser/cxfa_barcode.cpp
index d692291..a7dbb71 100644
--- a/xfa/fxfa/parser/cxfa_barcode.cpp
+++ b/xfa/fxfa/parser/cxfa_barcode.cpp
@@ -6,20 +6,21 @@
 
 #include "xfa/fxfa/parser/cxfa_barcode.h"
 
-#include "fxjs/xfa/cjx_barcode.h"
+#include "fxjs/xfa/cjx_node.h"
 #include "third_party/base/ptr_util.h"
+#include "xfa/fxfa/parser/cxfa_measurement.h"
 
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kBarcodeAttributeData[] = {
     {XFA_Attribute::Id, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::DataRowCount, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Use, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::DataPrep, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::None},
+     (void*)XFA_AttributeValue::None},
     {XFA_Attribute::Type, XFA_AttributeType::CData, (void*)nullptr},
     {XFA_Attribute::TextLocation, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::Below},
+     (void*)XFA_AttributeValue::Below},
     {XFA_Attribute::ModuleWidth, XFA_AttributeType::Measure, (void*)L"0.25mm"},
     {XFA_Attribute::PrintCheckDigit, XFA_AttributeType::Boolean, (void*)0},
     {XFA_Attribute::ModuleHeight, XFA_AttributeType::Measure, (void*)L"5mm"},
@@ -28,18 +29,16 @@
     {XFA_Attribute::WideNarrowRatio, XFA_AttributeType::CData, (void*)L"3:1"},
     {XFA_Attribute::ErrorCorrectionLevel, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::UpsMode, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::UsCarrier},
+     (void*)XFA_AttributeValue::UsCarrier},
     {XFA_Attribute::Checksum, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::None},
+     (void*)XFA_AttributeValue::None},
     {XFA_Attribute::CharEncoding, XFA_AttributeType::CData, (void*)L"UTF-8"},
     {XFA_Attribute::Usehref, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::DataColumnCount, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::RowColumnRatio, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::DataLength, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::EndChar, XFA_AttributeType::CData, nullptr},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"barcode";
+};
 
 }  // namespace
 
@@ -49,9 +48,126 @@
                 (XFA_XDPPACKET_Template | XFA_XDPPACKET_Form),
                 XFA_ObjectType::Node,
                 XFA_Element::Barcode,
-                nullptr,
-                kAttributeData,
-                kName,
-                pdfium::MakeUnique<CJX_Barcode>(this)) {}
+                {},
+                kBarcodeAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_Barcode::~CXFA_Barcode() {}
+CXFA_Barcode::~CXFA_Barcode() = default;
+
+XFA_FFWidgetType CXFA_Barcode::GetDefaultFFWidgetType() const {
+  return XFA_FFWidgetType::kBarcode;
+}
+
+WideString CXFA_Barcode::GetBarcodeType() {
+  return WideString(JSObject()->GetCData(XFA_Attribute::Type));
+}
+
+Optional<WideString> CXFA_Barcode::GetCharEncoding() {
+  return JSObject()->TryCData(XFA_Attribute::CharEncoding, true);
+}
+
+Optional<bool> CXFA_Barcode::GetChecksum() {
+  Optional<XFA_AttributeValue> checksum =
+      JSObject()->TryEnum(XFA_Attribute::Checksum, true);
+  if (!checksum)
+    return {};
+
+  switch (*checksum) {
+    case XFA_AttributeValue::None:
+      return {false};
+    case XFA_AttributeValue::Auto:
+      return {true};
+    case XFA_AttributeValue::Checksum_1mod10:
+    case XFA_AttributeValue::Checksum_1mod10_1mod11:
+    case XFA_AttributeValue::Checksum_2mod10:
+    default:
+      break;
+  }
+  return {};
+}
+
+Optional<int32_t> CXFA_Barcode::GetDataLength() {
+  Optional<WideString> wsDataLength =
+      JSObject()->TryCData(XFA_Attribute::DataLength, true);
+  if (!wsDataLength)
+    return {};
+
+  return {FXSYS_wtoi(wsDataLength->c_str())};
+}
+
+Optional<char> CXFA_Barcode::GetStartChar() {
+  Optional<WideString> wsStartEndChar =
+      JSObject()->TryCData(XFA_Attribute::StartChar, true);
+  if (!wsStartEndChar || wsStartEndChar->IsEmpty())
+    return {};
+
+  return {static_cast<char>((*wsStartEndChar)[0])};
+}
+
+Optional<char> CXFA_Barcode::GetEndChar() {
+  Optional<WideString> wsStartEndChar =
+      JSObject()->TryCData(XFA_Attribute::EndChar, true);
+  if (!wsStartEndChar || wsStartEndChar->IsEmpty())
+    return {};
+
+  return {static_cast<char>((*wsStartEndChar)[0])};
+}
+
+Optional<int32_t> CXFA_Barcode::GetECLevel() {
+  Optional<WideString> wsECLevel =
+      JSObject()->TryCData(XFA_Attribute::ErrorCorrectionLevel, true);
+  if (!wsECLevel)
+    return {};
+  return {FXSYS_wtoi(wsECLevel->c_str())};
+}
+
+Optional<int32_t> CXFA_Barcode::GetModuleWidth() {
+  Optional<CXFA_Measurement> moduleWidthHeight =
+      JSObject()->TryMeasure(XFA_Attribute::ModuleWidth, true);
+  if (!moduleWidthHeight)
+    return {};
+
+  return {static_cast<int32_t>(moduleWidthHeight->ToUnit(XFA_Unit::Pt))};
+}
+
+Optional<int32_t> CXFA_Barcode::GetModuleHeight() {
+  Optional<CXFA_Measurement> moduleWidthHeight =
+      JSObject()->TryMeasure(XFA_Attribute::ModuleHeight, true);
+  if (!moduleWidthHeight)
+    return {};
+
+  return {static_cast<int32_t>(moduleWidthHeight->ToUnit(XFA_Unit::Pt))};
+}
+
+Optional<bool> CXFA_Barcode::GetPrintChecksum() {
+  return JSObject()->TryBoolean(XFA_Attribute::PrintCheckDigit, true);
+}
+
+Optional<XFA_AttributeValue> CXFA_Barcode::GetTextLocation() {
+  return JSObject()->TryEnum(XFA_Attribute::TextLocation, true);
+}
+
+Optional<bool> CXFA_Barcode::GetTruncate() {
+  return JSObject()->TryBoolean(XFA_Attribute::Truncate, true);
+}
+
+Optional<int8_t> CXFA_Barcode::GetWideNarrowRatio() {
+  Optional<WideString> wsWideNarrowRatio =
+      JSObject()->TryCData(XFA_Attribute::WideNarrowRatio, true);
+  if (!wsWideNarrowRatio)
+    return {};
+
+  Optional<size_t> ptPos = wsWideNarrowRatio->Find(':');
+  if (!ptPos)
+    return {static_cast<int8_t>(FXSYS_wtoi(wsWideNarrowRatio->c_str()))};
+
+  int32_t fB = FXSYS_wtoi(
+      wsWideNarrowRatio->Last(wsWideNarrowRatio->GetLength() - (*ptPos + 1))
+          .c_str());
+  if (!fB)
+    return {0};
+
+  int32_t fA = FXSYS_wtoi(wsWideNarrowRatio->First(*ptPos).c_str());
+  float result = static_cast<float>(fA) / static_cast<float>(fB);
+  return {static_cast<int8_t>(result)};
+}
diff --git a/xfa/fxfa/parser/cxfa_barcode.h b/xfa/fxfa/parser/cxfa_barcode.h
index 469889b..219e8b3 100644
--- a/xfa/fxfa/parser/cxfa_barcode.h
+++ b/xfa/fxfa/parser/cxfa_barcode.h
@@ -7,12 +7,29 @@
 #ifndef XFA_FXFA_PARSER_CXFA_BARCODE_H_
 #define XFA_FXFA_PARSER_CXFA_BARCODE_H_
 
+#include "third_party/base/optional.h"
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Barcode : public CXFA_Node {
+class CXFA_Barcode final : public CXFA_Node {
  public:
   CXFA_Barcode(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Barcode() override;
+
+  XFA_FFWidgetType GetDefaultFFWidgetType() const override;
+
+  WideString GetBarcodeType();
+  Optional<WideString> GetCharEncoding();
+  Optional<bool> GetChecksum();
+  Optional<int32_t> GetDataLength();
+  Optional<char> GetStartChar();
+  Optional<char> GetEndChar();
+  Optional<int32_t> GetECLevel();
+  Optional<int32_t> GetModuleWidth();
+  Optional<int32_t> GetModuleHeight();
+  Optional<bool> GetPrintChecksum();
+  Optional<XFA_AttributeValue> GetTextLocation();
+  Optional<bool> GetTruncate();
+  Optional<int8_t> GetWideNarrowRatio();
 };
 
 #endif  // XFA_FXFA_PARSER_CXFA_BARCODE_H_
diff --git a/xfa/fxfa/parser/cxfa_base.cpp b/xfa/fxfa/parser/cxfa_base.cpp
index a82a79a..c5d0f88 100644
--- a/xfa/fxfa/parser/cxfa_base.cpp
+++ b/xfa/fxfa/parser/cxfa_base.cpp
@@ -6,14 +6,15 @@
 
 #include "xfa/fxfa/parser/cxfa_base.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kBaseAttributeData[] = {
     {XFA_Attribute::Desc, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Lock, XFA_AttributeType::Integer, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"base";
+};
 
 }  // namespace
 
@@ -23,8 +24,8 @@
                 XFA_XDPPACKET_Config,
                 XFA_ObjectType::ContentNode,
                 XFA_Element::Base,
-                nullptr,
-                kAttributeData,
-                kName) {}
+                {},
+                kBaseAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_Base::~CXFA_Base() {}
+CXFA_Base::~CXFA_Base() = default;
diff --git a/xfa/fxfa/parser/cxfa_base.h b/xfa/fxfa/parser/cxfa_base.h
index 3974343..3f1c9ba 100644
--- a/xfa/fxfa/parser/cxfa_base.h
+++ b/xfa/fxfa/parser/cxfa_base.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Base : public CXFA_Node {
+class CXFA_Base final : public CXFA_Node {
  public:
   CXFA_Base(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Base() override;
diff --git a/xfa/fxfa/parser/cxfa_batchoutput.cpp b/xfa/fxfa/parser/cxfa_batchoutput.cpp
index 1678d6a..daec03f 100644
--- a/xfa/fxfa/parser/cxfa_batchoutput.cpp
+++ b/xfa/fxfa/parser/cxfa_batchoutput.cpp
@@ -6,16 +6,17 @@
 
 #include "xfa/fxfa/parser/cxfa_batchoutput.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kBatchOutputAttributeData[] = {
     {XFA_Attribute::Format, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::None},
+     (void*)XFA_AttributeValue::None},
     {XFA_Attribute::Desc, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Lock, XFA_AttributeType::Integer, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"batchOutput";
+};
 
 }  // namespace
 
@@ -25,8 +26,8 @@
                 XFA_XDPPACKET_Config,
                 XFA_ObjectType::Node,
                 XFA_Element::BatchOutput,
-                nullptr,
-                kAttributeData,
-                kName) {}
+                {},
+                kBatchOutputAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_BatchOutput::~CXFA_BatchOutput() {}
+CXFA_BatchOutput::~CXFA_BatchOutput() = default;
diff --git a/xfa/fxfa/parser/cxfa_batchoutput.h b/xfa/fxfa/parser/cxfa_batchoutput.h
index 9faa6cf..8d1de09 100644
--- a/xfa/fxfa/parser/cxfa_batchoutput.h
+++ b/xfa/fxfa/parser/cxfa_batchoutput.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_BatchOutput : public CXFA_Node {
+class CXFA_BatchOutput final : public CXFA_Node {
  public:
   CXFA_BatchOutput(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_BatchOutput() override;
diff --git a/xfa/fxfa/parser/cxfa_behavioroverride.cpp b/xfa/fxfa/parser/cxfa_behavioroverride.cpp
index addf8f1..86ea80b 100644
--- a/xfa/fxfa/parser/cxfa_behavioroverride.cpp
+++ b/xfa/fxfa/parser/cxfa_behavioroverride.cpp
@@ -6,14 +6,15 @@
 
 #include "xfa/fxfa/parser/cxfa_behavioroverride.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kBehaviorOverrideAttributeData[] = {
     {XFA_Attribute::Desc, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Lock, XFA_AttributeType::Integer, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"behaviorOverride";
+};
 
 }  // namespace
 
@@ -24,8 +25,8 @@
                 XFA_XDPPACKET_Config,
                 XFA_ObjectType::ContentNode,
                 XFA_Element::BehaviorOverride,
-                nullptr,
-                kAttributeData,
-                kName) {}
+                {},
+                kBehaviorOverrideAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_BehaviorOverride::~CXFA_BehaviorOverride() {}
+CXFA_BehaviorOverride::~CXFA_BehaviorOverride() = default;
diff --git a/xfa/fxfa/parser/cxfa_behavioroverride.h b/xfa/fxfa/parser/cxfa_behavioroverride.h
index cb08211..d7dce1b 100644
--- a/xfa/fxfa/parser/cxfa_behavioroverride.h
+++ b/xfa/fxfa/parser/cxfa_behavioroverride.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_BehaviorOverride : public CXFA_Node {
+class CXFA_BehaviorOverride final : public CXFA_Node {
  public:
   CXFA_BehaviorOverride(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_BehaviorOverride() override;
diff --git a/xfa/fxfa/parser/cxfa_bind.cpp b/xfa/fxfa/parser/cxfa_bind.cpp
index d35a2cd..87f01e8 100644
--- a/xfa/fxfa/parser/cxfa_bind.cpp
+++ b/xfa/fxfa/parser/cxfa_bind.cpp
@@ -6,29 +6,29 @@
 
 #include "xfa/fxfa/parser/cxfa_bind.h"
 
-#include "fxjs/xfa/cjx_bind.h"
+#include "fxjs/xfa/cjx_node.h"
 #include "fxjs/xfa/cjx_object.h"
 #include "third_party/base/ptr_util.h"
 #include "xfa/fxfa/parser/cxfa_picture.h"
 
 namespace {
 
-const CXFA_Node::PropertyData kPropertyData[] = {{XFA_Element::Picture, 1, 0},
-                                                 {XFA_Element::Unknown, 0, 0}};
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::PropertyData kBindPropertyData[] = {
+    {XFA_Element::Picture, 1, 0},
+};
+
+const CXFA_Node::AttributeData kBindAttributeData[] = {
     {XFA_Attribute::Id, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Name, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Ref, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Use, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::ContentType, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::TransferEncoding, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::None},
+     (void*)XFA_AttributeValue::None},
     {XFA_Attribute::Usehref, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Match, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::Once},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"bind";
+     (void*)XFA_AttributeValue::Once},
+};
 
 }  // namespace
 
@@ -39,15 +39,14 @@
                  XFA_XDPPACKET_Form),
                 XFA_ObjectType::Node,
                 XFA_Element::Bind,
-                kPropertyData,
-                kAttributeData,
-                kName,
-                pdfium::MakeUnique<CJX_Bind>(this)) {}
+                kBindPropertyData,
+                kBindAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_Bind::~CXFA_Bind() {}
+CXFA_Bind::~CXFA_Bind() = default;
 
 WideString CXFA_Bind::GetPicture() {
   CXFA_Picture* pPicture =
       GetChild<CXFA_Picture>(0, XFA_Element::Picture, false);
-  return pPicture ? pPicture->JSObject()->GetContent(false) : L"";
+  return pPicture ? pPicture->JSObject()->GetContent(false) : WideString();
 }
diff --git a/xfa/fxfa/parser/cxfa_bind.h b/xfa/fxfa/parser/cxfa_bind.h
index 1924cb6..f6331d6 100644
--- a/xfa/fxfa/parser/cxfa_bind.h
+++ b/xfa/fxfa/parser/cxfa_bind.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Bind : public CXFA_Node {
+class CXFA_Bind final : public CXFA_Node {
  public:
   CXFA_Bind(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Bind() override;
diff --git a/xfa/fxfa/parser/cxfa_binditems.cpp b/xfa/fxfa/parser/cxfa_binditems.cpp
index d7d72a7..44badb8 100644
--- a/xfa/fxfa/parser/cxfa_binditems.cpp
+++ b/xfa/fxfa/parser/cxfa_binditems.cpp
@@ -6,19 +6,17 @@
 
 #include "xfa/fxfa/parser/cxfa_binditems.h"
 
-#include "fxjs/xfa/cjx_binditems.h"
+#include "fxjs/xfa/cjx_node.h"
 #include "third_party/base/ptr_util.h"
 
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kBindItemsAttributeData[] = {
     {XFA_Attribute::Ref, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Connection, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::LabelRef, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::ValueRef, XFA_AttributeType::CData, nullptr},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"bindItems";
+};
 
 }  // namespace
 
@@ -28,12 +26,11 @@
                 (XFA_XDPPACKET_Template | XFA_XDPPACKET_Form),
                 XFA_ObjectType::Node,
                 XFA_Element::BindItems,
-                nullptr,
-                kAttributeData,
-                kName,
-                pdfium::MakeUnique<CJX_BindItems>(this)) {}
+                {},
+                kBindItemsAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_BindItems::~CXFA_BindItems() {}
+CXFA_BindItems::~CXFA_BindItems() = default;
 
 WideString CXFA_BindItems::GetLabelRef() {
   return JSObject()->GetCData(XFA_Attribute::LabelRef);
diff --git a/xfa/fxfa/parser/cxfa_binditems.h b/xfa/fxfa/parser/cxfa_binditems.h
index f1a490d..34a4b67 100644
--- a/xfa/fxfa/parser/cxfa_binditems.h
+++ b/xfa/fxfa/parser/cxfa_binditems.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_BindItems : public CXFA_Node {
+class CXFA_BindItems final : public CXFA_Node {
  public:
   CXFA_BindItems(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_BindItems() override;
diff --git a/xfa/fxfa/parser/cxfa_bookend.cpp b/xfa/fxfa/parser/cxfa_bookend.cpp
index 6b172be..143a484 100644
--- a/xfa/fxfa/parser/cxfa_bookend.cpp
+++ b/xfa/fxfa/parser/cxfa_bookend.cpp
@@ -6,20 +6,18 @@
 
 #include "xfa/fxfa/parser/cxfa_bookend.h"
 
-#include "fxjs/xfa/cjx_bookend.h"
+#include "fxjs/xfa/cjx_node.h"
 #include "third_party/base/ptr_util.h"
 
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kBookendAttributeData[] = {
     {XFA_Attribute::Id, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Use, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Trailer, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Usehref, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Leader, XFA_AttributeType::CData, nullptr},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"bookend";
+};
 
 }  // namespace
 
@@ -29,9 +27,8 @@
                 (XFA_XDPPACKET_Template | XFA_XDPPACKET_Form),
                 XFA_ObjectType::Node,
                 XFA_Element::Bookend,
-                nullptr,
-                kAttributeData,
-                kName,
-                pdfium::MakeUnique<CJX_Bookend>(this)) {}
+                {},
+                kBookendAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_Bookend::~CXFA_Bookend() {}
+CXFA_Bookend::~CXFA_Bookend() = default;
diff --git a/xfa/fxfa/parser/cxfa_bookend.h b/xfa/fxfa/parser/cxfa_bookend.h
index 82eb13c..1c68763 100644
--- a/xfa/fxfa/parser/cxfa_bookend.h
+++ b/xfa/fxfa/parser/cxfa_bookend.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Bookend : public CXFA_Node {
+class CXFA_Bookend final : public CXFA_Node {
  public:
   CXFA_Bookend(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Bookend() override;
diff --git a/xfa/fxfa/parser/cxfa_boolean.cpp b/xfa/fxfa/parser/cxfa_boolean.cpp
index f804919..919d679 100644
--- a/xfa/fxfa/parser/cxfa_boolean.cpp
+++ b/xfa/fxfa/parser/cxfa_boolean.cpp
@@ -11,14 +11,12 @@
 
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kBooleanAttributeData[] = {
     {XFA_Attribute::Id, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Name, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Use, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Usehref, XFA_AttributeType::CData, nullptr},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"boolean";
+};
 
 }  // namespace
 
@@ -29,9 +27,8 @@
                  XFA_XDPPACKET_Form),
                 XFA_ObjectType::ContentNode,
                 XFA_Element::Boolean,
-                nullptr,
-                kAttributeData,
-                kName,
+                {},
+                kBooleanAttributeData,
                 pdfium::MakeUnique<CJX_Boolean>(this)) {}
 
 CXFA_Boolean::~CXFA_Boolean() {}
diff --git a/xfa/fxfa/parser/cxfa_boolean.h b/xfa/fxfa/parser/cxfa_boolean.h
index 4121e36..60b8e5e 100644
--- a/xfa/fxfa/parser/cxfa_boolean.h
+++ b/xfa/fxfa/parser/cxfa_boolean.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Boolean : public CXFA_Node {
+class CXFA_Boolean final : public CXFA_Node {
  public:
   CXFA_Boolean(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Boolean() override;
diff --git a/xfa/fxfa/parser/cxfa_border.cpp b/xfa/fxfa/parser/cxfa_border.cpp
index eb87562..1d315ad 100644
--- a/xfa/fxfa/parser/cxfa_border.cpp
+++ b/xfa/fxfa/parser/cxfa_border.cpp
@@ -6,29 +6,29 @@
 
 #include "xfa/fxfa/parser/cxfa_border.h"
 
-#include "fxjs/xfa/cjx_border.h"
+#include "fxjs/xfa/cjx_node.h"
 #include "third_party/base/ptr_util.h"
 
 namespace {
 
-const CXFA_Node::PropertyData kPropertyData[] = {
+const CXFA_Node::PropertyData kBorderPropertyData[] = {
     {XFA_Element::Margin, 1, 0}, {XFA_Element::Edge, 4, 0},
     {XFA_Element::Corner, 4, 0}, {XFA_Element::Fill, 1, 0},
-    {XFA_Element::Extras, 1, 0}, {XFA_Element::Unknown, 0, 0}};
-const CXFA_Node::AttributeData kAttributeData[] = {
+    {XFA_Element::Extras, 1, 0},
+};
+
+const CXFA_Node::AttributeData kBorderAttributeData[] = {
     {XFA_Attribute::Id, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Break, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::Close},
+     (void*)XFA_AttributeValue::Close},
     {XFA_Attribute::Use, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Presence, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::Visible},
+     (void*)XFA_AttributeValue::Visible},
     {XFA_Attribute::Relevant, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Usehref, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Hand, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::Even},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"border";
+     (void*)XFA_AttributeValue::Even},
+};
 
 }  // namespace
 
@@ -38,9 +38,8 @@
                      (XFA_XDPPACKET_Template | XFA_XDPPACKET_Form),
                      XFA_ObjectType::Node,
                      XFA_Element::Border,
-                     kPropertyData,
-                     kAttributeData,
-                     kName,
-                     pdfium::MakeUnique<CJX_Border>(this)) {}
+                     kBorderPropertyData,
+                     kBorderAttributeData,
+                     pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_Border::~CXFA_Border() {}
+CXFA_Border::~CXFA_Border() = default;
diff --git a/xfa/fxfa/parser/cxfa_border.h b/xfa/fxfa/parser/cxfa_border.h
index 24f3bb9..6071a77 100644
--- a/xfa/fxfa/parser/cxfa_border.h
+++ b/xfa/fxfa/parser/cxfa_border.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_rectangle.h"
 
-class CXFA_Border : public CXFA_Rectangle {
+class CXFA_Border final : public CXFA_Rectangle {
  public:
   CXFA_Border(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Border() override;
diff --git a/xfa/fxfa/parser/cxfa_box.cpp b/xfa/fxfa/parser/cxfa_box.cpp
index b814612..5ba01d3 100644
--- a/xfa/fxfa/parser/cxfa_box.cpp
+++ b/xfa/fxfa/parser/cxfa_box.cpp
@@ -24,10 +24,10 @@
 
 namespace {
 
-std::pair<XFA_AttributeEnum, CXFA_Stroke*> Style3D(
+std::pair<XFA_AttributeValue, CXFA_Stroke*> Style3D(
     const std::vector<CXFA_Stroke*>& strokes) {
   if (strokes.empty())
-    return {XFA_AttributeEnum::Unknown, nullptr};
+    return {XFA_AttributeValue::Unknown, nullptr};
 
   CXFA_Stroke* stroke = strokes[0];
   for (size_t i = 1; i < strokes.size(); i++) {
@@ -41,14 +41,14 @@
     break;
   }
 
-  XFA_AttributeEnum iType = stroke->GetStrokeType();
-  if (iType == XFA_AttributeEnum::Lowered ||
-      iType == XFA_AttributeEnum::Raised ||
-      iType == XFA_AttributeEnum::Etched ||
-      iType == XFA_AttributeEnum::Embossed) {
+  XFA_AttributeValue iType = stroke->GetStrokeType();
+  if (iType == XFA_AttributeValue::Lowered ||
+      iType == XFA_AttributeValue::Raised ||
+      iType == XFA_AttributeValue::Etched ||
+      iType == XFA_AttributeValue::Embossed) {
     return {iType, stroke};
   }
-  return {XFA_AttributeEnum::Unknown, stroke};
+  return {XFA_AttributeValue::Unknown, stroke};
 }
 
 CXFA_Rectangle* ToRectangle(CXFA_Box* box) {
@@ -62,9 +62,8 @@
                    uint32_t validPackets,
                    XFA_ObjectType oType,
                    XFA_Element eType,
-                   const PropertyData* properties,
-                   const AttributeData* attributes,
-                   const WideStringView& elementName,
+                   pdfium::span<const PropertyData> properties,
+                   pdfium::span<const AttributeData> attributes,
                    std::unique_ptr<CJX_Object> js_node)
     : CXFA_Node(pDoc,
                 ePacket,
@@ -73,19 +72,18 @@
                 eType,
                 properties,
                 attributes,
-                elementName,
                 std::move(js_node)) {}
 
 CXFA_Box::~CXFA_Box() = default;
 
-XFA_AttributeEnum CXFA_Box::GetHand() {
+XFA_AttributeValue CXFA_Box::GetHand() {
   return JSObject()->GetEnum(XFA_Attribute::Hand);
 }
 
-XFA_AttributeEnum CXFA_Box::GetPresence() {
+XFA_AttributeValue CXFA_Box::GetPresence() {
   return JSObject()
       ->TryEnum(XFA_Attribute::Presence, true)
-      .value_or(XFA_AttributeEnum::Visible);
+      .value_or(XFA_AttributeValue::Visible);
 }
 
 int32_t CXFA_Box::CountEdges() {
@@ -119,17 +117,17 @@
   return JSObject()->GetOrCreateProperty<CXFA_Fill>(0, XFA_Element::Fill);
 }
 
-std::tuple<XFA_AttributeEnum, bool, float> CXFA_Box::Get3DStyle() {
+std::tuple<XFA_AttributeValue, bool, float> CXFA_Box::Get3DStyle() {
   if (GetElementType() == XFA_Element::Arc)
-    return {XFA_AttributeEnum::Unknown, false, 0.0f};
+    return {XFA_AttributeValue::Unknown, false, 0.0f};
 
   std::vector<CXFA_Stroke*> strokes = GetStrokesInternal(true);
   CXFA_Stroke* stroke;
-  XFA_AttributeEnum iType;
+  XFA_AttributeValue iType;
 
   std::tie(iType, stroke) = Style3D(strokes);
-  if (iType == XFA_AttributeEnum::Unknown)
-    return {XFA_AttributeEnum::Unknown, false, 0.0f};
+  if (iType == XFA_AttributeValue::Unknown)
+    return {XFA_AttributeValue::Unknown, false, 0.0f};
 
   return {iType, stroke->IsVisible(), stroke->GetThickness()};
 }
@@ -184,7 +182,7 @@
                     const CFX_RectF& rtWidget,
                     const CFX_Matrix& matrix,
                     bool forceRound) {
-  if (GetPresence() != XFA_AttributeEnum::Visible)
+  if (GetPresence() != XFA_AttributeValue::Visible)
     return;
 
   XFA_Element eType = GetElementType();
@@ -224,13 +222,13 @@
     CXFA_Edge* edge = GetEdgeIfExists(0);
     float fThickness = std::fmax(0.0, edge ? edge->GetThickness() : 0);
     float fHalf = fThickness / 2;
-    XFA_AttributeEnum iHand = GetHand();
-    if (iHand == XFA_AttributeEnum::Left)
+    XFA_AttributeValue iHand = GetHand();
+    if (iHand == XFA_AttributeValue::Left)
       rtWidget.Inflate(fHalf, fHalf);
-    else if (iHand == XFA_AttributeEnum::Right)
+    else if (iHand == XFA_AttributeValue::Right)
       rtWidget.Deflate(fHalf, fHalf);
 
-    GetPathArcOrRounded(rtWidget, fillPath, forceRound);
+    GetPathArcOrRounded(rtWidget, forceRound, &fillPath);
   } else if (type == XFA_Element::Rectangle || type == XFA_Element::Border) {
     ToRectangle(this)->GetFillPath(strokes, rtWidget, &fillPath);
   } else {
@@ -243,8 +241,8 @@
 }
 
 void CXFA_Box::GetPathArcOrRounded(CFX_RectF rtDraw,
-                                   CXFA_GEPath& fillPath,
-                                   bool forceRound) {
+                                   bool forceRound,
+                                   CXFA_GEPath* fillPath) {
   float a, b;
   a = rtDraw.width / 2.0f;
   b = rtDraw.height / 2.0f;
@@ -259,13 +257,13 @@
   Optional<int32_t> startAngle = GetStartAngle();
   Optional<int32_t> sweepAngle = GetSweepAngle();
   if (!startAngle && !sweepAngle) {
-    fillPath.AddEllipse(rtDraw);
+    fillPath->AddEllipse(rtDraw);
     return;
   }
 
-  fillPath.AddArc(rtDraw.TopLeft(), rtDraw.Size(),
-                  -startAngle.value_or(0) * FX_PI / 180.0f,
-                  -sweepAngle.value_or(360) * FX_PI / 180.0f);
+  fillPath->AddArc(rtDraw.TopLeft(), rtDraw.Size(),
+                   -startAngle.value_or(0) * FX_PI / 180.0f,
+                   -sweepAngle.value_or(360) * FX_PI / 180.0f);
 }
 
 void CXFA_Box::StrokeArcOrRounded(CXFA_Graphics* pGS,
@@ -278,10 +276,10 @@
 
   bool bVisible;
   float fThickness;
-  XFA_AttributeEnum i3DType;
+  XFA_AttributeValue i3DType;
   std::tie(i3DType, bVisible, fThickness) = Get3DStyle();
   bool lowered3d = false;
-  if (i3DType != XFA_AttributeEnum::Unknown) {
+  if (i3DType != XFA_AttributeValue::Unknown) {
     if (bVisible && fThickness >= 0.001f)
       lowered3d = true;
   }
@@ -291,10 +289,10 @@
     fHalf = 0;
   }
 
-  XFA_AttributeEnum iHand = GetHand();
-  if (iHand == XFA_AttributeEnum::Left) {
+  XFA_AttributeValue iHand = GetHand();
+  if (iHand == XFA_AttributeValue::Left) {
     rtWidget.Inflate(fHalf, fHalf);
-  } else if (iHand == XFA_AttributeEnum::Right) {
+  } else if (iHand == XFA_AttributeValue::Right) {
     rtWidget.Deflate(fHalf, fHalf);
   }
   if (!forceRound || !lowered3d) {
@@ -302,7 +300,7 @@
       return;
 
     CXFA_GEPath arcPath;
-    GetPathArcOrRounded(rtWidget, arcPath, forceRound);
+    GetPathArcOrRounded(rtWidget, forceRound, &arcPath);
     if (edge)
       edge->Stroke(&arcPath, pGS, matrix);
     return;
@@ -324,10 +322,6 @@
   rtWidget.width = a + a;
   rtWidget.height = b + b;
 
-  float startAngle = 0, sweepAngle = 360;
-  startAngle = startAngle * FX_PI / 180.0f;
-  sweepAngle = -sweepAngle * FX_PI / 180.0f;
-
   CXFA_GEPath arcPath;
   arcPath.AddArc(rtWidget.TopLeft(), rtWidget.Size(), 3.0f * FX_PI / 4.0f,
                  FX_PI);
diff --git a/xfa/fxfa/parser/cxfa_box.h b/xfa/fxfa/parser/cxfa_box.h
index 0831cd6..cbda771 100644
--- a/xfa/fxfa/parser/cxfa_box.h
+++ b/xfa/fxfa/parser/cxfa_box.h
@@ -25,8 +25,8 @@
  public:
   ~CXFA_Box() override;
 
-  XFA_AttributeEnum GetPresence();
-  std::tuple<XFA_AttributeEnum, bool, float> Get3DStyle();
+  XFA_AttributeValue GetPresence();
+  std::tuple<XFA_AttributeValue, bool, float> Get3DStyle();
 
   int32_t CountEdges();
   CXFA_Edge* GetEdgeIfExists(int32_t nIndex);
@@ -45,12 +45,11 @@
            uint32_t validPackets,
            XFA_ObjectType oType,
            XFA_Element eType,
-           const PropertyData* properties,
-           const AttributeData* attributes,
-           const WideStringView& elementName,
+           pdfium::span<const PropertyData> properties,
+           pdfium::span<const AttributeData> attributes,
            std::unique_ptr<CJX_Object> js_node);
 
-  XFA_AttributeEnum GetHand();
+  XFA_AttributeValue GetHand();
 
  private:
   bool IsCircular();
@@ -68,8 +67,8 @@
                           const CFX_Matrix& matrix,
                           bool forceRound);
   void GetPathArcOrRounded(CFX_RectF rtDraw,
-                           CXFA_GEPath& fillPath,
-                           bool forceRound);
+                           bool forceRound,
+                           CXFA_GEPath* fillPath);
 };
 
 #endif  // XFA_FXFA_PARSER_CXFA_BOX_H_
diff --git a/xfa/fxfa/parser/cxfa_break.cpp b/xfa/fxfa/parser/cxfa_break.cpp
index 3a83b1c..e02fa1e 100644
--- a/xfa/fxfa/parser/cxfa_break.cpp
+++ b/xfa/fxfa/parser/cxfa_break.cpp
@@ -6,14 +6,16 @@
 
 #include "xfa/fxfa/parser/cxfa_break.h"
 
-#include "fxjs/xfa/cjx_break.h"
+#include "fxjs/xfa/cjx_node.h"
 #include "third_party/base/ptr_util.h"
 
 namespace {
 
-const CXFA_Node::PropertyData kPropertyData[] = {{XFA_Element::Extras, 1, 0},
-                                                 {XFA_Element::Unknown, 0, 0}};
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::PropertyData kBreakPropertyData[] = {
+    {XFA_Element::Extras, 1, 0},
+};
+
+const CXFA_Node::AttributeData kBreakAttributeData[] = {
     {XFA_Attribute::Id, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::BeforeTarget, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Use, XFA_AttributeType::CData, nullptr},
@@ -23,15 +25,13 @@
     {XFA_Attribute::StartNew, XFA_AttributeType::Boolean, (void*)0},
     {XFA_Attribute::BookendTrailer, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::After, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::Auto},
+     (void*)XFA_AttributeValue::Auto},
     {XFA_Attribute::Usehref, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::BookendLeader, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::AfterTarget, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Before, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::Auto},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"break";
+     (void*)XFA_AttributeValue::Auto},
+};
 
 }  // namespace
 
@@ -41,9 +41,8 @@
                 (XFA_XDPPACKET_Template | XFA_XDPPACKET_Form),
                 XFA_ObjectType::Node,
                 XFA_Element::Break,
-                kPropertyData,
-                kAttributeData,
-                kName,
-                pdfium::MakeUnique<CJX_Break>(this)) {}
+                kBreakPropertyData,
+                kBreakAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_Break::~CXFA_Break() {}
+CXFA_Break::~CXFA_Break() = default;
diff --git a/xfa/fxfa/parser/cxfa_break.h b/xfa/fxfa/parser/cxfa_break.h
index c0d937c..4bf7dde 100644
--- a/xfa/fxfa/parser/cxfa_break.h
+++ b/xfa/fxfa/parser/cxfa_break.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Break : public CXFA_Node {
+class CXFA_Break final : public CXFA_Node {
  public:
   CXFA_Break(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Break() override;
diff --git a/xfa/fxfa/parser/cxfa_breakafter.cpp b/xfa/fxfa/parser/cxfa_breakafter.cpp
index 925b721..252a607 100644
--- a/xfa/fxfa/parser/cxfa_breakafter.cpp
+++ b/xfa/fxfa/parser/cxfa_breakafter.cpp
@@ -6,26 +6,26 @@
 
 #include "xfa/fxfa/parser/cxfa_breakafter.h"
 
-#include "fxjs/xfa/cjx_breakafter.h"
+#include "fxjs/xfa/cjx_node.h"
 #include "third_party/base/ptr_util.h"
 
 namespace {
 
-const CXFA_Node::PropertyData kPropertyData[] = {{XFA_Element::Script, 1, 0},
-                                                 {XFA_Element::Unknown, 0, 0}};
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::PropertyData kBreakAfterPropertyData[] = {
+    {XFA_Element::Script, 1, 0},
+};
+
+const CXFA_Node::AttributeData kBreakAfterAttributeData[] = {
     {XFA_Attribute::Id, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Use, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::StartNew, XFA_AttributeType::Boolean, (void*)0},
     {XFA_Attribute::Trailer, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::TargetType, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::Auto},
+     (void*)XFA_AttributeValue::Auto},
     {XFA_Attribute::Usehref, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Target, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Leader, XFA_AttributeType::CData, nullptr},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"breakAfter";
+};
 
 }  // namespace
 
@@ -35,9 +35,8 @@
                 (XFA_XDPPACKET_Template | XFA_XDPPACKET_Form),
                 XFA_ObjectType::Node,
                 XFA_Element::BreakAfter,
-                kPropertyData,
-                kAttributeData,
-                kName,
-                pdfium::MakeUnique<CJX_BreakAfter>(this)) {}
+                kBreakAfterPropertyData,
+                kBreakAfterAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_BreakAfter::~CXFA_BreakAfter() {}
+CXFA_BreakAfter::~CXFA_BreakAfter() = default;
diff --git a/xfa/fxfa/parser/cxfa_breakafter.h b/xfa/fxfa/parser/cxfa_breakafter.h
index 952b0c9..c607ef5 100644
--- a/xfa/fxfa/parser/cxfa_breakafter.h
+++ b/xfa/fxfa/parser/cxfa_breakafter.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_BreakAfter : public CXFA_Node {
+class CXFA_BreakAfter final : public CXFA_Node {
  public:
   CXFA_BreakAfter(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_BreakAfter() override;
diff --git a/xfa/fxfa/parser/cxfa_breakbefore.cpp b/xfa/fxfa/parser/cxfa_breakbefore.cpp
index c8dcade..0518ae1 100644
--- a/xfa/fxfa/parser/cxfa_breakbefore.cpp
+++ b/xfa/fxfa/parser/cxfa_breakbefore.cpp
@@ -6,26 +6,26 @@
 
 #include "xfa/fxfa/parser/cxfa_breakbefore.h"
 
-#include "fxjs/xfa/cjx_breakbefore.h"
+#include "fxjs/xfa/cjx_node.h"
 #include "third_party/base/ptr_util.h"
 
 namespace {
 
-const CXFA_Node::PropertyData kPropertyData[] = {{XFA_Element::Script, 1, 0},
-                                                 {XFA_Element::Unknown, 0, 0}};
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::PropertyData kBreakBeforePropertyData[] = {
+    {XFA_Element::Script, 1, 0},
+};
+
+const CXFA_Node::AttributeData kBreakBeforeAttributeData[] = {
     {XFA_Attribute::Id, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Use, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::StartNew, XFA_AttributeType::Boolean, (void*)0},
     {XFA_Attribute::Trailer, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::TargetType, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::Auto},
+     (void*)XFA_AttributeValue::Auto},
     {XFA_Attribute::Usehref, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Target, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Leader, XFA_AttributeType::CData, nullptr},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"breakBefore";
+};
 
 }  // namespace
 
@@ -35,9 +35,8 @@
                 (XFA_XDPPACKET_Template | XFA_XDPPACKET_Form),
                 XFA_ObjectType::Node,
                 XFA_Element::BreakBefore,
-                kPropertyData,
-                kAttributeData,
-                kName,
-                pdfium::MakeUnique<CJX_BreakBefore>(this)) {}
+                kBreakBeforePropertyData,
+                kBreakBeforeAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_BreakBefore::~CXFA_BreakBefore() {}
+CXFA_BreakBefore::~CXFA_BreakBefore() = default;
diff --git a/xfa/fxfa/parser/cxfa_breakbefore.h b/xfa/fxfa/parser/cxfa_breakbefore.h
index 358e477..1b6dc63 100644
--- a/xfa/fxfa/parser/cxfa_breakbefore.h
+++ b/xfa/fxfa/parser/cxfa_breakbefore.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_BreakBefore : public CXFA_Node {
+class CXFA_BreakBefore final : public CXFA_Node {
  public:
   CXFA_BreakBefore(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_BreakBefore() override;
diff --git a/xfa/fxfa/parser/cxfa_button.cpp b/xfa/fxfa/parser/cxfa_button.cpp
index 2b62efb..4b35aad 100644
--- a/xfa/fxfa/parser/cxfa_button.cpp
+++ b/xfa/fxfa/parser/cxfa_button.cpp
@@ -6,22 +6,22 @@
 
 #include "xfa/fxfa/parser/cxfa_button.h"
 
-#include "fxjs/xfa/cjx_button.h"
+#include "fxjs/xfa/cjx_node.h"
 #include "third_party/base/ptr_util.h"
 
 namespace {
 
-const CXFA_Node::PropertyData kPropertyData[] = {{XFA_Element::Extras, 1, 0},
-                                                 {XFA_Element::Unknown, 0, 0}};
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::PropertyData kButtonPropertyData[] = {
+    {XFA_Element::Extras, 1, 0},
+};
+
+const CXFA_Node::AttributeData kButtonAttributeData[] = {
     {XFA_Attribute::Id, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Use, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Usehref, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Highlight, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::Inverted},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"button";
+     (void*)XFA_AttributeValue::Inverted},
+};
 
 }  // namespace
 
@@ -31,9 +31,16 @@
                 (XFA_XDPPACKET_Template | XFA_XDPPACKET_Form),
                 XFA_ObjectType::Node,
                 XFA_Element::Button,
-                kPropertyData,
-                kAttributeData,
-                kName,
-                pdfium::MakeUnique<CJX_Button>(this)) {}
+                kButtonPropertyData,
+                kButtonAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_Button::~CXFA_Button() {}
+CXFA_Button::~CXFA_Button() = default;
+
+XFA_FFWidgetType CXFA_Button::GetDefaultFFWidgetType() const {
+  return XFA_FFWidgetType::kButton;
+}
+
+XFA_AttributeValue CXFA_Button::GetHighlight() {
+  return JSObject()->GetEnum(XFA_Attribute::Highlight);
+}
diff --git a/xfa/fxfa/parser/cxfa_button.h b/xfa/fxfa/parser/cxfa_button.h
index 86ffb52..1eddd65 100644
--- a/xfa/fxfa/parser/cxfa_button.h
+++ b/xfa/fxfa/parser/cxfa_button.h
@@ -9,10 +9,14 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Button : public CXFA_Node {
+class CXFA_Button final : public CXFA_Node {
  public:
   CXFA_Button(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Button() override;
+
+  XFA_FFWidgetType GetDefaultFFWidgetType() const override;
+
+  XFA_AttributeValue GetHighlight();
 };
 
 #endif  // XFA_FXFA_PARSER_CXFA_BUTTON_H_
diff --git a/xfa/fxfa/parser/cxfa_cache.cpp b/xfa/fxfa/parser/cxfa_cache.cpp
index 74227a3..8b51c02 100644
--- a/xfa/fxfa/parser/cxfa_cache.cpp
+++ b/xfa/fxfa/parser/cxfa_cache.cpp
@@ -6,17 +6,19 @@
 
 #include "xfa/fxfa/parser/cxfa_cache.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::PropertyData kPropertyData[] = {
+const CXFA_Node::PropertyData kCachePropertyData[] = {
     {XFA_Element::TemplateCache, 1, 0},
-    {XFA_Element::Unknown, 0, 0}};
-const CXFA_Node::AttributeData kAttributeData[] = {
+};
+
+const CXFA_Node::AttributeData kCacheAttributeData[] = {
     {XFA_Attribute::Desc, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Lock, XFA_AttributeType::Integer, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"cache";
+};
 
 }  // namespace
 
@@ -26,8 +28,8 @@
                 XFA_XDPPACKET_Config,
                 XFA_ObjectType::Node,
                 XFA_Element::Cache,
-                kPropertyData,
-                kAttributeData,
-                kName) {}
+                kCachePropertyData,
+                kCacheAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
 CXFA_Cache::~CXFA_Cache() {}
diff --git a/xfa/fxfa/parser/cxfa_cache.h b/xfa/fxfa/parser/cxfa_cache.h
index e3907c6..430163a 100644
--- a/xfa/fxfa/parser/cxfa_cache.h
+++ b/xfa/fxfa/parser/cxfa_cache.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Cache : public CXFA_Node {
+class CXFA_Cache final : public CXFA_Node {
  public:
   CXFA_Cache(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Cache() override;
diff --git a/xfa/fxfa/parser/cxfa_calculate.cpp b/xfa/fxfa/parser/cxfa_calculate.cpp
index 3286787..ce79864 100644
--- a/xfa/fxfa/parser/cxfa_calculate.cpp
+++ b/xfa/fxfa/parser/cxfa_calculate.cpp
@@ -6,7 +6,7 @@
 
 #include "xfa/fxfa/parser/cxfa_calculate.h"
 
-#include "fxjs/xfa/cjx_calculate.h"
+#include "fxjs/xfa/cjx_node.h"
 #include "third_party/base/ptr_util.h"
 #include "xfa/fxfa/parser/cxfa_message.h"
 #include "xfa/fxfa/parser/cxfa_script.h"
@@ -14,19 +14,19 @@
 
 namespace {
 
-const CXFA_Node::PropertyData kPropertyData[] = {{XFA_Element::Message, 1, 0},
-                                                 {XFA_Element::Script, 1, 0},
-                                                 {XFA_Element::Extras, 1, 0},
-                                                 {XFA_Element::Unknown, 0, 0}};
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::PropertyData kCalculatePropertyData[] = {
+    {XFA_Element::Message, 1, 0},
+    {XFA_Element::Script, 1, 0},
+    {XFA_Element::Extras, 1, 0},
+};
+
+const CXFA_Node::AttributeData kCalculateAttributeData[] = {
     {XFA_Attribute::Id, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Use, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Usehref, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Override, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::Error},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"calculate";
+     (void*)XFA_AttributeValue::Error},
+};
 
 }  // namespace
 
@@ -36,17 +36,16 @@
                 (XFA_XDPPACKET_Template | XFA_XDPPACKET_Form),
                 XFA_ObjectType::Node,
                 XFA_Element::Calculate,
-                kPropertyData,
-                kAttributeData,
-                kName,
-                pdfium::MakeUnique<CJX_Calculate>(this)) {}
+                kCalculatePropertyData,
+                kCalculateAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_Calculate::~CXFA_Calculate() {}
+CXFA_Calculate::~CXFA_Calculate() = default;
 
-XFA_AttributeEnum CXFA_Calculate::GetOverride() {
+XFA_AttributeValue CXFA_Calculate::GetOverride() {
   return JSObject()
       ->TryEnum(XFA_Attribute::Override, false)
-      .value_or(XFA_AttributeEnum::Error);
+      .value_or(XFA_AttributeValue::Error);
 }
 
 CXFA_Script* CXFA_Calculate::GetScriptIfExists() {
@@ -56,8 +55,8 @@
 WideString CXFA_Calculate::GetMessageText() {
   CXFA_Message* pNode = GetChild<CXFA_Message>(0, XFA_Element::Message, false);
   if (!pNode)
-    return L"";
+    return WideString();
 
   CXFA_Text* text = pNode->GetChild<CXFA_Text>(0, XFA_Element::Text, false);
-  return text ? text->GetContent() : L"";
+  return text ? text->GetContent() : WideString();
 }
diff --git a/xfa/fxfa/parser/cxfa_calculate.h b/xfa/fxfa/parser/cxfa_calculate.h
index a5be908..a3934ac 100644
--- a/xfa/fxfa/parser/cxfa_calculate.h
+++ b/xfa/fxfa/parser/cxfa_calculate.h
@@ -11,12 +11,12 @@
 
 class CXFA_Script;
 
-class CXFA_Calculate : public CXFA_Node {
+class CXFA_Calculate final : public CXFA_Node {
  public:
   CXFA_Calculate(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Calculate() override;
 
-  XFA_AttributeEnum GetOverride();
+  XFA_AttributeValue GetOverride();
   CXFA_Script* GetScriptIfExists();
   WideString GetMessageText();
 };
diff --git a/xfa/fxfa/parser/cxfa_calendarsymbols.cpp b/xfa/fxfa/parser/cxfa_calendarsymbols.cpp
index c9ad3b5..155a296 100644
--- a/xfa/fxfa/parser/cxfa_calendarsymbols.cpp
+++ b/xfa/fxfa/parser/cxfa_calendarsymbols.cpp
@@ -6,20 +6,22 @@
 
 #include "xfa/fxfa/parser/cxfa_calendarsymbols.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::PropertyData kPropertyData[] = {
+const CXFA_Node::PropertyData kCalendarSymbolsPropertyData[] = {
     {XFA_Element::EraNames, 1, 0},
     {XFA_Element::DayNames, 2, 0},
     {XFA_Element::MeridiemNames, 1, 0},
     {XFA_Element::MonthNames, 2, 0},
-    {XFA_Element::Unknown, 0, 0}};
-const CXFA_Node::AttributeData kAttributeData[] = {
-    {XFA_Attribute::Name, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::Gregorian},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
+};
 
-constexpr wchar_t kName[] = L"calendarSymbols";
+const CXFA_Node::AttributeData kCalendarSymbolsAttributeData[] = {
+    {XFA_Attribute::Name, XFA_AttributeType::Enum,
+     (void*)XFA_AttributeValue::Gregorian},
+};
 
 }  // namespace
 
@@ -30,8 +32,8 @@
                 XFA_XDPPACKET_LocaleSet,
                 XFA_ObjectType::Node,
                 XFA_Element::CalendarSymbols,
-                kPropertyData,
-                kAttributeData,
-                kName) {}
+                kCalendarSymbolsPropertyData,
+                kCalendarSymbolsAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_CalendarSymbols::~CXFA_CalendarSymbols() {}
+CXFA_CalendarSymbols::~CXFA_CalendarSymbols() = default;
diff --git a/xfa/fxfa/parser/cxfa_calendarsymbols.h b/xfa/fxfa/parser/cxfa_calendarsymbols.h
index 1b1f007..82ecde4 100644
--- a/xfa/fxfa/parser/cxfa_calendarsymbols.h
+++ b/xfa/fxfa/parser/cxfa_calendarsymbols.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_CalendarSymbols : public CXFA_Node {
+class CXFA_CalendarSymbols final : public CXFA_Node {
  public:
   CXFA_CalendarSymbols(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_CalendarSymbols() override;
diff --git a/xfa/fxfa/parser/cxfa_caption.cpp b/xfa/fxfa/parser/cxfa_caption.cpp
index a54605a..1fadb8d 100644
--- a/xfa/fxfa/parser/cxfa_caption.cpp
+++ b/xfa/fxfa/parser/cxfa_caption.cpp
@@ -6,7 +6,7 @@
 
 #include "xfa/fxfa/parser/cxfa_caption.h"
 
-#include "fxjs/xfa/cjx_caption.h"
+#include "fxjs/xfa/cjx_node.h"
 #include "third_party/base/ptr_util.h"
 #include "xfa/fxfa/parser/cxfa_font.h"
 #include "xfa/fxfa/parser/cxfa_margin.h"
@@ -15,22 +15,22 @@
 
 namespace {
 
-const CXFA_Node::PropertyData kPropertyData[] = {
+const CXFA_Node::PropertyData kCaptionPropertyData[] = {
     {XFA_Element::Margin, 1, 0}, {XFA_Element::Para, 1, 0},
     {XFA_Element::Font, 1, 0},   {XFA_Element::Value, 1, 0},
-    {XFA_Element::Extras, 1, 0}, {XFA_Element::Unknown, 0, 0}};
-const CXFA_Node::AttributeData kAttributeData[] = {
+    {XFA_Element::Extras, 1, 0},
+};
+
+const CXFA_Node::AttributeData kCaptionAttributeData[] = {
     {XFA_Attribute::Id, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Use, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Reserve, XFA_AttributeType::Measure, (void*)L"-1un"},
     {XFA_Attribute::Presence, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::Visible},
+     (void*)XFA_AttributeValue::Visible},
     {XFA_Attribute::Usehref, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Placement, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::Left},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"caption";
+     (void*)XFA_AttributeValue::Left},
+};
 
 }  // namespace
 
@@ -40,34 +40,29 @@
                 (XFA_XDPPACKET_Template | XFA_XDPPACKET_Form),
                 XFA_ObjectType::Node,
                 XFA_Element::Caption,
-                kPropertyData,
-                kAttributeData,
-                kName,
-                pdfium::MakeUnique<CJX_Caption>(this)) {}
+                kCaptionPropertyData,
+                kCaptionAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_Caption::~CXFA_Caption() {}
+CXFA_Caption::~CXFA_Caption() = default;
 
 bool CXFA_Caption::IsVisible() {
-  return JSObject()
-             ->TryEnum(XFA_Attribute::Presence, true)
-             .value_or(XFA_AttributeEnum::Visible) ==
-         XFA_AttributeEnum::Visible;
+  auto value = JSObject()->TryEnum(XFA_Attribute::Presence, true);
+  return !value.has_value() || value.value() == XFA_AttributeValue::Visible;
 }
 
 bool CXFA_Caption::IsHidden() {
-  return JSObject()
-             ->TryEnum(XFA_Attribute::Presence, true)
-             .value_or(XFA_AttributeEnum::Visible) == XFA_AttributeEnum::Hidden;
+  auto value = JSObject()->TryEnum(XFA_Attribute::Presence, true);
+  return !value.has_value() || value.value() == XFA_AttributeValue::Hidden;
 }
 
-XFA_AttributeEnum CXFA_Caption::GetPlacementType() {
-  return JSObject()
-      ->TryEnum(XFA_Attribute::Placement, true)
-      .value_or(XFA_AttributeEnum::Left);
+XFA_AttributeValue CXFA_Caption::GetPlacementType() {
+  auto value = JSObject()->TryEnum(XFA_Attribute::Placement, true);
+  return value.value_or(XFA_AttributeValue::Left);
 }
 
 float CXFA_Caption::GetReserve() const {
-  return JSObject()->GetMeasure(XFA_Attribute::Reserve).ToUnit(XFA_Unit::Pt);
+  return JSObject()->GetMeasureInUnit(XFA_Attribute::Reserve, XFA_Unit::Pt);
 }
 
 CXFA_Margin* CXFA_Caption::GetMarginIfExists() {
diff --git a/xfa/fxfa/parser/cxfa_caption.h b/xfa/fxfa/parser/cxfa_caption.h
index c790787..9e7d38a 100644
--- a/xfa/fxfa/parser/cxfa_caption.h
+++ b/xfa/fxfa/parser/cxfa_caption.h
@@ -13,17 +13,17 @@
 class CXFA_Margin;
 class CXFA_Value;
 
-class CXFA_Caption : public CXFA_Node {
+class CXFA_Caption final : public CXFA_Node {
  public:
-  static constexpr XFA_AttributeEnum kDefaultPlacementType =
-      XFA_AttributeEnum::Left;
+  static constexpr XFA_AttributeValue kDefaultPlacementType =
+      XFA_AttributeValue::Left;
 
   CXFA_Caption(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Caption() override;
 
   bool IsVisible();
   bool IsHidden();
-  XFA_AttributeEnum GetPlacementType();
+  XFA_AttributeValue GetPlacementType();
   float GetReserve() const;
   CXFA_Margin* GetMarginIfExists();
   CXFA_Font* GetFontIfExists();
diff --git a/xfa/fxfa/parser/cxfa_certificate.cpp b/xfa/fxfa/parser/cxfa_certificate.cpp
index c3e8ec0..65b6941 100644
--- a/xfa/fxfa/parser/cxfa_certificate.cpp
+++ b/xfa/fxfa/parser/cxfa_certificate.cpp
@@ -6,19 +6,17 @@
 
 #include "xfa/fxfa/parser/cxfa_certificate.h"
 
-#include "fxjs/xfa/cjx_certificate.h"
+#include "fxjs/xfa/cjx_textnode.h"
 #include "third_party/base/ptr_util.h"
 
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kCertificateAttributeData[] = {
     {XFA_Attribute::Id, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Name, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Use, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Usehref, XFA_AttributeType::CData, nullptr},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"certificate";
+};
 
 }  // namespace
 
@@ -28,9 +26,8 @@
                 (XFA_XDPPACKET_Template | XFA_XDPPACKET_Form),
                 XFA_ObjectType::TextNode,
                 XFA_Element::Certificate,
-                nullptr,
-                kAttributeData,
-                kName,
-                pdfium::MakeUnique<CJX_Certificate>(this)) {}
+                {},
+                kCertificateAttributeData,
+                pdfium::MakeUnique<CJX_TextNode>(this)) {}
 
-CXFA_Certificate::~CXFA_Certificate() {}
+CXFA_Certificate::~CXFA_Certificate() = default;
diff --git a/xfa/fxfa/parser/cxfa_certificate.h b/xfa/fxfa/parser/cxfa_certificate.h
index 48106da..4923d57 100644
--- a/xfa/fxfa/parser/cxfa_certificate.h
+++ b/xfa/fxfa/parser/cxfa_certificate.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Certificate : public CXFA_Node {
+class CXFA_Certificate final : public CXFA_Node {
  public:
   CXFA_Certificate(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Certificate() override;
diff --git a/xfa/fxfa/parser/cxfa_certificates.cpp b/xfa/fxfa/parser/cxfa_certificates.cpp
index 0af8f30..42b025e 100644
--- a/xfa/fxfa/parser/cxfa_certificates.cpp
+++ b/xfa/fxfa/parser/cxfa_certificates.cpp
@@ -6,26 +6,26 @@
 
 #include "xfa/fxfa/parser/cxfa_certificates.h"
 
-#include "fxjs/xfa/cjx_certificates.h"
+#include "fxjs/xfa/cjx_node.h"
 #include "third_party/base/ptr_util.h"
 
 namespace {
 
-const CXFA_Node::PropertyData kPropertyData[] = {
+const CXFA_Node::PropertyData kCertificatesPropertyData[] = {
     {XFA_Element::KeyUsage, 1, 0}, {XFA_Element::SubjectDNs, 1, 0},
     {XFA_Element::Issuers, 1, 0},  {XFA_Element::Signing, 1, 0},
-    {XFA_Element::Oids, 1, 0},     {XFA_Element::Unknown, 0, 0}};
-const CXFA_Node::AttributeData kAttributeData[] = {
+    {XFA_Element::Oids, 1, 0},
+};
+
+const CXFA_Node::AttributeData kCertificatesAttributeData[] = {
     {XFA_Attribute::Id, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Url, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Use, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::CredentialServerPolicy, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::Optional},
+     (void*)XFA_AttributeValue::Optional},
     {XFA_Attribute::Usehref, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::UrlPolicy, XFA_AttributeType::CData, nullptr},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"certificates";
+};
 
 }  // namespace
 
@@ -35,9 +35,8 @@
                 (XFA_XDPPACKET_Template | XFA_XDPPACKET_Form),
                 XFA_ObjectType::Node,
                 XFA_Element::Certificates,
-                kPropertyData,
-                kAttributeData,
-                kName,
-                pdfium::MakeUnique<CJX_Certificates>(this)) {}
+                kCertificatesPropertyData,
+                kCertificatesAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_Certificates::~CXFA_Certificates() {}
+CXFA_Certificates::~CXFA_Certificates() = default;
diff --git a/xfa/fxfa/parser/cxfa_certificates.h b/xfa/fxfa/parser/cxfa_certificates.h
index a1bed73..6817d03 100644
--- a/xfa/fxfa/parser/cxfa_certificates.h
+++ b/xfa/fxfa/parser/cxfa_certificates.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Certificates : public CXFA_Node {
+class CXFA_Certificates final : public CXFA_Node {
  public:
   CXFA_Certificates(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Certificates() override;
diff --git a/xfa/fxfa/parser/cxfa_change.cpp b/xfa/fxfa/parser/cxfa_change.cpp
index 520c556..ae8da63 100644
--- a/xfa/fxfa/parser/cxfa_change.cpp
+++ b/xfa/fxfa/parser/cxfa_change.cpp
@@ -6,14 +6,15 @@
 
 #include "xfa/fxfa/parser/cxfa_change.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kChangeAttributeData[] = {
     {XFA_Attribute::Desc, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Lock, XFA_AttributeType::Integer, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"change";
+};
 
 }  // namespace
 
@@ -23,8 +24,8 @@
                 XFA_XDPPACKET_Config,
                 XFA_ObjectType::ContentNode,
                 XFA_Element::Change,
-                nullptr,
-                kAttributeData,
-                kName) {}
+                {},
+                kChangeAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_Change::~CXFA_Change() {}
+CXFA_Change::~CXFA_Change() = default;
diff --git a/xfa/fxfa/parser/cxfa_change.h b/xfa/fxfa/parser/cxfa_change.h
index f39b92e..2fa4ba9 100644
--- a/xfa/fxfa/parser/cxfa_change.h
+++ b/xfa/fxfa/parser/cxfa_change.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Change : public CXFA_Node {
+class CXFA_Change final : public CXFA_Node {
  public:
   CXFA_Change(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Change() override;
diff --git a/xfa/fxfa/parser/cxfa_checkbutton.cpp b/xfa/fxfa/parser/cxfa_checkbutton.cpp
index 00f3993..903ce49 100644
--- a/xfa/fxfa/parser/cxfa_checkbutton.cpp
+++ b/xfa/fxfa/parser/cxfa_checkbutton.cpp
@@ -6,28 +6,28 @@
 
 #include "xfa/fxfa/parser/cxfa_checkbutton.h"
 
-#include "fxjs/xfa/cjx_checkbutton.h"
+#include "fxjs/xfa/cjx_node.h"
 #include "third_party/base/ptr_util.h"
 
 namespace {
 
-const CXFA_Node::PropertyData kPropertyData[] = {{XFA_Element::Margin, 1, 0},
-                                                 {XFA_Element::Border, 1, 0},
-                                                 {XFA_Element::Extras, 1, 0},
-                                                 {XFA_Element::Unknown, 0, 0}};
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::PropertyData kCheckButtonPropertyData[] = {
+    {XFA_Element::Margin, 1, 0},
+    {XFA_Element::Border, 1, 0},
+    {XFA_Element::Extras, 1, 0},
+};
+
+const CXFA_Node::AttributeData kCheckButtonAttributeData[] = {
     {XFA_Attribute::Id, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Use, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::AllowNeutral, XFA_AttributeType::Boolean, (void*)0},
     {XFA_Attribute::Mark, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::Default},
+     (void*)XFA_AttributeValue::Default},
     {XFA_Attribute::Shape, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::Square},
+     (void*)XFA_AttributeValue::Square},
     {XFA_Attribute::Size, XFA_AttributeType::Measure, (void*)L"10pt"},
     {XFA_Attribute::Usehref, XFA_AttributeType::CData, nullptr},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"checkButton";
+};
 
 }  // namespace
 
@@ -37,9 +37,24 @@
                 (XFA_XDPPACKET_Template | XFA_XDPPACKET_Form),
                 XFA_ObjectType::Node,
                 XFA_Element::CheckButton,
-                kPropertyData,
-                kAttributeData,
-                kName,
-                pdfium::MakeUnique<CJX_CheckButton>(this)) {}
+                kCheckButtonPropertyData,
+                kCheckButtonAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_CheckButton::~CXFA_CheckButton() {}
+CXFA_CheckButton::~CXFA_CheckButton() = default;
+
+XFA_FFWidgetType CXFA_CheckButton::GetDefaultFFWidgetType() const {
+  return XFA_FFWidgetType::kCheckButton;
+}
+
+bool CXFA_CheckButton::IsRound() {
+  return JSObject()->GetEnum(XFA_Attribute::Shape) == XFA_AttributeValue::Round;
+}
+
+XFA_AttributeValue CXFA_CheckButton::GetMark() {
+  return JSObject()->GetEnum(XFA_Attribute::Mark);
+}
+
+bool CXFA_CheckButton::IsAllowNeutral() {
+  return JSObject()->GetBoolean(XFA_Attribute::AllowNeutral);
+}
diff --git a/xfa/fxfa/parser/cxfa_checkbutton.h b/xfa/fxfa/parser/cxfa_checkbutton.h
index dbfb4bb..3ca8b9e 100644
--- a/xfa/fxfa/parser/cxfa_checkbutton.h
+++ b/xfa/fxfa/parser/cxfa_checkbutton.h
@@ -9,10 +9,16 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_CheckButton : public CXFA_Node {
+class CXFA_CheckButton final : public CXFA_Node {
  public:
   CXFA_CheckButton(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_CheckButton() override;
+
+  XFA_FFWidgetType GetDefaultFFWidgetType() const override;
+
+  bool IsRound();
+  bool IsAllowNeutral();
+  XFA_AttributeValue GetMark();
 };
 
 #endif  // XFA_FXFA_PARSER_CXFA_CHECKBUTTON_H_
diff --git a/xfa/fxfa/parser/cxfa_choicelist.cpp b/xfa/fxfa/parser/cxfa_choicelist.cpp
index 33f8683..63e9882 100644
--- a/xfa/fxfa/parser/cxfa_choicelist.cpp
+++ b/xfa/fxfa/parser/cxfa_choicelist.cpp
@@ -6,27 +6,27 @@
 
 #include "xfa/fxfa/parser/cxfa_choicelist.h"
 
-#include "fxjs/xfa/cjx_choicelist.h"
+#include "fxjs/xfa/cjx_node.h"
 #include "third_party/base/ptr_util.h"
 
 namespace {
 
-const CXFA_Node::PropertyData kPropertyData[] = {{XFA_Element::Margin, 1, 0},
-                                                 {XFA_Element::Border, 1, 0},
-                                                 {XFA_Element::Extras, 1, 0},
-                                                 {XFA_Element::Unknown, 0, 0}};
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::PropertyData kChoiceListPropertyData[] = {
+    {XFA_Element::Margin, 1, 0},
+    {XFA_Element::Border, 1, 0},
+    {XFA_Element::Extras, 1, 0},
+};
+
+const CXFA_Node::AttributeData kChoiceListAttributeData[] = {
     {XFA_Attribute::Id, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Use, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Open, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::UserControl},
+     (void*)XFA_AttributeValue::UserControl},
     {XFA_Attribute::CommitOn, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::Select},
+     (void*)XFA_AttributeValue::Select},
     {XFA_Attribute::TextEntry, XFA_AttributeType::Boolean, (void*)0},
     {XFA_Attribute::Usehref, XFA_AttributeType::CData, nullptr},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"choiceList";
+};
 
 }  // namespace
 
@@ -36,9 +36,19 @@
                 (XFA_XDPPACKET_Template | XFA_XDPPACKET_Form),
                 XFA_ObjectType::Node,
                 XFA_Element::ChoiceList,
-                kPropertyData,
-                kAttributeData,
-                kName,
-                pdfium::MakeUnique<CJX_ChoiceList>(this)) {}
+                kChoiceListPropertyData,
+                kChoiceListAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_ChoiceList::~CXFA_ChoiceList() {}
+CXFA_ChoiceList::~CXFA_ChoiceList() = default;
+
+XFA_Element CXFA_ChoiceList::GetValueNodeType() const {
+  return JSObject()->GetEnum(XFA_Attribute::Open) ==
+                 XFA_AttributeValue::MultiSelect
+             ? XFA_Element::ExData
+             : XFA_Element::Text;
+}
+
+XFA_FFWidgetType CXFA_ChoiceList::GetDefaultFFWidgetType() const {
+  return XFA_FFWidgetType::kChoiceList;
+}
diff --git a/xfa/fxfa/parser/cxfa_choicelist.h b/xfa/fxfa/parser/cxfa_choicelist.h
index 9e94880..cff1463 100644
--- a/xfa/fxfa/parser/cxfa_choicelist.h
+++ b/xfa/fxfa/parser/cxfa_choicelist.h
@@ -9,10 +9,13 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_ChoiceList : public CXFA_Node {
+class CXFA_ChoiceList final : public CXFA_Node {
  public:
   CXFA_ChoiceList(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_ChoiceList() override;
+
+  XFA_Element GetValueNodeType() const override;
+  XFA_FFWidgetType GetDefaultFFWidgetType() const override;
 };
 
 #endif  // XFA_FXFA_PARSER_CXFA_CHOICELIST_H_
diff --git a/xfa/fxfa/parser/cxfa_color.cpp b/xfa/fxfa/parser/cxfa_color.cpp
index 95c0ad3..477121b 100644
--- a/xfa/fxfa/parser/cxfa_color.cpp
+++ b/xfa/fxfa/parser/cxfa_color.cpp
@@ -6,22 +6,22 @@
 
 #include "xfa/fxfa/parser/cxfa_color.h"
 
-#include "fxjs/xfa/cjx_color.h"
+#include "fxjs/xfa/cjx_node.h"
 #include "third_party/base/ptr_util.h"
 
 namespace {
 
-const CXFA_Node::PropertyData kPropertyData[] = {{XFA_Element::Extras, 1, 0},
-                                                 {XFA_Element::Unknown, 0, 0}};
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::PropertyData kColorPropertyData[] = {
+    {XFA_Element::Extras, 1, 0},
+};
+
+const CXFA_Node::AttributeData kColorAttributeData[] = {
     {XFA_Attribute::Id, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Use, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::CSpace, XFA_AttributeType::CData, (void*)L"SRGB"},
     {XFA_Attribute::Usehref, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Value, XFA_AttributeType::CData, nullptr},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"color";
+};
 
 }  // namespace
 
@@ -31,12 +31,11 @@
                 (XFA_XDPPACKET_Template | XFA_XDPPACKET_Form),
                 XFA_ObjectType::Node,
                 XFA_Element::Color,
-                kPropertyData,
-                kAttributeData,
-                kName,
-                pdfium::MakeUnique<CJX_Color>(this)) {}
+                kColorPropertyData,
+                kColorAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_Color::~CXFA_Color() {}
+CXFA_Color::~CXFA_Color() = default;
 
 FX_ARGB CXFA_Color::GetValue() {
   Optional<WideString> val = JSObject()->TryCData(XFA_Attribute::Value, false);
diff --git a/xfa/fxfa/parser/cxfa_color.h b/xfa/fxfa/parser/cxfa_color.h
index b15c9d8..d13a553 100644
--- a/xfa/fxfa/parser/cxfa_color.h
+++ b/xfa/fxfa/parser/cxfa_color.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Color : public CXFA_Node {
+class CXFA_Color final : public CXFA_Node {
  public:
   static constexpr FX_ARGB kBlackColor = 0xFF000000;
 
diff --git a/xfa/fxfa/parser/cxfa_comb.cpp b/xfa/fxfa/parser/cxfa_comb.cpp
index c427dde..4bd8ac5 100644
--- a/xfa/fxfa/parser/cxfa_comb.cpp
+++ b/xfa/fxfa/parser/cxfa_comb.cpp
@@ -6,19 +6,17 @@
 
 #include "xfa/fxfa/parser/cxfa_comb.h"
 
-#include "fxjs/xfa/cjx_comb.h"
+#include "fxjs/xfa/cjx_node.h"
 #include "third_party/base/ptr_util.h"
 
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kCombAttributeData[] = {
     {XFA_Attribute::Id, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Use, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::NumberOfCells, XFA_AttributeType::Integer, (void*)0},
     {XFA_Attribute::Usehref, XFA_AttributeType::CData, nullptr},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"comb";
+};
 
 }  // namespace
 
@@ -28,9 +26,8 @@
                 (XFA_XDPPACKET_Template | XFA_XDPPACKET_Form),
                 XFA_ObjectType::Node,
                 XFA_Element::Comb,
-                nullptr,
-                kAttributeData,
-                kName,
-                pdfium::MakeUnique<CJX_Comb>(this)) {}
+                {},
+                kCombAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
 CXFA_Comb::~CXFA_Comb() {}
diff --git a/xfa/fxfa/parser/cxfa_comb.h b/xfa/fxfa/parser/cxfa_comb.h
index 1f2b538..4193a9c 100644
--- a/xfa/fxfa/parser/cxfa_comb.h
+++ b/xfa/fxfa/parser/cxfa_comb.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Comb : public CXFA_Node {
+class CXFA_Comb final : public CXFA_Node {
  public:
   CXFA_Comb(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Comb() override;
diff --git a/xfa/fxfa/parser/cxfa_command.cpp b/xfa/fxfa/parser/cxfa_command.cpp
index ce385e1..4d1e283 100644
--- a/xfa/fxfa/parser/cxfa_command.cpp
+++ b/xfa/fxfa/parser/cxfa_command.cpp
@@ -6,25 +6,25 @@
 
 #include "xfa/fxfa/parser/cxfa_command.h"
 
-#include "fxjs/xfa/cjx_command.h"
+#include "fxjs/xfa/cjx_node.h"
 #include "third_party/base/ptr_util.h"
 
 namespace {
 
-const CXFA_Node::PropertyData kPropertyData[] = {{XFA_Element::Query, 1, 0},
-                                                 {XFA_Element::Insert, 1, 0},
-                                                 {XFA_Element::Update, 1, 0},
-                                                 {XFA_Element::Delete, 1, 0},
-                                                 {XFA_Element::Unknown, 0, 0}};
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::PropertyData kCommandPropertyData[] = {
+    {XFA_Element::Query, 1, 0},
+    {XFA_Element::Insert, 1, 0},
+    {XFA_Element::Update, 1, 0},
+    {XFA_Element::Delete, 1, 0},
+};
+
+const CXFA_Node::AttributeData kCommandAttributeData[] = {
     {XFA_Attribute::Id, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Name, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Use, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Timeout, XFA_AttributeType::Integer, (void*)30},
     {XFA_Attribute::Usehref, XFA_AttributeType::CData, nullptr},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"command";
+};
 
 }  // namespace
 
@@ -34,9 +34,8 @@
                 XFA_XDPPACKET_SourceSet,
                 XFA_ObjectType::Node,
                 XFA_Element::Command,
-                kPropertyData,
-                kAttributeData,
-                kName,
-                pdfium::MakeUnique<CJX_Command>(this)) {}
+                kCommandPropertyData,
+                kCommandAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_Command::~CXFA_Command() {}
+CXFA_Command::~CXFA_Command() = default;
diff --git a/xfa/fxfa/parser/cxfa_command.h b/xfa/fxfa/parser/cxfa_command.h
index 88b74f3..46f9854 100644
--- a/xfa/fxfa/parser/cxfa_command.h
+++ b/xfa/fxfa/parser/cxfa_command.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Command : public CXFA_Node {
+class CXFA_Command final : public CXFA_Node {
  public:
   CXFA_Command(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Command() override;
diff --git a/xfa/fxfa/parser/cxfa_common.cpp b/xfa/fxfa/parser/cxfa_common.cpp
index e95f02f..576234c 100644
--- a/xfa/fxfa/parser/cxfa_common.cpp
+++ b/xfa/fxfa/parser/cxfa_common.cpp
@@ -6,9 +6,12 @@
 
 #include "xfa/fxfa/parser/cxfa_common.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::PropertyData kPropertyData[] = {
+const CXFA_Node::PropertyData kCommonPropertyData[] = {
     {XFA_Element::SuppressBanner, 1, 0},
     {XFA_Element::VersionControl, 1, 0},
     {XFA_Element::LocaleSet, 1, 0},
@@ -17,13 +20,12 @@
     {XFA_Element::Locale, 1, 0},
     {XFA_Element::Data, 1, 0},
     {XFA_Element::Messaging, 1, 0},
-    {XFA_Element::Unknown, 0, 0}};
-const CXFA_Node::AttributeData kAttributeData[] = {
+};
+
+const CXFA_Node::AttributeData kCommonAttributeData[] = {
     {XFA_Attribute::Desc, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Lock, XFA_AttributeType::Integer, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"common";
+};
 
 }  // namespace
 
@@ -33,8 +35,8 @@
                 XFA_XDPPACKET_Config,
                 XFA_ObjectType::Node,
                 XFA_Element::Common,
-                kPropertyData,
-                kAttributeData,
-                kName) {}
+                kCommonPropertyData,
+                kCommonAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_Common::~CXFA_Common() {}
+CXFA_Common::~CXFA_Common() = default;
diff --git a/xfa/fxfa/parser/cxfa_common.h b/xfa/fxfa/parser/cxfa_common.h
index d0ce0ea..7cab852 100644
--- a/xfa/fxfa/parser/cxfa_common.h
+++ b/xfa/fxfa/parser/cxfa_common.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Common : public CXFA_Node {
+class CXFA_Common final : public CXFA_Node {
  public:
   CXFA_Common(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Common() override;
diff --git a/xfa/fxfa/parser/cxfa_compress.cpp b/xfa/fxfa/parser/cxfa_compress.cpp
index 72a3b92..6b593e7 100644
--- a/xfa/fxfa/parser/cxfa_compress.cpp
+++ b/xfa/fxfa/parser/cxfa_compress.cpp
@@ -6,16 +6,17 @@
 
 #include "xfa/fxfa/parser/cxfa_compress.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kCompressAttributeData[] = {
     {XFA_Attribute::Desc, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Scope, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::ImageOnly},
+     (void*)XFA_AttributeValue::ImageOnly},
     {XFA_Attribute::Lock, XFA_AttributeType::Integer, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"compress";
+};
 
 }  // namespace
 
@@ -25,8 +26,8 @@
                 XFA_XDPPACKET_Config,
                 XFA_ObjectType::Node,
                 XFA_Element::Compress,
-                nullptr,
-                kAttributeData,
-                kName) {}
+                {},
+                kCompressAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_Compress::~CXFA_Compress() {}
+CXFA_Compress::~CXFA_Compress() = default;
diff --git a/xfa/fxfa/parser/cxfa_compress.h b/xfa/fxfa/parser/cxfa_compress.h
index bec1883..2b56390 100644
--- a/xfa/fxfa/parser/cxfa_compress.h
+++ b/xfa/fxfa/parser/cxfa_compress.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Compress : public CXFA_Node {
+class CXFA_Compress final : public CXFA_Node {
  public:
   CXFA_Compress(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Compress() override;
diff --git a/xfa/fxfa/parser/cxfa_compression.cpp b/xfa/fxfa/parser/cxfa_compression.cpp
index 3d2bfde..344101d 100644
--- a/xfa/fxfa/parser/cxfa_compression.cpp
+++ b/xfa/fxfa/parser/cxfa_compression.cpp
@@ -6,20 +6,22 @@
 
 #include "xfa/fxfa/parser/cxfa_compression.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::PropertyData kPropertyData[] = {
+const CXFA_Node::PropertyData kCompressionPropertyData[] = {
     {XFA_Element::Level, 1, 0},
     {XFA_Element::Type, 1, 0},
     {XFA_Element::CompressObjectStream, 1, 0},
     {XFA_Element::CompressLogicalStructure, 1, 0},
-    {XFA_Element::Unknown, 0, 0}};
-const CXFA_Node::AttributeData kAttributeData[] = {
+};
+
+const CXFA_Node::AttributeData kCompressionAttributeData[] = {
     {XFA_Attribute::Desc, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Lock, XFA_AttributeType::Integer, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"compression";
+};
 
 }  // namespace
 
@@ -29,8 +31,8 @@
                 XFA_XDPPACKET_Config,
                 XFA_ObjectType::Node,
                 XFA_Element::Compression,
-                kPropertyData,
-                kAttributeData,
-                kName) {}
+                kCompressionPropertyData,
+                kCompressionAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_Compression::~CXFA_Compression() {}
+CXFA_Compression::~CXFA_Compression() = default;
diff --git a/xfa/fxfa/parser/cxfa_compression.h b/xfa/fxfa/parser/cxfa_compression.h
index f0e26cb..7a571ae 100644
--- a/xfa/fxfa/parser/cxfa_compression.h
+++ b/xfa/fxfa/parser/cxfa_compression.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Compression : public CXFA_Node {
+class CXFA_Compression final : public CXFA_Node {
  public:
   CXFA_Compression(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Compression() override;
diff --git a/xfa/fxfa/parser/cxfa_compresslogicalstructure.cpp b/xfa/fxfa/parser/cxfa_compresslogicalstructure.cpp
index a9c2baf..c9bcf6b 100644
--- a/xfa/fxfa/parser/cxfa_compresslogicalstructure.cpp
+++ b/xfa/fxfa/parser/cxfa_compresslogicalstructure.cpp
@@ -6,14 +6,15 @@
 
 #include "xfa/fxfa/parser/cxfa_compresslogicalstructure.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kCompressLogicalStructureAttributeData[] = {
     {XFA_Attribute::Desc, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Lock, XFA_AttributeType::Integer, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"compressLogicalStructure";
+};
 
 }  // namespace
 
@@ -25,8 +26,8 @@
                 XFA_XDPPACKET_Config,
                 XFA_ObjectType::ContentNode,
                 XFA_Element::CompressLogicalStructure,
-                nullptr,
-                kAttributeData,
-                kName) {}
+                {},
+                kCompressLogicalStructureAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_CompressLogicalStructure::~CXFA_CompressLogicalStructure() {}
+CXFA_CompressLogicalStructure::~CXFA_CompressLogicalStructure() = default;
diff --git a/xfa/fxfa/parser/cxfa_compresslogicalstructure.h b/xfa/fxfa/parser/cxfa_compresslogicalstructure.h
index a8b5068..843eb60 100644
--- a/xfa/fxfa/parser/cxfa_compresslogicalstructure.h
+++ b/xfa/fxfa/parser/cxfa_compresslogicalstructure.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_CompressLogicalStructure : public CXFA_Node {
+class CXFA_CompressLogicalStructure final : public CXFA_Node {
  public:
   CXFA_CompressLogicalStructure(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_CompressLogicalStructure() override;
diff --git a/xfa/fxfa/parser/cxfa_compressobjectstream.cpp b/xfa/fxfa/parser/cxfa_compressobjectstream.cpp
index 49eaed0..ed643d0 100644
--- a/xfa/fxfa/parser/cxfa_compressobjectstream.cpp
+++ b/xfa/fxfa/parser/cxfa_compressobjectstream.cpp
@@ -6,14 +6,15 @@
 
 #include "xfa/fxfa/parser/cxfa_compressobjectstream.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kCompressObjectStreamAttributeData[] = {
     {XFA_Attribute::Desc, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Lock, XFA_AttributeType::Integer, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"compressObjectStream";
+};
 
 }  // namespace
 
@@ -24,8 +25,8 @@
                 XFA_XDPPACKET_Config,
                 XFA_ObjectType::ContentNode,
                 XFA_Element::CompressObjectStream,
-                nullptr,
-                kAttributeData,
-                kName) {}
+                {},
+                kCompressObjectStreamAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_CompressObjectStream::~CXFA_CompressObjectStream() {}
+CXFA_CompressObjectStream::~CXFA_CompressObjectStream() = default;
diff --git a/xfa/fxfa/parser/cxfa_compressobjectstream.h b/xfa/fxfa/parser/cxfa_compressobjectstream.h
index 94e02ce..bce7c65 100644
--- a/xfa/fxfa/parser/cxfa_compressobjectstream.h
+++ b/xfa/fxfa/parser/cxfa_compressobjectstream.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_CompressObjectStream : public CXFA_Node {
+class CXFA_CompressObjectStream final : public CXFA_Node {
  public:
   CXFA_CompressObjectStream(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_CompressObjectStream() override;
diff --git a/xfa/fxfa/parser/cxfa_config.cpp b/xfa/fxfa/parser/cxfa_config.cpp
index 79232a2..540e967 100644
--- a/xfa/fxfa/parser/cxfa_config.cpp
+++ b/xfa/fxfa/parser/cxfa_config.cpp
@@ -6,18 +6,21 @@
 
 #include "xfa/fxfa/parser/cxfa_config.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::PropertyData kPropertyData[] = {{XFA_Element::Present, 1, 0},
-                                                 {XFA_Element::Acrobat, 1, 0},
-                                                 {XFA_Element::Trace, 1, 0},
-                                                 {XFA_Element::Unknown, 0, 0}};
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::PropertyData kConfigPropertyData[] = {
+    {XFA_Element::Present, 1, 0},
+    {XFA_Element::Acrobat, 1, 0},
+    {XFA_Element::Trace, 1, 0},
+};
+
+const CXFA_Node::AttributeData kConfigAttributeData[] = {
     {XFA_Attribute::Desc, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Lock, XFA_AttributeType::Integer, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"config";
+};
 
 }  // namespace
 
@@ -27,8 +30,8 @@
                 XFA_XDPPACKET_Config,
                 XFA_ObjectType::ModelNode,
                 XFA_Element::Config,
-                kPropertyData,
-                kAttributeData,
-                kName) {}
+                kConfigPropertyData,
+                kConfigAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_Config::~CXFA_Config() {}
+CXFA_Config::~CXFA_Config() = default;
diff --git a/xfa/fxfa/parser/cxfa_config.h b/xfa/fxfa/parser/cxfa_config.h
index 2ddb692..644c475 100644
--- a/xfa/fxfa/parser/cxfa_config.h
+++ b/xfa/fxfa/parser/cxfa_config.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Config : public CXFA_Node {
+class CXFA_Config final : public CXFA_Node {
  public:
   CXFA_Config(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Config() override;
diff --git a/xfa/fxfa/parser/cxfa_conformance.cpp b/xfa/fxfa/parser/cxfa_conformance.cpp
index f83c8ea..b9c8e34 100644
--- a/xfa/fxfa/parser/cxfa_conformance.cpp
+++ b/xfa/fxfa/parser/cxfa_conformance.cpp
@@ -6,14 +6,15 @@
 
 #include "xfa/fxfa/parser/cxfa_conformance.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kConformanceAttributeData[] = {
     {XFA_Attribute::Desc, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Lock, XFA_AttributeType::Integer, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"conformance";
+};
 
 }  // namespace
 
@@ -23,8 +24,8 @@
                 XFA_XDPPACKET_Config,
                 XFA_ObjectType::ContentNode,
                 XFA_Element::Conformance,
-                nullptr,
-                kAttributeData,
-                kName) {}
+                {},
+                kConformanceAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_Conformance::~CXFA_Conformance() {}
+CXFA_Conformance::~CXFA_Conformance() = default;
diff --git a/xfa/fxfa/parser/cxfa_conformance.h b/xfa/fxfa/parser/cxfa_conformance.h
index 11a72e7..829bb1c 100644
--- a/xfa/fxfa/parser/cxfa_conformance.h
+++ b/xfa/fxfa/parser/cxfa_conformance.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Conformance : public CXFA_Node {
+class CXFA_Conformance final : public CXFA_Node {
  public:
   CXFA_Conformance(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Conformance() override;
diff --git a/xfa/fxfa/parser/cxfa_connect.cpp b/xfa/fxfa/parser/cxfa_connect.cpp
index 40648f4..c46debc 100644
--- a/xfa/fxfa/parser/cxfa_connect.cpp
+++ b/xfa/fxfa/parser/cxfa_connect.cpp
@@ -6,18 +6,19 @@
 
 #include "xfa/fxfa/parser/cxfa_connect.h"
 
-#include "fxjs/xfa/cjx_connect.h"
+#include "fxjs/xfa/cjx_node.h"
 #include "third_party/base/ptr_util.h"
 
 namespace {
 
-const CXFA_Node::PropertyData kPropertyData[] = {
+const CXFA_Node::PropertyData kConnectPropertyData[] = {
     {XFA_Element::Picture, 1, 0},
     {XFA_Element::ConnectString, 1, 0},
     {XFA_Element::User, 1, 0},
     {XFA_Element::Password, 1, 0},
-    {XFA_Element::Unknown, 0, 0}};
-const CXFA_Node::AttributeData kAttributeData[] = {
+};
+
+const CXFA_Node::AttributeData kConnectAttributeData[] = {
     {XFA_Attribute::Id, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Name, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Ref, XFA_AttributeType::CData, nullptr},
@@ -25,12 +26,10 @@
     {XFA_Attribute::Timeout, XFA_AttributeType::Integer, (void*)15},
     {XFA_Attribute::Connection, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Usage, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::ExportAndImport},
+     (void*)XFA_AttributeValue::ExportAndImport},
     {XFA_Attribute::Usehref, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::DelayedOpen, XFA_AttributeType::CData, nullptr},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"connect";
+};
 
 }  // namespace
 
@@ -41,9 +40,8 @@
                  XFA_XDPPACKET_Form),
                 XFA_ObjectType::Node,
                 XFA_Element::Connect,
-                kPropertyData,
-                kAttributeData,
-                kName,
-                pdfium::MakeUnique<CJX_Connect>(this)) {}
+                kConnectPropertyData,
+                kConnectAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_Connect::~CXFA_Connect() {}
+CXFA_Connect::~CXFA_Connect() = default;
diff --git a/xfa/fxfa/parser/cxfa_connect.h b/xfa/fxfa/parser/cxfa_connect.h
index ac91577..3d616ce 100644
--- a/xfa/fxfa/parser/cxfa_connect.h
+++ b/xfa/fxfa/parser/cxfa_connect.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Connect : public CXFA_Node {
+class CXFA_Connect final : public CXFA_Node {
  public:
   CXFA_Connect(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Connect() override;
diff --git a/xfa/fxfa/parser/cxfa_connectionset.cpp b/xfa/fxfa/parser/cxfa_connectionset.cpp
index 78f02e0..74585e6 100644
--- a/xfa/fxfa/parser/cxfa_connectionset.cpp
+++ b/xfa/fxfa/parser/cxfa_connectionset.cpp
@@ -9,12 +9,6 @@
 #include "fxjs/xfa/cjx_model.h"
 #include "third_party/base/ptr_util.h"
 
-namespace {
-
-constexpr wchar_t kName[] = L"connectionSet";
-
-}  // namespace
-
 CXFA_ConnectionSet::CXFA_ConnectionSet(CXFA_Document* doc,
                                        XFA_PacketType packet)
     : CXFA_Node(doc,
@@ -22,9 +16,8 @@
                 XFA_XDPPACKET_ConnectionSet,
                 XFA_ObjectType::ModelNode,
                 XFA_Element::ConnectionSet,
-                nullptr,
-                nullptr,
-                kName,
+                {},
+                {},
                 pdfium::MakeUnique<CJX_Model>(this)) {}
 
-CXFA_ConnectionSet::~CXFA_ConnectionSet() {}
+CXFA_ConnectionSet::~CXFA_ConnectionSet() = default;
diff --git a/xfa/fxfa/parser/cxfa_connectionset.h b/xfa/fxfa/parser/cxfa_connectionset.h
index 59316f7..74238e0 100644
--- a/xfa/fxfa/parser/cxfa_connectionset.h
+++ b/xfa/fxfa/parser/cxfa_connectionset.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_ConnectionSet : public CXFA_Node {
+class CXFA_ConnectionSet final : public CXFA_Node {
  public:
   CXFA_ConnectionSet(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_ConnectionSet() override;
diff --git a/xfa/fxfa/parser/cxfa_connectstring.cpp b/xfa/fxfa/parser/cxfa_connectstring.cpp
index 87eb70d..c5e37f4 100644
--- a/xfa/fxfa/parser/cxfa_connectstring.cpp
+++ b/xfa/fxfa/parser/cxfa_connectstring.cpp
@@ -6,19 +6,17 @@
 
 #include "xfa/fxfa/parser/cxfa_connectstring.h"
 
-#include "fxjs/xfa/cjx_connectstring.h"
+#include "fxjs/xfa/cjx_textnode.h"
 #include "third_party/base/ptr_util.h"
 
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kConnectStringAttributeData[] = {
     {XFA_Attribute::Id, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Name, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Use, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Usehref, XFA_AttributeType::CData, nullptr},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"connectString";
+};
 
 }  // namespace
 
@@ -29,9 +27,8 @@
                 XFA_XDPPACKET_SourceSet,
                 XFA_ObjectType::TextNode,
                 XFA_Element::ConnectString,
-                nullptr,
-                kAttributeData,
-                kName,
-                pdfium::MakeUnique<CJX_ConnectString>(this)) {}
+                {},
+                kConnectStringAttributeData,
+                pdfium::MakeUnique<CJX_TextNode>(this)) {}
 
-CXFA_ConnectString::~CXFA_ConnectString() {}
+CXFA_ConnectString::~CXFA_ConnectString() = default;
diff --git a/xfa/fxfa/parser/cxfa_connectstring.h b/xfa/fxfa/parser/cxfa_connectstring.h
index 6c3a0b0..88dd7bc 100644
--- a/xfa/fxfa/parser/cxfa_connectstring.h
+++ b/xfa/fxfa/parser/cxfa_connectstring.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_ConnectString : public CXFA_Node {
+class CXFA_ConnectString final : public CXFA_Node {
  public:
   CXFA_ConnectString(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_ConnectString() override;
diff --git a/xfa/fxfa/parser/cxfa_containerlayoutitem.cpp b/xfa/fxfa/parser/cxfa_containerlayoutitem.cpp
deleted file mode 100644
index ee122b6..0000000
--- a/xfa/fxfa/parser/cxfa_containerlayoutitem.cpp
+++ /dev/null
@@ -1,52 +0,0 @@
-// Copyright 2016 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
-
-#include "xfa/fxfa/parser/cxfa_containerlayoutitem.h"
-
-#include "fxjs/xfa/cjx_object.h"
-#include "xfa/fxfa/parser/cxfa_layoutpagemgr.h"
-#include "xfa/fxfa/parser/cxfa_layoutprocessor.h"
-#include "xfa/fxfa/parser/cxfa_measurement.h"
-#include "xfa/fxfa/parser/cxfa_medium.h"
-#include "xfa/fxfa/parser/cxfa_node.h"
-
-CXFA_ContainerLayoutItem::CXFA_ContainerLayoutItem(CXFA_Node* pNode)
-    : CXFA_LayoutItem(pNode, false), m_pOldSubform(nullptr) {}
-
-CXFA_LayoutProcessor* CXFA_ContainerLayoutItem::GetLayout() const {
-  return m_pFormNode->GetDocument()->GetLayoutProcessor();
-}
-
-int32_t CXFA_ContainerLayoutItem::GetPageIndex() const {
-  return m_pFormNode->GetDocument()
-      ->GetLayoutProcessor()
-      ->GetLayoutPageMgr()
-      ->GetPageIndex(this);
-}
-
-CFX_SizeF CXFA_ContainerLayoutItem::GetPageSize() const {
-  CFX_SizeF size;
-  CXFA_Medium* pMedium =
-      m_pFormNode->GetFirstChildByClass<CXFA_Medium>(XFA_Element::Medium);
-  if (!pMedium)
-    return size;
-
-  size = CFX_SizeF(pMedium->JSObject()
-                       ->GetMeasure(XFA_Attribute::Short)
-                       .ToUnit(XFA_Unit::Pt),
-                   pMedium->JSObject()
-                       ->GetMeasure(XFA_Attribute::Long)
-                       .ToUnit(XFA_Unit::Pt));
-  if (pMedium->JSObject()->GetEnum(XFA_Attribute::Orientation) ==
-      XFA_AttributeEnum::Landscape) {
-    size = CFX_SizeF(size.height, size.width);
-  }
-  return size;
-}
-
-CXFA_Node* CXFA_ContainerLayoutItem::GetMasterPage() const {
-  return m_pFormNode;
-}
diff --git a/xfa/fxfa/parser/cxfa_containerlayoutitem.h b/xfa/fxfa/parser/cxfa_containerlayoutitem.h
deleted file mode 100644
index 3c8a8af..0000000
--- a/xfa/fxfa/parser/cxfa_containerlayoutitem.h
+++ /dev/null
@@ -1,28 +0,0 @@
-// Copyright 2016 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_CONTAINERLAYOUTITEM_H_
-#define XFA_FXFA_PARSER_CXFA_CONTAINERLAYOUTITEM_H_
-
-#include "xfa/fxfa/parser/cxfa_layoutitem.h"
-
-class CXFA_ContainerLayoutItem : public CXFA_LayoutItem {
- public:
-  explicit CXFA_ContainerLayoutItem(CXFA_Node* pNode);
-
-  CXFA_LayoutProcessor* GetLayout() const;
-  int32_t GetPageIndex() const;
-  CFX_SizeF GetPageSize() const;
-  CXFA_Node* GetMasterPage() const;
-
-  CXFA_Node* m_pOldSubform;
-};
-
-inline CXFA_ContainerLayoutItem* ToContainerLayoutItem(CXFA_LayoutItem* pItem) {
-  return pItem ? pItem->AsContainerLayoutItem() : nullptr;
-}
-
-#endif  // XFA_FXFA_PARSER_CXFA_CONTAINERLAYOUTITEM_H_
diff --git a/xfa/fxfa/parser/cxfa_contentarea.cpp b/xfa/fxfa/parser/cxfa_contentarea.cpp
index 48f52f7..8c62c0a 100644
--- a/xfa/fxfa/parser/cxfa_contentarea.cpp
+++ b/xfa/fxfa/parser/cxfa_contentarea.cpp
@@ -6,15 +6,17 @@
 
 #include "xfa/fxfa/parser/cxfa_contentarea.h"
 
-#include "fxjs/xfa/cjx_contentarea.h"
+#include "fxjs/xfa/cjx_container.h"
 #include "third_party/base/ptr_util.h"
 
 namespace {
 
-const CXFA_Node::PropertyData kPropertyData[] = {{XFA_Element::Desc, 1, 0},
-                                                 {XFA_Element::Extras, 1, 0},
-                                                 {XFA_Element::Unknown, 0, 0}};
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::PropertyData kContentAreaPropertyData[] = {
+    {XFA_Element::Desc, 1, 0},
+    {XFA_Element::Extras, 1, 0},
+};
+
+const CXFA_Node::AttributeData kContentAreaAttributeData[] = {
     {XFA_Attribute::H, XFA_AttributeType::Measure, (void*)L"0in"},
     {XFA_Attribute::W, XFA_AttributeType::Measure, (void*)L"0in"},
     {XFA_Attribute::X, XFA_AttributeType::Measure, (void*)L"0in"},
@@ -24,9 +26,7 @@
     {XFA_Attribute::Use, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Relevant, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Usehref, XFA_AttributeType::CData, nullptr},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"contentArea";
+};
 
 }  // namespace
 
@@ -36,9 +36,8 @@
                 (XFA_XDPPACKET_Template | XFA_XDPPACKET_Form),
                 XFA_ObjectType::ContainerNode,
                 XFA_Element::ContentArea,
-                kPropertyData,
-                kAttributeData,
-                kName,
-                pdfium::MakeUnique<CJX_ContentArea>(this)) {}
+                kContentAreaPropertyData,
+                kContentAreaAttributeData,
+                pdfium::MakeUnique<CJX_Container>(this)) {}
 
-CXFA_ContentArea::~CXFA_ContentArea() {}
+CXFA_ContentArea::~CXFA_ContentArea() = default;
diff --git a/xfa/fxfa/parser/cxfa_contentarea.h b/xfa/fxfa/parser/cxfa_contentarea.h
index 3c5ff60..43f6868 100644
--- a/xfa/fxfa/parser/cxfa_contentarea.h
+++ b/xfa/fxfa/parser/cxfa_contentarea.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_ContentArea : public CXFA_Node {
+class CXFA_ContentArea final : public CXFA_Node {
  public:
   CXFA_ContentArea(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_ContentArea() override;
diff --git a/xfa/fxfa/parser/cxfa_contentcopy.cpp b/xfa/fxfa/parser/cxfa_contentcopy.cpp
index a55d576..38fd27e 100644
--- a/xfa/fxfa/parser/cxfa_contentcopy.cpp
+++ b/xfa/fxfa/parser/cxfa_contentcopy.cpp
@@ -6,14 +6,15 @@
 
 #include "xfa/fxfa/parser/cxfa_contentcopy.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kContentCopyAttributeData[] = {
     {XFA_Attribute::Desc, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Lock, XFA_AttributeType::Integer, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"contentCopy";
+};
 
 }  // namespace
 
@@ -23,8 +24,8 @@
                 XFA_XDPPACKET_Config,
                 XFA_ObjectType::ContentNode,
                 XFA_Element::ContentCopy,
-                nullptr,
-                kAttributeData,
-                kName) {}
+                {},
+                kContentCopyAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_ContentCopy::~CXFA_ContentCopy() {}
+CXFA_ContentCopy::~CXFA_ContentCopy() = default;
diff --git a/xfa/fxfa/parser/cxfa_contentcopy.h b/xfa/fxfa/parser/cxfa_contentcopy.h
index d394c74..5b32beb 100644
--- a/xfa/fxfa/parser/cxfa_contentcopy.h
+++ b/xfa/fxfa/parser/cxfa_contentcopy.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_ContentCopy : public CXFA_Node {
+class CXFA_ContentCopy final : public CXFA_Node {
  public:
   CXFA_ContentCopy(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_ContentCopy() override;
diff --git a/xfa/fxfa/parser/cxfa_contentlayoutitem.cpp b/xfa/fxfa/parser/cxfa_contentlayoutitem.cpp
deleted file mode 100644
index 1ee364b..0000000
--- a/xfa/fxfa/parser/cxfa_contentlayoutitem.cpp
+++ /dev/null
@@ -1,21 +0,0 @@
-// Copyright 2016 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
-
-#include "xfa/fxfa/parser/cxfa_contentlayoutitem.h"
-
-#include "fxjs/xfa/cjx_object.h"
-#include "xfa/fxfa/parser/cxfa_node.h"
-
-CXFA_ContentLayoutItem::CXFA_ContentLayoutItem(CXFA_Node* pNode)
-    : CXFA_LayoutItem(pNode, true),
-      m_pPrev(nullptr),
-      m_pNext(nullptr),
-      m_dwStatus(0) {}
-
-CXFA_ContentLayoutItem::~CXFA_ContentLayoutItem() {
-  if (m_pFormNode->JSObject()->GetLayoutItem() == this)
-    m_pFormNode->JSObject()->SetLayoutItem(nullptr);
-}
diff --git a/xfa/fxfa/parser/cxfa_contentlayoutitem.h b/xfa/fxfa/parser/cxfa_contentlayoutitem.h
deleted file mode 100644
index 500d3e4..0000000
--- a/xfa/fxfa/parser/cxfa_contentlayoutitem.h
+++ /dev/null
@@ -1,28 +0,0 @@
-// Copyright 2016 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_CONTENTLAYOUTITEM_H_
-#define XFA_FXFA_PARSER_CXFA_CONTENTLAYOUTITEM_H_
-
-#include "xfa/fxfa/parser/cxfa_layoutitem.h"
-
-class CXFA_ContentLayoutItem : public CXFA_LayoutItem {
- public:
-  explicit CXFA_ContentLayoutItem(CXFA_Node* pNode);
-  ~CXFA_ContentLayoutItem() override;
-
-  CXFA_ContentLayoutItem* m_pPrev;
-  CXFA_ContentLayoutItem* m_pNext;
-  CFX_PointF m_sPos;
-  CFX_SizeF m_sSize;
-  mutable uint32_t m_dwStatus;
-};
-
-inline CXFA_ContentLayoutItem* ToContentLayoutItem(CXFA_LayoutItem* pItem) {
-  return pItem ? pItem->AsContentLayoutItem() : nullptr;
-}
-
-#endif  // XFA_FXFA_PARSER_CXFA_CONTENTLAYOUTITEM_H_
diff --git a/xfa/fxfa/parser/cxfa_copies.cpp b/xfa/fxfa/parser/cxfa_copies.cpp
index 4ddf07f..7b8ef0e 100644
--- a/xfa/fxfa/parser/cxfa_copies.cpp
+++ b/xfa/fxfa/parser/cxfa_copies.cpp
@@ -6,14 +6,15 @@
 
 #include "xfa/fxfa/parser/cxfa_copies.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kCopiesAttributeData[] = {
     {XFA_Attribute::Desc, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Lock, XFA_AttributeType::Integer, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"copies";
+};
 
 }  // namespace
 
@@ -23,8 +24,8 @@
                 XFA_XDPPACKET_Config,
                 XFA_ObjectType::ContentNode,
                 XFA_Element::Copies,
-                nullptr,
-                kAttributeData,
-                kName) {}
+                {},
+                kCopiesAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_Copies::~CXFA_Copies() {}
+CXFA_Copies::~CXFA_Copies() = default;
diff --git a/xfa/fxfa/parser/cxfa_copies.h b/xfa/fxfa/parser/cxfa_copies.h
index 1ecd616..46497f9 100644
--- a/xfa/fxfa/parser/cxfa_copies.h
+++ b/xfa/fxfa/parser/cxfa_copies.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Copies : public CXFA_Node {
+class CXFA_Copies final : public CXFA_Node {
  public:
   CXFA_Copies(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Copies() override;
diff --git a/xfa/fxfa/parser/cxfa_corner.cpp b/xfa/fxfa/parser/cxfa_corner.cpp
index 0cd3ef4..3ffbc71 100644
--- a/xfa/fxfa/parser/cxfa_corner.cpp
+++ b/xfa/fxfa/parser/cxfa_corner.cpp
@@ -6,30 +6,30 @@
 
 #include "xfa/fxfa/parser/cxfa_corner.h"
 
-#include "fxjs/xfa/cjx_corner.h"
+#include "fxjs/xfa/cjx_node.h"
 #include "third_party/base/ptr_util.h"
 
 namespace {
 
-const CXFA_Node::PropertyData kPropertyData[] = {{XFA_Element::Color, 1, 0},
-                                                 {XFA_Element::Extras, 1, 0},
-                                                 {XFA_Element::Unknown, 0, 0}};
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::PropertyData kCornerPropertyData[] = {
+    {XFA_Element::Color, 1, 0},
+    {XFA_Element::Extras, 1, 0},
+};
+
+const CXFA_Node::AttributeData kCornerAttributeData[] = {
     {XFA_Attribute::Id, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Use, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Stroke, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::Solid},
+     (void*)XFA_AttributeValue::Solid},
     {XFA_Attribute::Presence, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::Visible},
+     (void*)XFA_AttributeValue::Visible},
     {XFA_Attribute::Inverted, XFA_AttributeType::Boolean, (void*)0},
     {XFA_Attribute::Thickness, XFA_AttributeType::Measure, (void*)L"0.5pt"},
     {XFA_Attribute::Usehref, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Join, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::Square},
+     (void*)XFA_AttributeValue::Square},
     {XFA_Attribute::Radius, XFA_AttributeType::Measure, (void*)L"0in"},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"corner";
+};
 
 }  // namespace
 
@@ -39,9 +39,8 @@
                   (XFA_XDPPACKET_Template | XFA_XDPPACKET_Form),
                   XFA_ObjectType::Node,
                   XFA_Element::Corner,
-                  kPropertyData,
-                  kAttributeData,
-                  kName,
-                  pdfium::MakeUnique<CJX_Corner>(this)) {}
+                  kCornerPropertyData,
+                  kCornerAttributeData,
+                  pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_Corner::~CXFA_Corner() {}
+CXFA_Corner::~CXFA_Corner() = default;
diff --git a/xfa/fxfa/parser/cxfa_corner.h b/xfa/fxfa/parser/cxfa_corner.h
index 1042729..7dcaf32 100644
--- a/xfa/fxfa/parser/cxfa_corner.h
+++ b/xfa/fxfa/parser/cxfa_corner.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_stroke.h"
 
-class CXFA_Corner : public CXFA_Stroke {
+class CXFA_Corner final : public CXFA_Stroke {
  public:
   CXFA_Corner(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Corner() override;
diff --git a/xfa/fxfa/parser/cxfa_creator.cpp b/xfa/fxfa/parser/cxfa_creator.cpp
index 2e65068..e03b32a 100644
--- a/xfa/fxfa/parser/cxfa_creator.cpp
+++ b/xfa/fxfa/parser/cxfa_creator.cpp
@@ -6,14 +6,15 @@
 
 #include "xfa/fxfa/parser/cxfa_creator.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kCreatorAttributeData[] = {
     {XFA_Attribute::Desc, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Lock, XFA_AttributeType::Integer, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"creator";
+};
 
 }  // namespace
 
@@ -23,8 +24,8 @@
                 XFA_XDPPACKET_Config,
                 XFA_ObjectType::ContentNode,
                 XFA_Element::Creator,
-                nullptr,
-                kAttributeData,
-                kName) {}
+                {},
+                kCreatorAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_Creator::~CXFA_Creator() {}
+CXFA_Creator::~CXFA_Creator() = default;
diff --git a/xfa/fxfa/parser/cxfa_creator.h b/xfa/fxfa/parser/cxfa_creator.h
index c046883..437fab5 100644
--- a/xfa/fxfa/parser/cxfa_creator.h
+++ b/xfa/fxfa/parser/cxfa_creator.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Creator : public CXFA_Node {
+class CXFA_Creator final : public CXFA_Node {
  public:
   CXFA_Creator(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Creator() override;
diff --git a/xfa/fxfa/parser/cxfa_currencysymbol.cpp b/xfa/fxfa/parser/cxfa_currencysymbol.cpp
index de11f27..beca653 100644
--- a/xfa/fxfa/parser/cxfa_currencysymbol.cpp
+++ b/xfa/fxfa/parser/cxfa_currencysymbol.cpp
@@ -6,14 +6,15 @@
 
 #include "xfa/fxfa/parser/cxfa_currencysymbol.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kCurrencySymbolAttributeData[] = {
     {XFA_Attribute::Name, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::Symbol},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"currencySymbol";
+     (void*)XFA_AttributeValue::Symbol},
+};
 
 }  // namespace
 
@@ -24,8 +25,8 @@
                 XFA_XDPPACKET_LocaleSet,
                 XFA_ObjectType::ContentNode,
                 XFA_Element::CurrencySymbol,
-                nullptr,
-                kAttributeData,
-                kName) {}
+                {},
+                kCurrencySymbolAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_CurrencySymbol::~CXFA_CurrencySymbol() {}
+CXFA_CurrencySymbol::~CXFA_CurrencySymbol() = default;
diff --git a/xfa/fxfa/parser/cxfa_currencysymbol.h b/xfa/fxfa/parser/cxfa_currencysymbol.h
index 271f7fc..3d7b5bd 100644
--- a/xfa/fxfa/parser/cxfa_currencysymbol.h
+++ b/xfa/fxfa/parser/cxfa_currencysymbol.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_CurrencySymbol : public CXFA_Node {
+class CXFA_CurrencySymbol final : public CXFA_Node {
  public:
   CXFA_CurrencySymbol(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_CurrencySymbol() override;
diff --git a/xfa/fxfa/parser/cxfa_currencysymbols.cpp b/xfa/fxfa/parser/cxfa_currencysymbols.cpp
index 4160be9..3b2e90c 100644
--- a/xfa/fxfa/parser/cxfa_currencysymbols.cpp
+++ b/xfa/fxfa/parser/cxfa_currencysymbols.cpp
@@ -6,13 +6,14 @@
 
 #include "xfa/fxfa/parser/cxfa_currencysymbols.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::PropertyData kPropertyData[] = {
+const CXFA_Node::PropertyData kCurrencySymbolsPropertyData[] = {
     {XFA_Element::CurrencySymbol, 3, 0},
-    {XFA_Element::Unknown, 0, 0}};
-
-constexpr wchar_t kName[] = L"currencySymbols";
+};
 
 }  // namespace
 
@@ -23,8 +24,8 @@
                 XFA_XDPPACKET_LocaleSet,
                 XFA_ObjectType::Node,
                 XFA_Element::CurrencySymbols,
-                kPropertyData,
-                nullptr,
-                kName) {}
+                kCurrencySymbolsPropertyData,
+                {},
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_CurrencySymbols::~CXFA_CurrencySymbols() {}
+CXFA_CurrencySymbols::~CXFA_CurrencySymbols() = default;
diff --git a/xfa/fxfa/parser/cxfa_currencysymbols.h b/xfa/fxfa/parser/cxfa_currencysymbols.h
index acd3f2a..2ce27cf 100644
--- a/xfa/fxfa/parser/cxfa_currencysymbols.h
+++ b/xfa/fxfa/parser/cxfa_currencysymbols.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_CurrencySymbols : public CXFA_Node {
+class CXFA_CurrencySymbols final : public CXFA_Node {
  public:
   CXFA_CurrencySymbols(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_CurrencySymbols() override;
diff --git a/xfa/fxfa/parser/cxfa_currentpage.cpp b/xfa/fxfa/parser/cxfa_currentpage.cpp
index be200e4..a98aa1c 100644
--- a/xfa/fxfa/parser/cxfa_currentpage.cpp
+++ b/xfa/fxfa/parser/cxfa_currentpage.cpp
@@ -6,14 +6,15 @@
 
 #include "xfa/fxfa/parser/cxfa_currentpage.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kCurrentPageAttributeData[] = {
     {XFA_Attribute::Desc, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Lock, XFA_AttributeType::Integer, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"currentPage";
+};
 
 }  // namespace
 
@@ -23,8 +24,8 @@
                 XFA_XDPPACKET_Config,
                 XFA_ObjectType::ContentNode,
                 XFA_Element::CurrentPage,
-                nullptr,
-                kAttributeData,
-                kName) {}
+                {},
+                kCurrentPageAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_CurrentPage::~CXFA_CurrentPage() {}
+CXFA_CurrentPage::~CXFA_CurrentPage() = default;
diff --git a/xfa/fxfa/parser/cxfa_currentpage.h b/xfa/fxfa/parser/cxfa_currentpage.h
index d526b4a..5bba6a0 100644
--- a/xfa/fxfa/parser/cxfa_currentpage.h
+++ b/xfa/fxfa/parser/cxfa_currentpage.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_CurrentPage : public CXFA_Node {
+class CXFA_CurrentPage final : public CXFA_Node {
  public:
   CXFA_CurrentPage(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_CurrentPage() override;
diff --git a/xfa/fxfa/parser/cxfa_data.cpp b/xfa/fxfa/parser/cxfa_data.cpp
index 6fd66a9..5173147 100644
--- a/xfa/fxfa/parser/cxfa_data.cpp
+++ b/xfa/fxfa/parser/cxfa_data.cpp
@@ -6,21 +6,23 @@
 
 #include "xfa/fxfa/parser/cxfa_data.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::PropertyData kPropertyData[] = {
+const CXFA_Node::PropertyData kDataPropertyData[] = {
     {XFA_Element::Uri, 1, 0},        {XFA_Element::Xsl, 1, 0},
     {XFA_Element::StartNode, 1, 0},  {XFA_Element::OutputXSL, 1, 0},
     {XFA_Element::AdjustData, 1, 0}, {XFA_Element::Attributes, 1, 0},
     {XFA_Element::Window, 1, 0},     {XFA_Element::Record, 1, 0},
     {XFA_Element::Range, 1, 0},      {XFA_Element::IncrementalLoad, 1, 0},
-    {XFA_Element::Unknown, 0, 0}};
-const CXFA_Node::AttributeData kAttributeData[] = {
+};
+
+const CXFA_Node::AttributeData kDataAttributeData[] = {
     {XFA_Attribute::Desc, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Lock, XFA_AttributeType::Integer, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"data";
+};
 
 }  // namespace
 
@@ -30,8 +32,8 @@
                 XFA_XDPPACKET_Config,
                 XFA_ObjectType::Node,
                 XFA_Element::Data,
-                kPropertyData,
-                kAttributeData,
-                kName) {}
+                kDataPropertyData,
+                kDataAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_Data::~CXFA_Data() {}
+CXFA_Data::~CXFA_Data() = default;
diff --git a/xfa/fxfa/parser/cxfa_data.h b/xfa/fxfa/parser/cxfa_data.h
index cb30f61..44cf40d 100644
--- a/xfa/fxfa/parser/cxfa_data.h
+++ b/xfa/fxfa/parser/cxfa_data.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Data : public CXFA_Node {
+class CXFA_Data final : public CXFA_Node {
  public:
   CXFA_Data(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Data() override;
diff --git a/xfa/fxfa/parser/cxfa_dataexporter.cpp b/xfa/fxfa/parser/cxfa_dataexporter.cpp
index 23fc178..50106ab 100644
--- a/xfa/fxfa/parser/cxfa_dataexporter.cpp
+++ b/xfa/fxfa/parser/cxfa_dataexporter.cpp
@@ -7,80 +7,56 @@
 #include "xfa/fxfa/parser/cxfa_dataexporter.h"
 
 #include "core/fxcrt/fx_codepage.h"
-#include "core/fxcrt/xml/cfx_xmldoc.h"
 #include "core/fxcrt/xml/cfx_xmlelement.h"
 #include "core/fxcrt/xml/cfx_xmlnode.h"
-#include "third_party/base/stl_util.h"
 #include "xfa/fxfa/parser/cxfa_document.h"
 #include "xfa/fxfa/parser/cxfa_node.h"
 #include "xfa/fxfa/parser/xfa_utils.h"
 
-CXFA_DataExporter::CXFA_DataExporter(CXFA_Document* pDocument)
-    : m_pDocument(pDocument) {
-  ASSERT(m_pDocument);
-}
+CXFA_DataExporter::CXFA_DataExporter() = default;
 
-CXFA_DataExporter::~CXFA_DataExporter() {}
+CXFA_DataExporter::~CXFA_DataExporter() = default;
 
-bool CXFA_DataExporter::Export(const RetainPtr<IFX_SeekableStream>& pWrite) {
-  return Export(pWrite, m_pDocument->GetRoot(), 0, nullptr);
-}
+bool CXFA_DataExporter::Export(const RetainPtr<IFX_SeekableStream>& pStream,
+                               CXFA_Node* pNode) {
+  ASSERT(pStream);
 
-bool CXFA_DataExporter::Export(const RetainPtr<IFX_SeekableStream>& pWrite,
-                               CXFA_Node* pNode,
-                               uint32_t dwFlag,
-                               const char* pChecksum) {
-  ASSERT(pWrite);
-  if (!pWrite)
+  if (!pStream)
     return false;
 
-  auto pStream = pdfium::MakeRetain<CFX_SeekableStreamProxy>(pWrite, true);
-  pStream->SetCodePage(FX_CODEPAGE_UTF8);
-  return Export(pStream, pNode, dwFlag, pChecksum);
-}
-
-bool CXFA_DataExporter::Export(
-    const RetainPtr<CFX_SeekableStreamProxy>& pStream,
-    CXFA_Node* pNode,
-    uint32_t dwFlag,
-    const char* pChecksum) {
-  CFX_XMLDoc* pXMLDoc = m_pDocument->GetXMLDoc();
   if (pNode->IsModelNode()) {
     switch (pNode->GetPacketType()) {
       case XFA_PacketType::Xdp: {
         pStream->WriteString(
-            L"<xdp:xdp xmlns:xdp=\"http://ns.adobe.com/xdp/\">");
+            "<xdp:xdp xmlns:xdp=\"http://ns.adobe.com/xdp/\">");
         for (CXFA_Node* pChild = pNode->GetFirstChild(); pChild;
              pChild = pChild->GetNextSibling()) {
-          Export(pStream, pChild, dwFlag, pChecksum);
+          Export(pStream, pChild);
         }
-        pStream->WriteString(L"</xdp:xdp\n>");
+        pStream->WriteString("</xdp:xdp\n>");
         break;
       }
       case XFA_PacketType::Datasets: {
-        CFX_XMLElement* pElement =
-            static_cast<CFX_XMLElement*>(pNode->GetXMLMappingNode());
-        if (!pElement || pElement->GetType() != FX_XMLNODE_Element)
+        CFX_XMLElement* pElement = ToXMLElement(pNode->GetXMLMappingNode());
+        if (!pElement)
           return false;
 
         CXFA_Node* pDataNode = pNode->GetFirstChild();
         ASSERT(pDataNode);
         XFA_DataExporter_DealWithDataGroupNode(pDataNode);
-        pXMLDoc->SaveXMLNode(pStream, pElement);
+        pElement->Save(pStream);
         break;
       }
-      case XFA_PacketType::Form: {
-        XFA_DataExporter_RegenerateFormFile(pNode, pStream, pChecksum, false);
+      case XFA_PacketType::Form:
+        XFA_DataExporter_RegenerateFormFile(pNode, pStream, false);
         break;
-      }
       case XFA_PacketType::Template:
       default: {
-        CFX_XMLElement* pElement =
-            static_cast<CFX_XMLElement*>(pNode->GetXMLMappingNode());
-        if (!pElement || pElement->GetType() != FX_XMLNODE_Element)
+        CFX_XMLElement* pElement = ToXMLElement(pNode->GetXMLMappingNode());
+        if (!pElement)
           return false;
 
-        pXMLDoc->SaveXMLNode(pStream, pElement);
+        pElement->Save(pStream);
         break;
       }
     }
@@ -96,15 +72,14 @@
       break;
     }
   }
-  CFX_XMLElement* pElement =
-      static_cast<CFX_XMLElement*>(pExportNode->GetXMLMappingNode());
-  if (!pElement || pElement->GetType() != FX_XMLNODE_Element)
+  CFX_XMLElement* pElement = ToXMLElement(pExportNode->GetXMLMappingNode());
+  if (!pElement)
     return false;
 
   XFA_DataExporter_DealWithDataGroupNode(pExportNode);
-  pElement->SetString(L"xmlns:xfa", L"http://www.xfa.org/schema/xfa-data/1.0/");
-  pXMLDoc->SaveXMLNode(pStream, pElement);
+  pElement->SetAttribute(L"xmlns:xfa",
+                         L"http://www.xfa.org/schema/xfa-data/1.0/");
+  pElement->Save(pStream);
   pElement->RemoveAttribute(L"xmlns:xfa");
-
   return true;
 }
diff --git a/xfa/fxfa/parser/cxfa_dataexporter.h b/xfa/fxfa/parser/cxfa_dataexporter.h
index a2a55b3..6fe19d5 100644
--- a/xfa/fxfa/parser/cxfa_dataexporter.h
+++ b/xfa/fxfa/parser/cxfa_dataexporter.h
@@ -13,26 +13,13 @@
 class CXFA_Document;
 class CXFA_Node;
 class IFX_SeekableStream;
-class CFX_SeekableStreamProxy;
 
 class CXFA_DataExporter {
  public:
-  explicit CXFA_DataExporter(CXFA_Document* pDocument);
+  CXFA_DataExporter();
   ~CXFA_DataExporter();
 
-  bool Export(const RetainPtr<IFX_SeekableStream>& pWrite);
-  bool Export(const RetainPtr<IFX_SeekableStream>& pWrite,
-              CXFA_Node* pNode,
-              uint32_t dwFlag,
-              const char* pChecksum);
-
- private:
-  bool Export(const RetainPtr<CFX_SeekableStreamProxy>& pStream,
-              CXFA_Node* pNode,
-              uint32_t dwFlag,
-              const char* pChecksum);
-
-  UnownedPtr<CXFA_Document> const m_pDocument;
+  bool Export(const RetainPtr<IFX_SeekableStream>& pWrite, CXFA_Node* pNode);
 };
 
 #endif  // XFA_FXFA_PARSER_CXFA_DATAEXPORTER_H_
diff --git a/xfa/fxfa/parser/cxfa_datagroup.cpp b/xfa/fxfa/parser/cxfa_datagroup.cpp
index 9b65146..bb5b5fb 100644
--- a/xfa/fxfa/parser/cxfa_datagroup.cpp
+++ b/xfa/fxfa/parser/cxfa_datagroup.cpp
@@ -6,13 +6,14 @@
 
 #include "xfa/fxfa/parser/cxfa_datagroup.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kDataGroupAttributeData[] = {
     {XFA_Attribute::Name, XFA_AttributeType::CData, nullptr},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"dataGroup";
+};
 
 }  // namespace
 
@@ -22,8 +23,8 @@
                 XFA_XDPPACKET_Datasets,
                 XFA_ObjectType::Node,
                 XFA_Element::DataGroup,
-                nullptr,
-                kAttributeData,
-                kName) {}
+                {},
+                kDataGroupAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_DataGroup::~CXFA_DataGroup() {}
+CXFA_DataGroup::~CXFA_DataGroup() = default;
diff --git a/xfa/fxfa/parser/cxfa_datagroup.h b/xfa/fxfa/parser/cxfa_datagroup.h
index 649b096..5a61704 100644
--- a/xfa/fxfa/parser/cxfa_datagroup.h
+++ b/xfa/fxfa/parser/cxfa_datagroup.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_DataGroup : public CXFA_Node {
+class CXFA_DataGroup final : public CXFA_Node {
  public:
   CXFA_DataGroup(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_DataGroup() override;
diff --git a/xfa/fxfa/parser/cxfa_dataimporter.cpp b/xfa/fxfa/parser/cxfa_dataimporter.cpp
deleted file mode 100644
index 9171b00..0000000
--- a/xfa/fxfa/parser/cxfa_dataimporter.cpp
+++ /dev/null
@@ -1,65 +0,0 @@
-// Copyright 2016 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
-
-#include "xfa/fxfa/parser/cxfa_dataimporter.h"
-
-#include <memory>
-
-#include "core/fxcrt/fx_stream.h"
-#include "core/fxcrt/xml/cfx_xmlnode.h"
-#include "third_party/base/ptr_util.h"
-#include "xfa/fxfa/fxfa.h"
-#include "xfa/fxfa/fxfa_basic.h"
-#include "xfa/fxfa/parser/cxfa_document.h"
-#include "xfa/fxfa/parser/cxfa_node.h"
-#include "xfa/fxfa/parser/cxfa_simple_parser.h"
-
-CXFA_DataImporter::CXFA_DataImporter(CXFA_Document* pDocument)
-    : m_pDocument(pDocument) {
-  ASSERT(m_pDocument);
-}
-
-CXFA_DataImporter::~CXFA_DataImporter() {}
-
-bool CXFA_DataImporter::ImportData(
-    const RetainPtr<IFX_SeekableStream>& pDataDocument) {
-  auto pDataDocumentParser =
-      pdfium::MakeUnique<CXFA_SimpleParser>(m_pDocument.Get());
-  if (pDataDocumentParser->StartParse(
-          pDataDocument, XFA_PacketType::Datasets) != XFA_PARSESTATUS_Ready) {
-    return false;
-  }
-  if (pDataDocumentParser->DoParse() < XFA_PARSESTATUS_Done)
-    return false;
-
-  CXFA_Node* pImportDataRoot = pDataDocumentParser->GetRootNode();
-  if (!pImportDataRoot)
-    return false;
-
-  CXFA_Node* pDataModel =
-      ToNode(m_pDocument->GetXFAObject(XFA_HASHCODE_Datasets));
-  if (!pDataModel)
-    return false;
-
-  CXFA_Node* pDataNode = ToNode(m_pDocument->GetXFAObject(XFA_HASHCODE_Data));
-  if (pDataNode)
-    pDataModel->RemoveChild(pDataNode, true);
-
-  if (pImportDataRoot->GetElementType() == XFA_Element::DataModel) {
-    while (CXFA_Node* pChildNode = pImportDataRoot->GetFirstChild()) {
-      pImportDataRoot->RemoveChild(pChildNode, true);
-      pDataModel->InsertChild(pChildNode, nullptr);
-    }
-  } else {
-    CFX_XMLNode* pXMLNode = pImportDataRoot->GetXMLMappingNode();
-    CFX_XMLNode* pParentXMLNode = pXMLNode->GetNodeItem(CFX_XMLNode::Parent);
-    if (pParentXMLNode)
-      pParentXMLNode->RemoveChildNode(pXMLNode);
-    pDataModel->InsertChild(pImportDataRoot, nullptr);
-  }
-  m_pDocument->DoDataRemerge(false);
-  return true;
-}
diff --git a/xfa/fxfa/parser/cxfa_dataimporter.h b/xfa/fxfa/parser/cxfa_dataimporter.h
deleted file mode 100644
index ca5896e..0000000
--- a/xfa/fxfa/parser/cxfa_dataimporter.h
+++ /dev/null
@@ -1,28 +0,0 @@
-// Copyright 2016 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_DATAIMPORTER_H_
-#define XFA_FXFA_PARSER_CXFA_DATAIMPORTER_H_
-
-#include "core/fxcrt/fx_system.h"
-#include "core/fxcrt/retain_ptr.h"
-#include "core/fxcrt/unowned_ptr.h"
-
-class CXFA_Document;
-class IFX_SeekableStream;
-
-class CXFA_DataImporter {
- public:
-  explicit CXFA_DataImporter(CXFA_Document* pDocument);
-  ~CXFA_DataImporter();
-
-  bool ImportData(const RetainPtr<IFX_SeekableStream>& pDataDocument);
-
- private:
-  UnownedPtr<CXFA_Document> const m_pDocument;
-};
-
-#endif  // XFA_FXFA_PARSER_CXFA_DATAIMPORTER_H_
diff --git a/xfa/fxfa/parser/cxfa_datamodel.cpp b/xfa/fxfa/parser/cxfa_datamodel.cpp
index 686ba4c..4b506c5 100644
--- a/xfa/fxfa/parser/cxfa_datamodel.cpp
+++ b/xfa/fxfa/parser/cxfa_datamodel.cpp
@@ -9,21 +9,14 @@
 #include "fxjs/xfa/cjx_model.h"
 #include "third_party/base/ptr_util.h"
 
-namespace {
-
-constexpr wchar_t kName[] = L"dataModel";
-
-}  // namespace
-
 CXFA_DataModel::CXFA_DataModel(CXFA_Document* doc, XFA_PacketType packet)
     : CXFA_Node(doc,
                 packet,
                 XFA_XDPPACKET_Datasets,
                 XFA_ObjectType::ModelNode,
                 XFA_Element::DataModel,
-                nullptr,
-                nullptr,
-                kName,
+                {},
+                {},
                 pdfium::MakeUnique<CJX_Model>(this)) {}
 
-CXFA_DataModel::~CXFA_DataModel() {}
+CXFA_DataModel::~CXFA_DataModel() = default;
diff --git a/xfa/fxfa/parser/cxfa_datamodel.h b/xfa/fxfa/parser/cxfa_datamodel.h
index f414ea3..8a1bd42 100644
--- a/xfa/fxfa/parser/cxfa_datamodel.h
+++ b/xfa/fxfa/parser/cxfa_datamodel.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_DataModel : public CXFA_Node {
+class CXFA_DataModel final : public CXFA_Node {
  public:
   CXFA_DataModel(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_DataModel() override;
diff --git a/xfa/fxfa/parser/cxfa_datavalue.cpp b/xfa/fxfa/parser/cxfa_datavalue.cpp
index e2ebaf0..6e541a4 100644
--- a/xfa/fxfa/parser/cxfa_datavalue.cpp
+++ b/xfa/fxfa/parser/cxfa_datavalue.cpp
@@ -6,21 +6,19 @@
 
 #include "xfa/fxfa/parser/cxfa_datavalue.h"
 
-#include "fxjs/xfa/cjx_datavalue.h"
+#include "fxjs/xfa/cjx_node.h"
 #include "third_party/base/ptr_util.h"
 
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kDataValueAttributeData[] = {
     {XFA_Attribute::Name, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::ContentType, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Contains, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::Data},
+     (void*)XFA_AttributeValue::Data},
     {XFA_Attribute::Value, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::IsNull, XFA_AttributeType::Boolean, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"dataValue";
+};
 
 }  // namespace
 
@@ -30,9 +28,8 @@
                 XFA_XDPPACKET_Datasets,
                 XFA_ObjectType::Node,
                 XFA_Element::DataValue,
-                nullptr,
-                kAttributeData,
-                kName,
-                pdfium::MakeUnique<CJX_DataValue>(this)) {}
+                {},
+                kDataValueAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_DataValue::~CXFA_DataValue() {}
+CXFA_DataValue::~CXFA_DataValue() = default;
diff --git a/xfa/fxfa/parser/cxfa_datavalue.h b/xfa/fxfa/parser/cxfa_datavalue.h
index 8170aba..ee2c621 100644
--- a/xfa/fxfa/parser/cxfa_datavalue.h
+++ b/xfa/fxfa/parser/cxfa_datavalue.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_DataValue : public CXFA_Node {
+class CXFA_DataValue final : public CXFA_Node {
  public:
   CXFA_DataValue(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_DataValue() override;
diff --git a/xfa/fxfa/parser/cxfa_date.cpp b/xfa/fxfa/parser/cxfa_date.cpp
index 984ab32..9508e65 100644
--- a/xfa/fxfa/parser/cxfa_date.cpp
+++ b/xfa/fxfa/parser/cxfa_date.cpp
@@ -6,19 +6,17 @@
 
 #include "xfa/fxfa/parser/cxfa_date.h"
 
-#include "fxjs/xfa/cjx_date.h"
+#include "fxjs/xfa/cjx_node.h"
 #include "third_party/base/ptr_util.h"
 
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kDateAttributeData[] = {
     {XFA_Attribute::Id, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Name, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Use, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Usehref, XFA_AttributeType::CData, nullptr},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"date";
+};
 
 }  // namespace
 
@@ -28,9 +26,8 @@
                 (XFA_XDPPACKET_Template | XFA_XDPPACKET_Form),
                 XFA_ObjectType::ContentNode,
                 XFA_Element::Date,
-                nullptr,
-                kAttributeData,
-                kName,
-                pdfium::MakeUnique<CJX_Date>(this)) {}
+                {},
+                kDateAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_Date::~CXFA_Date() {}
+CXFA_Date::~CXFA_Date() = default;
diff --git a/xfa/fxfa/parser/cxfa_date.h b/xfa/fxfa/parser/cxfa_date.h
index e5ebb25..3fb7ba7 100644
--- a/xfa/fxfa/parser/cxfa_date.h
+++ b/xfa/fxfa/parser/cxfa_date.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Date : public CXFA_Node {
+class CXFA_Date final : public CXFA_Node {
  public:
   CXFA_Date(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Date() override;
diff --git a/xfa/fxfa/parser/cxfa_datepattern.cpp b/xfa/fxfa/parser/cxfa_datepattern.cpp
index 237874b..9f4f635 100644
--- a/xfa/fxfa/parser/cxfa_datepattern.cpp
+++ b/xfa/fxfa/parser/cxfa_datepattern.cpp
@@ -6,14 +6,15 @@
 
 #include "xfa/fxfa/parser/cxfa_datepattern.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kDatePatternAttributeData[] = {
     {XFA_Attribute::Name, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::Med},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"datePattern";
+     (void*)XFA_AttributeValue::Med},
+};
 
 }  // namespace
 
@@ -23,8 +24,8 @@
                 XFA_XDPPACKET_LocaleSet,
                 XFA_ObjectType::ContentNode,
                 XFA_Element::DatePattern,
-                nullptr,
-                kAttributeData,
-                kName) {}
+                {},
+                kDatePatternAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_DatePattern::~CXFA_DatePattern() {}
+CXFA_DatePattern::~CXFA_DatePattern() = default;
diff --git a/xfa/fxfa/parser/cxfa_datepattern.h b/xfa/fxfa/parser/cxfa_datepattern.h
index b661478..e67a61f 100644
--- a/xfa/fxfa/parser/cxfa_datepattern.h
+++ b/xfa/fxfa/parser/cxfa_datepattern.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_DatePattern : public CXFA_Node {
+class CXFA_DatePattern final : public CXFA_Node {
  public:
   CXFA_DatePattern(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_DatePattern() override;
diff --git a/xfa/fxfa/parser/cxfa_datepatterns.cpp b/xfa/fxfa/parser/cxfa_datepatterns.cpp
index 37a380d..9ac1922 100644
--- a/xfa/fxfa/parser/cxfa_datepatterns.cpp
+++ b/xfa/fxfa/parser/cxfa_datepatterns.cpp
@@ -6,13 +6,14 @@
 
 #include "xfa/fxfa/parser/cxfa_datepatterns.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::PropertyData kPropertyData[] = {
+const CXFA_Node::PropertyData kDatePatternsPropertyData[] = {
     {XFA_Element::DatePattern, 4, 0},
-    {XFA_Element::Unknown, 0, 0}};
-
-constexpr wchar_t kName[] = L"datePatterns";
+};
 
 }  // namespace
 
@@ -22,8 +23,8 @@
                 XFA_XDPPACKET_LocaleSet,
                 XFA_ObjectType::Node,
                 XFA_Element::DatePatterns,
-                kPropertyData,
-                nullptr,
-                kName) {}
+                kDatePatternsPropertyData,
+                {},
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_DatePatterns::~CXFA_DatePatterns() {}
+CXFA_DatePatterns::~CXFA_DatePatterns() = default;
diff --git a/xfa/fxfa/parser/cxfa_datepatterns.h b/xfa/fxfa/parser/cxfa_datepatterns.h
index dfc55d0..6c2dca4 100644
--- a/xfa/fxfa/parser/cxfa_datepatterns.h
+++ b/xfa/fxfa/parser/cxfa_datepatterns.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_DatePatterns : public CXFA_Node {
+class CXFA_DatePatterns final : public CXFA_Node {
  public:
   CXFA_DatePatterns(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_DatePatterns() override;
diff --git a/xfa/fxfa/parser/cxfa_datetime.cpp b/xfa/fxfa/parser/cxfa_datetime.cpp
index 809e40c..313a469 100644
--- a/xfa/fxfa/parser/cxfa_datetime.cpp
+++ b/xfa/fxfa/parser/cxfa_datetime.cpp
@@ -6,19 +6,17 @@
 
 #include "xfa/fxfa/parser/cxfa_datetime.h"
 
-#include "fxjs/xfa/cjx_datetime.h"
+#include "fxjs/xfa/cjx_node.h"
 #include "third_party/base/ptr_util.h"
 
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kDateTimeAttributeData[] = {
     {XFA_Attribute::Id, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Name, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Use, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Usehref, XFA_AttributeType::CData, nullptr},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"dateTime";
+};
 
 }  // namespace
 
@@ -28,9 +26,8 @@
                 (XFA_XDPPACKET_Template | XFA_XDPPACKET_Form),
                 XFA_ObjectType::ContentNode,
                 XFA_Element::DateTime,
-                nullptr,
-                kAttributeData,
-                kName,
-                pdfium::MakeUnique<CJX_DateTime>(this)) {}
+                {},
+                kDateTimeAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_DateTime::~CXFA_DateTime() {}
+CXFA_DateTime::~CXFA_DateTime() = default;
diff --git a/xfa/fxfa/parser/cxfa_datetime.h b/xfa/fxfa/parser/cxfa_datetime.h
index f5cd6f6..ca71daf 100644
--- a/xfa/fxfa/parser/cxfa_datetime.h
+++ b/xfa/fxfa/parser/cxfa_datetime.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_DateTime : public CXFA_Node {
+class CXFA_DateTime final : public CXFA_Node {
  public:
   CXFA_DateTime(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_DateTime() override;
diff --git a/xfa/fxfa/parser/cxfa_datetimeedit.cpp b/xfa/fxfa/parser/cxfa_datetimeedit.cpp
index 5c9a804..e64abbd 100644
--- a/xfa/fxfa/parser/cxfa_datetimeedit.cpp
+++ b/xfa/fxfa/parser/cxfa_datetimeedit.cpp
@@ -6,27 +6,27 @@
 
 #include "xfa/fxfa/parser/cxfa_datetimeedit.h"
 
-#include "fxjs/xfa/cjx_datetimeedit.h"
+#include "fxjs/xfa/cjx_node.h"
 #include "third_party/base/ptr_util.h"
 
 namespace {
 
-const CXFA_Node::PropertyData kPropertyData[] = {{XFA_Element::Margin, 1, 0},
-                                                 {XFA_Element::Border, 1, 0},
-                                                 {XFA_Element::Comb, 1, 0},
-                                                 {XFA_Element::Extras, 1, 0},
-                                                 {XFA_Element::Unknown, 0, 0}};
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::PropertyData kDateTimeEditPropertyData[] = {
+    {XFA_Element::Margin, 1, 0},
+    {XFA_Element::Border, 1, 0},
+    {XFA_Element::Comb, 1, 0},
+    {XFA_Element::Extras, 1, 0},
+};
+
+const CXFA_Node::AttributeData kDateTimeEditAttributeData[] = {
     {XFA_Attribute::Id, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Use, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Usehref, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Picker, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::Host},
+     (void*)XFA_AttributeValue::Host},
     {XFA_Attribute::HScrollPolicy, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::Auto},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"dateTimeEdit";
+     (void*)XFA_AttributeValue::Auto},
+};
 
 }  // namespace
 
@@ -36,9 +36,16 @@
                 (XFA_XDPPACKET_Template | XFA_XDPPACKET_Form),
                 XFA_ObjectType::Node,
                 XFA_Element::DateTimeEdit,
-                kPropertyData,
-                kAttributeData,
-                kName,
-                pdfium::MakeUnique<CJX_DateTimeEdit>(this)) {}
+                kDateTimeEditPropertyData,
+                kDateTimeEditAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_DateTimeEdit::~CXFA_DateTimeEdit() {}
+CXFA_DateTimeEdit::~CXFA_DateTimeEdit() = default;
+
+XFA_Element CXFA_DateTimeEdit::GetValueNodeType() const {
+  return XFA_Element::DateTime;
+}
+
+XFA_FFWidgetType CXFA_DateTimeEdit::GetDefaultFFWidgetType() const {
+  return XFA_FFWidgetType::kDateTimeEdit;
+}
diff --git a/xfa/fxfa/parser/cxfa_datetimeedit.h b/xfa/fxfa/parser/cxfa_datetimeedit.h
index bac7879..de76e2a 100644
--- a/xfa/fxfa/parser/cxfa_datetimeedit.h
+++ b/xfa/fxfa/parser/cxfa_datetimeedit.h
@@ -9,10 +9,13 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_DateTimeEdit : public CXFA_Node {
+class CXFA_DateTimeEdit final : public CXFA_Node {
  public:
   CXFA_DateTimeEdit(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_DateTimeEdit() override;
+
+  XFA_Element GetValueNodeType() const override;
+  XFA_FFWidgetType GetDefaultFFWidgetType() const override;
 };
 
 #endif  // XFA_FXFA_PARSER_CXFA_DATETIMEEDIT_H_
diff --git a/xfa/fxfa/parser/cxfa_datetimesymbols.cpp b/xfa/fxfa/parser/cxfa_datetimesymbols.cpp
index 9f29666..159d821 100644
--- a/xfa/fxfa/parser/cxfa_datetimesymbols.cpp
+++ b/xfa/fxfa/parser/cxfa_datetimesymbols.cpp
@@ -6,11 +6,8 @@
 
 #include "xfa/fxfa/parser/cxfa_datetimesymbols.h"
 
-namespace {
-
-constexpr wchar_t kName[] = L"dateTimeSymbols";
-
-}  // namespace
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
 
 CXFA_DateTimeSymbols::CXFA_DateTimeSymbols(CXFA_Document* doc,
                                            XFA_PacketType packet)
@@ -19,8 +16,8 @@
                 XFA_XDPPACKET_LocaleSet,
                 XFA_ObjectType::ContentNode,
                 XFA_Element::DateTimeSymbols,
-                nullptr,
-                nullptr,
-                kName) {}
+                {},
+                {},
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_DateTimeSymbols::~CXFA_DateTimeSymbols() {}
+CXFA_DateTimeSymbols::~CXFA_DateTimeSymbols() = default;
diff --git a/xfa/fxfa/parser/cxfa_datetimesymbols.h b/xfa/fxfa/parser/cxfa_datetimesymbols.h
index e2296d6..cfbe069 100644
--- a/xfa/fxfa/parser/cxfa_datetimesymbols.h
+++ b/xfa/fxfa/parser/cxfa_datetimesymbols.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_DateTimeSymbols : public CXFA_Node {
+class CXFA_DateTimeSymbols final : public CXFA_Node {
  public:
   CXFA_DateTimeSymbols(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_DateTimeSymbols() override;
diff --git a/xfa/fxfa/parser/cxfa_day.cpp b/xfa/fxfa/parser/cxfa_day.cpp
index c08b820..ffbeb2f 100644
--- a/xfa/fxfa/parser/cxfa_day.cpp
+++ b/xfa/fxfa/parser/cxfa_day.cpp
@@ -6,11 +6,8 @@
 
 #include "xfa/fxfa/parser/cxfa_day.h"
 
-namespace {
-
-constexpr wchar_t kName[] = L"day";
-
-}  // namespace
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
 
 CXFA_Day::CXFA_Day(CXFA_Document* doc, XFA_PacketType packet)
     : CXFA_Node(doc,
@@ -18,8 +15,8 @@
                 XFA_XDPPACKET_LocaleSet,
                 XFA_ObjectType::ContentNode,
                 XFA_Element::Day,
-                nullptr,
-                nullptr,
-                kName) {}
+                {},
+                {},
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_Day::~CXFA_Day() {}
+CXFA_Day::~CXFA_Day() = default;
diff --git a/xfa/fxfa/parser/cxfa_day.h b/xfa/fxfa/parser/cxfa_day.h
index 8d04bf4..6fb2f45 100644
--- a/xfa/fxfa/parser/cxfa_day.h
+++ b/xfa/fxfa/parser/cxfa_day.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Day : public CXFA_Node {
+class CXFA_Day final : public CXFA_Node {
  public:
   CXFA_Day(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Day() override;
diff --git a/xfa/fxfa/parser/cxfa_daynames.cpp b/xfa/fxfa/parser/cxfa_daynames.cpp
index 47468e9..8a3b447 100644
--- a/xfa/fxfa/parser/cxfa_daynames.cpp
+++ b/xfa/fxfa/parser/cxfa_daynames.cpp
@@ -6,15 +6,18 @@
 
 #include "xfa/fxfa/parser/cxfa_daynames.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::PropertyData kPropertyData[] = {{XFA_Element::Day, 7, 0},
-                                                 {XFA_Element::Unknown, 0, 0}};
-const CXFA_Node::AttributeData kAttributeData[] = {
-    {XFA_Attribute::Abbr, XFA_AttributeType::Boolean, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
+const CXFA_Node::PropertyData kDayNamesPropertyData[] = {
+    {XFA_Element::Day, 7, 0},
+};
 
-constexpr wchar_t kName[] = L"dayNames";
+const CXFA_Node::AttributeData kDayNamesAttributeData[] = {
+    {XFA_Attribute::Abbr, XFA_AttributeType::Boolean, (void*)0},
+};
 
 }  // namespace
 
@@ -24,8 +27,8 @@
                 XFA_XDPPACKET_LocaleSet,
                 XFA_ObjectType::Node,
                 XFA_Element::DayNames,
-                kPropertyData,
-                kAttributeData,
-                kName) {}
+                kDayNamesPropertyData,
+                kDayNamesAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_DayNames::~CXFA_DayNames() {}
+CXFA_DayNames::~CXFA_DayNames() = default;
diff --git a/xfa/fxfa/parser/cxfa_daynames.h b/xfa/fxfa/parser/cxfa_daynames.h
index d566e50..229d69c 100644
--- a/xfa/fxfa/parser/cxfa_daynames.h
+++ b/xfa/fxfa/parser/cxfa_daynames.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_DayNames : public CXFA_Node {
+class CXFA_DayNames final : public CXFA_Node {
  public:
   CXFA_DayNames(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_DayNames() override;
diff --git a/xfa/fxfa/parser/cxfa_debug.cpp b/xfa/fxfa/parser/cxfa_debug.cpp
index 91cfd63..f4b6ac9 100644
--- a/xfa/fxfa/parser/cxfa_debug.cpp
+++ b/xfa/fxfa/parser/cxfa_debug.cpp
@@ -6,16 +6,19 @@
 
 #include "xfa/fxfa/parser/cxfa_debug.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::PropertyData kPropertyData[] = {{XFA_Element::Uri, 1, 0},
-                                                 {XFA_Element::Unknown, 0, 0}};
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::PropertyData kDebugPropertyData[] = {
+    {XFA_Element::Uri, 1, 0},
+};
+
+const CXFA_Node::AttributeData kDebugAttributeData[] = {
     {XFA_Attribute::Desc, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Lock, XFA_AttributeType::Integer, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"debug";
+};
 
 }  // namespace
 
@@ -25,8 +28,8 @@
                 XFA_XDPPACKET_Config,
                 XFA_ObjectType::Node,
                 XFA_Element::Debug,
-                kPropertyData,
-                kAttributeData,
-                kName) {}
+                kDebugPropertyData,
+                kDebugAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_Debug::~CXFA_Debug() {}
+CXFA_Debug::~CXFA_Debug() = default;
diff --git a/xfa/fxfa/parser/cxfa_debug.h b/xfa/fxfa/parser/cxfa_debug.h
index e2e4ed1..1a254f0 100644
--- a/xfa/fxfa/parser/cxfa_debug.h
+++ b/xfa/fxfa/parser/cxfa_debug.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Debug : public CXFA_Node {
+class CXFA_Debug final : public CXFA_Node {
  public:
   CXFA_Debug(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Debug() override;
diff --git a/xfa/fxfa/parser/cxfa_decimal.cpp b/xfa/fxfa/parser/cxfa_decimal.cpp
index c887e8d..93e5e10 100644
--- a/xfa/fxfa/parser/cxfa_decimal.cpp
+++ b/xfa/fxfa/parser/cxfa_decimal.cpp
@@ -6,21 +6,19 @@
 
 #include "xfa/fxfa/parser/cxfa_decimal.h"
 
-#include "fxjs/xfa/cjx_decimal.h"
+#include "fxjs/xfa/cjx_object.h"
 #include "third_party/base/ptr_util.h"
 
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kDecimalAttributeData[] = {
     {XFA_Attribute::Id, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Name, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Use, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::FracDigits, XFA_AttributeType::Integer, (void*)2},
     {XFA_Attribute::Usehref, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::LeadDigits, XFA_AttributeType::Integer, (void*)-1},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"decimal";
+};
 
 }  // namespace
 
@@ -30,9 +28,8 @@
                 (XFA_XDPPACKET_Template | XFA_XDPPACKET_Form),
                 XFA_ObjectType::ContentNode,
                 XFA_Element::Decimal,
-                nullptr,
-                kAttributeData,
-                kName,
-                pdfium::MakeUnique<CJX_Decimal>(this)) {}
+                {},
+                kDecimalAttributeData,
+                pdfium::MakeUnique<CJX_Object>(this)) {}
 
-CXFA_Decimal::~CXFA_Decimal() {}
+CXFA_Decimal::~CXFA_Decimal() = default;
diff --git a/xfa/fxfa/parser/cxfa_decimal.h b/xfa/fxfa/parser/cxfa_decimal.h
index da58896..668f61a 100644
--- a/xfa/fxfa/parser/cxfa_decimal.h
+++ b/xfa/fxfa/parser/cxfa_decimal.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Decimal : public CXFA_Node {
+class CXFA_Decimal final : public CXFA_Node {
  public:
   CXFA_Decimal(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Decimal() override;
diff --git a/xfa/fxfa/parser/cxfa_defaulttypeface.cpp b/xfa/fxfa/parser/cxfa_defaulttypeface.cpp
index 60da786..1d38e32 100644
--- a/xfa/fxfa/parser/cxfa_defaulttypeface.cpp
+++ b/xfa/fxfa/parser/cxfa_defaulttypeface.cpp
@@ -6,16 +6,17 @@
 
 #include "xfa/fxfa/parser/cxfa_defaulttypeface.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kDefaultTypefaceAttributeData[] = {
     {XFA_Attribute::Desc, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::WritingScript, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::Asterisk},
+     (void*)XFA_AttributeValue::Asterisk},
     {XFA_Attribute::Lock, XFA_AttributeType::Integer, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"defaultTypeface";
+};
 
 }  // namespace
 
@@ -26,8 +27,8 @@
                 XFA_XDPPACKET_Config,
                 XFA_ObjectType::NodeV,
                 XFA_Element::DefaultTypeface,
-                nullptr,
-                kAttributeData,
-                kName) {}
+                {},
+                kDefaultTypefaceAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_DefaultTypeface::~CXFA_DefaultTypeface() {}
+CXFA_DefaultTypeface::~CXFA_DefaultTypeface() = default;
diff --git a/xfa/fxfa/parser/cxfa_defaulttypeface.h b/xfa/fxfa/parser/cxfa_defaulttypeface.h
index 511ed8f..a241bf8 100644
--- a/xfa/fxfa/parser/cxfa_defaulttypeface.h
+++ b/xfa/fxfa/parser/cxfa_defaulttypeface.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_DefaultTypeface : public CXFA_Node {
+class CXFA_DefaultTypeface final : public CXFA_Node {
  public:
   CXFA_DefaultTypeface(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_DefaultTypeface() override;
diff --git a/xfa/fxfa/parser/cxfa_defaultui.cpp b/xfa/fxfa/parser/cxfa_defaultui.cpp
index a940084..26114b0 100644
--- a/xfa/fxfa/parser/cxfa_defaultui.cpp
+++ b/xfa/fxfa/parser/cxfa_defaultui.cpp
@@ -6,20 +6,20 @@
 
 #include "xfa/fxfa/parser/cxfa_defaultui.h"
 
-#include "fxjs/xfa/cjx_defaultui.h"
+#include "fxjs/xfa/cjx_node.h"
 #include "third_party/base/ptr_util.h"
 
 namespace {
 
-const CXFA_Node::PropertyData kPropertyData[] = {{XFA_Element::Extras, 1, 0},
-                                                 {XFA_Element::Unknown, 0, 0}};
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::PropertyData kDefaultUiPropertyData[] = {
+    {XFA_Element::Extras, 1, 0},
+};
+
+const CXFA_Node::AttributeData kDefaultUiAttributeData[] = {
     {XFA_Attribute::Id, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Use, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Usehref, XFA_AttributeType::CData, nullptr},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"defaultUi";
+};
 
 }  // namespace
 
@@ -29,8 +29,12 @@
                 (XFA_XDPPACKET_Template | XFA_XDPPACKET_Form),
                 XFA_ObjectType::Node,
                 XFA_Element::DefaultUi,
-                kPropertyData,
-                kAttributeData,
-                kName) {}
+                kDefaultUiPropertyData,
+                kDefaultUiAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_DefaultUi::~CXFA_DefaultUi() {}
+CXFA_DefaultUi::~CXFA_DefaultUi() = default;
+
+XFA_FFWidgetType CXFA_DefaultUi::GetDefaultFFWidgetType() const {
+  return XFA_FFWidgetType::kTextEdit;
+}
diff --git a/xfa/fxfa/parser/cxfa_defaultui.h b/xfa/fxfa/parser/cxfa_defaultui.h
index ce14941..d09da0b 100644
--- a/xfa/fxfa/parser/cxfa_defaultui.h
+++ b/xfa/fxfa/parser/cxfa_defaultui.h
@@ -9,10 +9,12 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_DefaultUi : public CXFA_Node {
+class CXFA_DefaultUi final : public CXFA_Node {
  public:
   CXFA_DefaultUi(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_DefaultUi() override;
+
+  XFA_FFWidgetType GetDefaultFFWidgetType() const override;
 };
 
 #endif  // XFA_FXFA_PARSER_CXFA_DEFAULTUI_H_
diff --git a/xfa/fxfa/parser/cxfa_delete.cpp b/xfa/fxfa/parser/cxfa_delete.cpp
index 8477fa9..bf76b00 100644
--- a/xfa/fxfa/parser/cxfa_delete.cpp
+++ b/xfa/fxfa/parser/cxfa_delete.cpp
@@ -6,19 +6,17 @@
 
 #include "xfa/fxfa/parser/cxfa_delete.h"
 
-#include "fxjs/xfa/cjx_delete.h"
+#include "fxjs/xfa/cjx_textnode.h"
 #include "third_party/base/ptr_util.h"
 
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kDeleteAttributeData[] = {
     {XFA_Attribute::Id, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Name, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Use, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Usehref, XFA_AttributeType::CData, nullptr},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"delete";
+};
 
 }  // namespace
 
@@ -28,9 +26,8 @@
                 XFA_XDPPACKET_SourceSet,
                 XFA_ObjectType::TextNode,
                 XFA_Element::Delete,
-                nullptr,
-                kAttributeData,
-                kName,
-                pdfium::MakeUnique<CJX_Delete>(this)) {}
+                {},
+                kDeleteAttributeData,
+                pdfium::MakeUnique<CJX_TextNode>(this)) {}
 
-CXFA_Delete::~CXFA_Delete() {}
+CXFA_Delete::~CXFA_Delete() = default;
diff --git a/xfa/fxfa/parser/cxfa_delete.h b/xfa/fxfa/parser/cxfa_delete.h
index 7c6058a..0ea6ab3 100644
--- a/xfa/fxfa/parser/cxfa_delete.h
+++ b/xfa/fxfa/parser/cxfa_delete.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Delete : public CXFA_Node {
+class CXFA_Delete final : public CXFA_Node {
  public:
   CXFA_Delete(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Delete() override;
diff --git a/xfa/fxfa/parser/cxfa_delta.cpp b/xfa/fxfa/parser/cxfa_delta.cpp
index 4b5bf77..c48b2b3 100644
--- a/xfa/fxfa/parser/cxfa_delta.cpp
+++ b/xfa/fxfa/parser/cxfa_delta.cpp
@@ -9,21 +9,14 @@
 #include "fxjs/xfa/cjx_delta.h"
 #include "third_party/base/ptr_util.h"
 
-namespace {
-
-constexpr wchar_t kName[] = L"delta";
-
-}  // namespace
-
 CXFA_Delta::CXFA_Delta(CXFA_Document* doc, XFA_PacketType packet)
     : CXFA_Node(doc,
                 packet,
                 XFA_XDPPACKET_Form,
                 XFA_ObjectType::Object,
                 XFA_Element::Delta,
-                nullptr,
-                nullptr,
-                kName,
+                {},
+                {},
                 pdfium::MakeUnique<CJX_Delta>(this)) {}
 
-CXFA_Delta::~CXFA_Delta() {}
+CXFA_Delta::~CXFA_Delta() = default;
diff --git a/xfa/fxfa/parser/cxfa_delta.h b/xfa/fxfa/parser/cxfa_delta.h
index 693287b..40bfa56 100644
--- a/xfa/fxfa/parser/cxfa_delta.h
+++ b/xfa/fxfa/parser/cxfa_delta.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Delta : public CXFA_Node {
+class CXFA_Delta final : public CXFA_Node {
  public:
   CXFA_Delta(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Delta() override;
diff --git a/xfa/fxfa/parser/cxfa_deltas.cpp b/xfa/fxfa/parser/cxfa_deltas.cpp
index 4db0936..c55595c 100644
--- a/xfa/fxfa/parser/cxfa_deltas.cpp
+++ b/xfa/fxfa/parser/cxfa_deltas.cpp
@@ -6,10 +6,10 @@
 
 #include "xfa/fxfa/parser/cxfa_deltas.h"
 
-#include "fxjs/xfa/cjx_deltas.h"
+#include "fxjs/xfa/cjx_list.h"
 #include "third_party/base/ptr_util.h"
 
 CXFA_Deltas::CXFA_Deltas(CXFA_Document* doc)
-    : CXFA_List(doc, pdfium::MakeUnique<CJX_Deltas>(this)) {}
+    : CXFA_List(doc, pdfium::MakeUnique<CJX_List>(this)) {}
 
 CXFA_Deltas::~CXFA_Deltas() {}
diff --git a/xfa/fxfa/parser/cxfa_desc.cpp b/xfa/fxfa/parser/cxfa_desc.cpp
index 9cda06d..dc26ca4 100644
--- a/xfa/fxfa/parser/cxfa_desc.cpp
+++ b/xfa/fxfa/parser/cxfa_desc.cpp
@@ -11,20 +11,19 @@
 
 namespace {
 
-const CXFA_Node::PropertyData kPropertyData[] = {
+const CXFA_Node::PropertyData kDescPropertyData[] = {
     {XFA_Element::Text, 1, 0},     {XFA_Element::Time, 1, 0},
     {XFA_Element::DateTime, 1, 0}, {XFA_Element::Image, 1, 0},
     {XFA_Element::Decimal, 1, 0},  {XFA_Element::Boolean, 1, 0},
     {XFA_Element::Integer, 1, 0},  {XFA_Element::ExData, 1, 0},
     {XFA_Element::Date, 1, 0},     {XFA_Element::Float, 1, 0},
-    {XFA_Element::Unknown, 0, 0}};
-const CXFA_Node::AttributeData kAttributeData[] = {
+};
+
+const CXFA_Node::AttributeData kDescAttributeData[] = {
     {XFA_Attribute::Id, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Use, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Usehref, XFA_AttributeType::CData, nullptr},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"desc";
+};
 
 }  // namespace
 
@@ -34,9 +33,8 @@
                 (XFA_XDPPACKET_Template | XFA_XDPPACKET_Form),
                 XFA_ObjectType::Node,
                 XFA_Element::Desc,
-                kPropertyData,
-                kAttributeData,
-                kName,
+                kDescPropertyData,
+                kDescAttributeData,
                 pdfium::MakeUnique<CJX_Desc>(this)) {}
 
-CXFA_Desc::~CXFA_Desc() {}
+CXFA_Desc::~CXFA_Desc() = default;
diff --git a/xfa/fxfa/parser/cxfa_desc.h b/xfa/fxfa/parser/cxfa_desc.h
index 1811c63..11baa90 100644
--- a/xfa/fxfa/parser/cxfa_desc.h
+++ b/xfa/fxfa/parser/cxfa_desc.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Desc : public CXFA_Node {
+class CXFA_Desc final : public CXFA_Node {
  public:
   CXFA_Desc(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Desc() override;
diff --git a/xfa/fxfa/parser/cxfa_destination.cpp b/xfa/fxfa/parser/cxfa_destination.cpp
index 4e5d10b..b80dceb 100644
--- a/xfa/fxfa/parser/cxfa_destination.cpp
+++ b/xfa/fxfa/parser/cxfa_destination.cpp
@@ -6,14 +6,15 @@
 
 #include "xfa/fxfa/parser/cxfa_destination.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kDestinationAttributeData[] = {
     {XFA_Attribute::Desc, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Lock, XFA_AttributeType::Integer, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"destination";
+};
 
 }  // namespace
 
@@ -23,8 +24,8 @@
                 XFA_XDPPACKET_Config,
                 XFA_ObjectType::ContentNode,
                 XFA_Element::Destination,
-                nullptr,
-                kAttributeData,
-                kName) {}
+                {},
+                kDestinationAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_Destination::~CXFA_Destination() {}
+CXFA_Destination::~CXFA_Destination() = default;
diff --git a/xfa/fxfa/parser/cxfa_destination.h b/xfa/fxfa/parser/cxfa_destination.h
index d9fc553..d31434f 100644
--- a/xfa/fxfa/parser/cxfa_destination.h
+++ b/xfa/fxfa/parser/cxfa_destination.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Destination : public CXFA_Node {
+class CXFA_Destination final : public CXFA_Node {
  public:
   CXFA_Destination(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Destination() override;
diff --git a/xfa/fxfa/parser/cxfa_digestmethod.cpp b/xfa/fxfa/parser/cxfa_digestmethod.cpp
index e74832e..70c781d 100644
--- a/xfa/fxfa/parser/cxfa_digestmethod.cpp
+++ b/xfa/fxfa/parser/cxfa_digestmethod.cpp
@@ -6,18 +6,16 @@
 
 #include "xfa/fxfa/parser/cxfa_digestmethod.h"
 
-#include "fxjs/xfa/cjx_digestmethod.h"
+#include "fxjs/xfa/cjx_node.h"
 #include "third_party/base/ptr_util.h"
 
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kDigestMethodAttributeData[] = {
     {XFA_Attribute::Id, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Use, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Usehref, XFA_AttributeType::CData, nullptr},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"digestMethod";
+};
 
 }  // namespace
 
@@ -27,9 +25,8 @@
                 (XFA_XDPPACKET_Template | XFA_XDPPACKET_Form),
                 XFA_ObjectType::NodeC,
                 XFA_Element::DigestMethod,
-                nullptr,
-                kAttributeData,
-                kName,
-                pdfium::MakeUnique<CJX_DigestMethod>(this)) {}
+                {},
+                kDigestMethodAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_DigestMethod::~CXFA_DigestMethod() {}
+CXFA_DigestMethod::~CXFA_DigestMethod() = default;
diff --git a/xfa/fxfa/parser/cxfa_digestmethod.h b/xfa/fxfa/parser/cxfa_digestmethod.h
index 4ac22bb..777f46a 100644
--- a/xfa/fxfa/parser/cxfa_digestmethod.h
+++ b/xfa/fxfa/parser/cxfa_digestmethod.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_DigestMethod : public CXFA_Node {
+class CXFA_DigestMethod final : public CXFA_Node {
  public:
   CXFA_DigestMethod(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_DigestMethod() override;
diff --git a/xfa/fxfa/parser/cxfa_digestmethods.cpp b/xfa/fxfa/parser/cxfa_digestmethods.cpp
index 4993fd0..2a1d1a2 100644
--- a/xfa/fxfa/parser/cxfa_digestmethods.cpp
+++ b/xfa/fxfa/parser/cxfa_digestmethods.cpp
@@ -6,20 +6,18 @@
 
 #include "xfa/fxfa/parser/cxfa_digestmethods.h"
 
-#include "fxjs/xfa/cjx_digestmethods.h"
+#include "fxjs/xfa/cjx_node.h"
 #include "third_party/base/ptr_util.h"
 
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kDigestMethodsAttributeData[] = {
     {XFA_Attribute::Id, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Use, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Type, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::Optional},
+     (void*)XFA_AttributeValue::Optional},
     {XFA_Attribute::Usehref, XFA_AttributeType::CData, nullptr},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"digestMethods";
+};
 
 }  // namespace
 
@@ -30,9 +28,8 @@
                 (XFA_XDPPACKET_Template | XFA_XDPPACKET_Form),
                 XFA_ObjectType::Node,
                 XFA_Element::DigestMethods,
-                nullptr,
-                kAttributeData,
-                kName,
-                pdfium::MakeUnique<CJX_DigestMethods>(this)) {}
+                {},
+                kDigestMethodsAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_DigestMethods::~CXFA_DigestMethods() {}
+CXFA_DigestMethods::~CXFA_DigestMethods() = default;
diff --git a/xfa/fxfa/parser/cxfa_digestmethods.h b/xfa/fxfa/parser/cxfa_digestmethods.h
index 65d40fb..61dac97 100644
--- a/xfa/fxfa/parser/cxfa_digestmethods.h
+++ b/xfa/fxfa/parser/cxfa_digestmethods.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_DigestMethods : public CXFA_Node {
+class CXFA_DigestMethods final : public CXFA_Node {
  public:
   CXFA_DigestMethods(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_DigestMethods() override;
diff --git a/xfa/fxfa/parser/cxfa_document.cpp b/xfa/fxfa/parser/cxfa_document.cpp
index 0675e35..1a2c5b9 100644
--- a/xfa/fxfa/parser/cxfa_document.cpp
+++ b/xfa/fxfa/parser/cxfa_document.cpp
@@ -6,8 +6,17 @@
 
 #include "xfa/fxfa/parser/cxfa_document.h"
 
+#include <set>
+#include <utility>
+
 #include "core/fxcrt/fx_extension.h"
-#include "fxjs/cfxjse_engine.h"
+#include "core/fxcrt/xml/cfx_xmldocument.h"
+#include "fxjs/xfa/cfxjse_engine.h"
+#include "fxjs/xfa/cjx_object.h"
+#include "third_party/base/compiler_specific.h"
+#include "third_party/base/ptr_util.h"
+#include "third_party/base/stl_util.h"
+#include "xfa/fxfa/cxfa_ffdoc.h"
 #include "xfa/fxfa/cxfa_ffnotify.h"
 #include "xfa/fxfa/parser/cscript_datawindow.h"
 #include "xfa/fxfa/parser/cscript_eventpseudomodel.h"
@@ -15,26 +24,115 @@
 #include "xfa/fxfa/parser/cscript_layoutpseudomodel.h"
 #include "xfa/fxfa/parser/cscript_logpseudomodel.h"
 #include "xfa/fxfa/parser/cscript_signaturepseudomodel.h"
+#include "xfa/fxfa/parser/cxfa_bind.h"
 #include "xfa/fxfa/parser/cxfa_datagroup.h"
-#include "xfa/fxfa/parser/cxfa_document_parser.h"
+#include "xfa/fxfa/parser/cxfa_exdata.h"
+#include "xfa/fxfa/parser/cxfa_form.h"
+#include "xfa/fxfa/parser/cxfa_image.h"
 #include "xfa/fxfa/parser/cxfa_interactive.h"
-#include "xfa/fxfa/parser/cxfa_layoutprocessor.h"
+#include "xfa/fxfa/parser/cxfa_items.h"
 #include "xfa/fxfa/parser/cxfa_localemgr.h"
 #include "xfa/fxfa/parser/cxfa_node.h"
+#include "xfa/fxfa/parser/cxfa_occur.h"
+#include "xfa/fxfa/parser/cxfa_pageset.h"
 #include "xfa/fxfa/parser/cxfa_pdf.h"
 #include "xfa/fxfa/parser/cxfa_present.h"
+#include "xfa/fxfa/parser/cxfa_subform.h"
+#include "xfa/fxfa/parser/cxfa_template.h"
+#include "xfa/fxfa/parser/cxfa_traversestrategy_xfacontainernode.h"
 #include "xfa/fxfa/parser/cxfa_traversestrategy_xfanode.h"
+#include "xfa/fxfa/parser/cxfa_value.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 {
 
-constexpr const wchar_t kTemplateNS[] =
-    L"http://www.xfa.org/schema/xfa-template/";
+const wchar_t kTemplateNS[] = L"http://www.xfa.org/schema/xfa-template/";
 
-void MergeNodeRecurse(CXFA_Document* pDocument,
-                      CXFA_Node* pDestNodeParent,
-                      CXFA_Node* pProtoNode) {
+struct RecurseRecord {
+  CXFA_Node* pTemplateChild;
+  CXFA_Node* pDataChild;
+};
+
+class CXFA_TraverseStrategy_DDGroup {
+ public:
+  static CXFA_Node* GetFirstChild(CXFA_Node* pDDGroupNode) {
+    return pDDGroupNode->GetFirstChildByName(XFA_HASHCODE_Group);
+  }
+  static CXFA_Node* GetNextSibling(CXFA_Node* pDDGroupNode) {
+    return pDDGroupNode->GetNextSameNameSibling(XFA_HASHCODE_Group);
+  }
+  static CXFA_Node* GetParent(CXFA_Node* pDDGroupNode) {
+    return pDDGroupNode->GetParent();
+  }
+};
+
+void FormValueNode_MatchNoneCreateChild(CXFA_Node* pFormNode) {
+  ASSERT(pFormNode->IsWidgetReady());
+  // GetUIChildNode has the side effect of creating the UI child.
+  pFormNode->GetUIChildNode();
+}
+
+CXFA_Node* FormValueNode_CreateChild(CXFA_Node* pValueNode, XFA_Element iType) {
+  CXFA_Node* pChildNode = pValueNode->GetFirstChild();
+  if (!pChildNode) {
+    if (iType == XFA_Element::Unknown)
+      return nullptr;
+
+    pChildNode =
+        pValueNode->JSObject()->GetOrCreateProperty<CXFA_Node>(0, iType);
+  }
+  return pChildNode;
+}
+
+void FormValueNode_SetChildContent(CXFA_Node* pValueNode,
+                                   const WideString& wsContent,
+                                   XFA_Element iType) {
+  if (!pValueNode)
+    return;
+
+  ASSERT(pValueNode->GetPacketType() == XFA_PacketType::Form);
+  CXFA_Node* pChildNode = FormValueNode_CreateChild(pValueNode, iType);
+  if (!pChildNode)
+    return;
+
+  switch (pChildNode->GetObjectType()) {
+    case XFA_ObjectType::ContentNode: {
+      CXFA_Node* pContentRawDataNode = pChildNode->GetFirstChild();
+      if (!pContentRawDataNode) {
+        XFA_Element element = XFA_Element::Sharptext;
+        if (pChildNode->GetElementType() == XFA_Element::ExData) {
+          Optional<WideString> contentType =
+              pChildNode->JSObject()->TryAttribute(XFA_Attribute::ContentType,
+                                                   false);
+          if (contentType.has_value()) {
+            if (contentType.value().EqualsASCII("text/html"))
+              element = XFA_Element::SharpxHTML;
+            else if (contentType.value().EqualsASCII("text/xml"))
+              element = XFA_Element::Sharpxml;
+          }
+        }
+        pContentRawDataNode = pChildNode->CreateSamePacketNode(element);
+        pChildNode->InsertChildAndNotify(pContentRawDataNode, nullptr);
+      }
+      pContentRawDataNode->JSObject()->SetCData(XFA_Attribute::Value, wsContent,
+                                                false, false);
+      break;
+    }
+    case XFA_ObjectType::NodeC:
+    case XFA_ObjectType::TextNode:
+    case XFA_ObjectType::NodeV: {
+      pChildNode->JSObject()->SetCData(XFA_Attribute::Value, wsContent, false,
+                                       false);
+      break;
+    }
+    default:
+      break;
+  }
+}
+
+void MergeNodeRecurse(CXFA_Node* pDestNodeParent, CXFA_Node* pProtoNode) {
   CXFA_Node* pExistingNode = nullptr;
   for (CXFA_Node* pFormChild = pDestNodeParent->GetFirstChild(); pFormChild;
        pFormChild = pFormChild->GetNextSibling()) {
@@ -51,29 +149,27 @@
     pExistingNode->SetTemplateNode(pProtoNode);
     for (CXFA_Node* pTemplateChild = pProtoNode->GetFirstChild();
          pTemplateChild; pTemplateChild = pTemplateChild->GetNextSibling()) {
-      MergeNodeRecurse(pDocument, pExistingNode, pTemplateChild);
+      MergeNodeRecurse(pExistingNode, pTemplateChild);
     }
     return;
   }
   CXFA_Node* pNewNode = pProtoNode->Clone(true);
   pNewNode->SetTemplateNode(pProtoNode);
-  pDestNodeParent->InsertChild(pNewNode, nullptr);
+  pDestNodeParent->InsertChildAndNotify(pNewNode, nullptr);
 }
 
-void MergeNode(CXFA_Document* pDocument,
-               CXFA_Node* pDestNode,
-               CXFA_Node* pProtoNode) {
+void MergeNode(CXFA_Node* pDestNode, CXFA_Node* pProtoNode) {
   {
     CXFA_NodeIterator sIterator(pDestNode);
     for (CXFA_Node* pNode = sIterator.GetCurrent(); pNode;
          pNode = sIterator.MoveToNext()) {
-      pNode->SetFlag(XFA_NodeFlag_UnusedNode, true);
+      pNode->SetFlag(XFA_NodeFlag_UnusedNode);
     }
   }
   pDestNode->SetTemplateNode(pProtoNode);
   for (CXFA_Node* pTemplateChild = pProtoNode->GetFirstChild(); pTemplateChild;
        pTemplateChild = pTemplateChild->GetNextSibling()) {
-    MergeNodeRecurse(pDocument, pDestNode, pTemplateChild);
+    MergeNodeRecurse(pDestNode, pTemplateChild);
   }
   {
     CXFA_NodeIterator sIterator(pDestNode);
@@ -84,42 +180,1114 @@
   }
 }
 
+CXFA_Node* CloneOrMergeInstanceManager(CXFA_Document* pDocument,
+                                       CXFA_Node* pFormParent,
+                                       CXFA_Node* pTemplateNode,
+                                       std::vector<CXFA_Node*>* subforms) {
+  WideString wsSubformName =
+      pTemplateNode->JSObject()->GetCData(XFA_Attribute::Name);
+  WideString wsInstMgrNodeName = L"_" + wsSubformName;
+  uint32_t dwInstNameHash =
+      FX_HashCode_GetW(wsInstMgrNodeName.AsStringView(), false);
+  CXFA_Node* pExistingNode = XFA_DataMerge_FindFormDOMInstance(
+      pDocument, XFA_Element::InstanceManager, dwInstNameHash, pFormParent);
+  if (pExistingNode) {
+    uint32_t dwNameHash = pTemplateNode->GetNameHash();
+    for (CXFA_Node* pNode = pExistingNode->GetNextSibling(); pNode;) {
+      XFA_Element eCurType = pNode->GetElementType();
+      if (eCurType == XFA_Element::InstanceManager)
+        break;
+
+      if ((eCurType != XFA_Element::Subform) &&
+          (eCurType != XFA_Element::SubformSet)) {
+        pNode = pNode->GetNextSibling();
+        continue;
+      }
+      if (dwNameHash != pNode->GetNameHash())
+        break;
+
+      CXFA_Node* pNextNode = pNode->GetNextSibling();
+      pFormParent->RemoveChildAndNotify(pNode, true);
+      subforms->push_back(pNode);
+      pNode = pNextNode;
+    }
+    pFormParent->RemoveChildAndNotify(pExistingNode, true);
+    pFormParent->InsertChildAndNotify(pExistingNode, nullptr);
+    pExistingNode->ClearFlag(XFA_NodeFlag_UnusedNode);
+    pExistingNode->SetTemplateNode(pTemplateNode);
+    return pExistingNode;
+  }
+
+  CXFA_Node* pNewNode =
+      pDocument->CreateNode(XFA_PacketType::Form, XFA_Element::InstanceManager);
+  wsInstMgrNodeName =
+      L"_" + pTemplateNode->JSObject()->GetCData(XFA_Attribute::Name);
+  pNewNode->JSObject()->SetCData(XFA_Attribute::Name, wsInstMgrNodeName, false,
+                                 false);
+  pFormParent->InsertChildAndNotify(pNewNode, nullptr);
+  pNewNode->SetTemplateNode(pTemplateNode);
+  return pNewNode;
+}
+
+void SortRecurseRecord(std::vector<RecurseRecord>* rgRecords,
+                       CXFA_Node* pDataScope,
+                       bool bChoiceMode) {
+  std::vector<RecurseRecord> rgResultRecord;
+  for (CXFA_Node* pNode = pDataScope->GetFirstChild(); pNode;
+       pNode = pNode->GetNextSibling()) {
+    auto it = std::find_if(rgRecords->begin(), rgRecords->end(),
+                           [pNode](const RecurseRecord& record) {
+                             return pNode == record.pDataChild;
+                           });
+    if (it != rgRecords->end()) {
+      rgResultRecord.push_back(*it);
+      rgRecords->erase(it);
+      if (bChoiceMode)
+        break;
+    }
+  }
+  if (rgResultRecord.empty())
+    return;
+
+  if (!bChoiceMode) {
+    rgResultRecord.insert(rgResultRecord.end(), rgRecords->begin(),
+                          rgRecords->end());
+  }
+  *rgRecords = rgResultRecord;
+}
+
+CXFA_Node* ScopeMatchGlobalBinding(CXFA_Node* pDataScope,
+                                   uint32_t dwNameHash,
+                                   XFA_Element eMatchDataNodeType,
+                                   bool bUpLevel) {
+  for (CXFA_Node *pCurDataScope = pDataScope, *pLastDataScope = nullptr;
+       pCurDataScope &&
+       pCurDataScope->GetPacketType() == XFA_PacketType::Datasets;
+       pLastDataScope = pCurDataScope,
+                 pCurDataScope = pCurDataScope->GetParent()) {
+    for (CXFA_Node* pDataChild = pCurDataScope->GetFirstChildByName(dwNameHash);
+         pDataChild;
+         pDataChild = pDataChild->GetNextSameNameSibling(dwNameHash)) {
+      if (pDataChild == pLastDataScope ||
+          (eMatchDataNodeType != XFA_Element::DataModel &&
+           pDataChild->GetElementType() != eMatchDataNodeType) ||
+          pDataChild->HasBindItem()) {
+        continue;
+      }
+      return pDataChild;
+    }
+
+    for (CXFA_DataGroup* pDataChild =
+             pCurDataScope->GetFirstChildByClass<CXFA_DataGroup>(
+                 XFA_Element::DataGroup);
+         pDataChild;
+         pDataChild = pDataChild->GetNextSameClassSibling<CXFA_DataGroup>(
+             XFA_Element::DataGroup)) {
+      CXFA_Node* pDataNode = ScopeMatchGlobalBinding(pDataChild, dwNameHash,
+                                                     eMatchDataNodeType, false);
+      if (pDataNode)
+        return pDataNode;
+    }
+    if (!bUpLevel)
+      break;
+  }
+  return nullptr;
+}
+
+CXFA_Node* FindGlobalDataNode(CXFA_Document* pDocument,
+                              const WideString& wsName,
+                              CXFA_Node* pDataScope,
+                              XFA_Element eMatchNodeType) {
+  if (wsName.IsEmpty())
+    return nullptr;
+
+  uint32_t dwNameHash = FX_HashCode_GetW(wsName.AsStringView(), false);
+  CXFA_Node* pBounded = pDocument->GetGlobalBinding(dwNameHash);
+  if (!pBounded) {
+    pBounded =
+        ScopeMatchGlobalBinding(pDataScope, dwNameHash, eMatchNodeType, true);
+    if (pBounded)
+      pDocument->RegisterGlobalBinding(dwNameHash, pBounded);
+  }
+  return pBounded;
+}
+
+CXFA_Node* FindOnceDataNode(const WideString& wsName,
+                            CXFA_Node* pDataScope,
+                            XFA_Element eMatchNodeType) {
+  if (wsName.IsEmpty())
+    return nullptr;
+
+  uint32_t dwNameHash = FX_HashCode_GetW(wsName.AsStringView(), false);
+  CXFA_Node* pLastDataScope = nullptr;
+  for (CXFA_Node* pCurDataScope = pDataScope;
+       pCurDataScope &&
+       pCurDataScope->GetPacketType() == XFA_PacketType::Datasets;
+       pCurDataScope = pCurDataScope->GetParent()) {
+    for (CXFA_Node* pDataChild = pCurDataScope->GetFirstChildByName(dwNameHash);
+         pDataChild;
+         pDataChild = pDataChild->GetNextSameNameSibling(dwNameHash)) {
+      if (pDataChild == pLastDataScope || pDataChild->HasBindItem() ||
+          (eMatchNodeType != XFA_Element::DataModel &&
+           pDataChild->GetElementType() != eMatchNodeType)) {
+        continue;
+      }
+      return pDataChild;
+    }
+    pLastDataScope = pCurDataScope;
+  }
+  return nullptr;
+}
+
+CXFA_Node* FindDataRefDataNode(CXFA_Document* pDocument,
+                               const WideString& wsRef,
+                               CXFA_Node* pDataScope,
+                               XFA_Element eMatchNodeType,
+                               CXFA_Node* pTemplateNode,
+                               bool bForceBind,
+                               bool bUpLevel) {
+  uint32_t dFlags = XFA_RESOLVENODE_Children | XFA_RESOLVENODE_BindNew;
+  if (bUpLevel || !wsRef.EqualsASCII("name"))
+    dFlags |= (XFA_RESOLVENODE_Parent | XFA_RESOLVENODE_Siblings);
+
+  XFA_RESOLVENODE_RS rs;
+  pDocument->GetScriptContext()->ResolveObjects(
+      pDataScope, wsRef.AsStringView(), &rs, dFlags, pTemplateNode);
+  if (rs.dwFlags == XFA_ResolveNode_RSType_CreateNodeAll ||
+      rs.dwFlags == XFA_ResolveNode_RSType_CreateNodeMidAll ||
+      rs.objects.size() > 1) {
+    return pDocument->GetNotBindNode(rs.objects);
+  }
+
+  if (rs.dwFlags == XFA_ResolveNode_RSType_CreateNodeOne) {
+    CXFA_Object* pObject =
+        !rs.objects.empty() ? rs.objects.front().Get() : nullptr;
+    CXFA_Node* pNode = ToNode(pObject);
+    return (bForceBind || !pNode || !pNode->HasBindItem()) ? pNode : nullptr;
+  }
+  return nullptr;
+}
+
+CXFA_Node* FindMatchingDataNode(
+    CXFA_Document* pDocument,
+    CXFA_Node* pTemplateNode,
+    CXFA_Node* pDataScope,
+    bool& bAccessedDataDOM,
+    bool bForceBind,
+    CXFA_NodeIteratorTemplate<CXFA_Node,
+                              CXFA_TraverseStrategy_XFAContainerNode>*
+        pIterator,
+    bool& bSelfMatch,
+    XFA_AttributeValue& eBindMatch,
+    bool bUpLevel) {
+  CXFA_Node* pResult = nullptr;
+  CXFA_Node* pCurTemplateNode = pIterator->GetCurrent();
+  while (pCurTemplateNode) {
+    XFA_Element eMatchNodeType;
+    switch (pCurTemplateNode->GetElementType()) {
+      case XFA_Element::Subform:
+        eMatchNodeType = XFA_Element::DataGroup;
+        break;
+      case XFA_Element::Field: {
+        eMatchNodeType = XFA_FieldIsMultiListBox(pCurTemplateNode)
+                             ? XFA_Element::DataGroup
+                             : XFA_Element::DataValue;
+      } break;
+      case XFA_Element::ExclGroup:
+        eMatchNodeType = XFA_Element::DataValue;
+        break;
+      default:
+        pCurTemplateNode = pIterator->MoveToNext();
+        continue;
+    }
+
+    CXFA_Occur* pTemplateNodeOccur =
+        pCurTemplateNode->GetFirstChildByClass<CXFA_Occur>(XFA_Element::Occur);
+    if (pTemplateNodeOccur) {
+      int32_t iMin;
+      int32_t iMax;
+      int32_t iInit;
+      std::tie(iMin, iMax, iInit) = pTemplateNodeOccur->GetOccurInfo();
+      if (iMax == 0) {
+        pCurTemplateNode = pIterator->MoveToNext();
+        continue;
+      }
+    }
+
+    CXFA_Bind* pTemplateNodeBind =
+        pCurTemplateNode->GetFirstChildByClass<CXFA_Bind>(XFA_Element::Bind);
+    XFA_AttributeValue eMatch =
+        pTemplateNodeBind
+            ? pTemplateNodeBind->JSObject()->GetEnum(XFA_Attribute::Match)
+            : XFA_AttributeValue::Once;
+    eBindMatch = eMatch;
+    switch (eMatch) {
+      case XFA_AttributeValue::None:
+        pCurTemplateNode = pIterator->MoveToNext();
+        continue;
+      case XFA_AttributeValue::Global:
+        bAccessedDataDOM = true;
+        if (!bForceBind) {
+          pCurTemplateNode = pIterator->MoveToNext();
+          continue;
+        }
+        if (eMatchNodeType == XFA_Element::DataValue ||
+            (eMatchNodeType == XFA_Element::DataGroup &&
+             XFA_FieldIsMultiListBox(pTemplateNodeBind))) {
+          CXFA_Node* pGlobalBindNode = FindGlobalDataNode(
+              pDocument,
+              pCurTemplateNode->JSObject()->GetCData(XFA_Attribute::Name),
+              pDataScope, eMatchNodeType);
+          if (!pGlobalBindNode) {
+            pCurTemplateNode = pIterator->MoveToNext();
+            continue;
+          }
+          pResult = pGlobalBindNode;
+          break;
+        }
+        FALLTHROUGH;
+      case XFA_AttributeValue::Once: {
+        bAccessedDataDOM = true;
+        CXFA_Node* pOnceBindNode = FindOnceDataNode(
+            pCurTemplateNode->JSObject()->GetCData(XFA_Attribute::Name),
+            pDataScope, eMatchNodeType);
+        if (!pOnceBindNode) {
+          pCurTemplateNode = pIterator->MoveToNext();
+          continue;
+        }
+        pResult = pOnceBindNode;
+        break;
+      }
+      case XFA_AttributeValue::DataRef: {
+        bAccessedDataDOM = true;
+        CXFA_Node* pDataRefBindNode = FindDataRefDataNode(
+            pDocument,
+            pTemplateNodeBind->JSObject()->GetCData(XFA_Attribute::Ref),
+            pDataScope, eMatchNodeType, pTemplateNode, bForceBind, bUpLevel);
+        if (pDataRefBindNode &&
+            pDataRefBindNode->GetElementType() == eMatchNodeType) {
+          pResult = pDataRefBindNode;
+        }
+        if (!pResult) {
+          pCurTemplateNode = pIterator->SkipChildrenAndMoveToNext();
+          continue;
+        }
+        break;
+      }
+      default:
+        break;
+    }
+    if (pCurTemplateNode == pTemplateNode && pResult)
+      bSelfMatch = true;
+    break;
+  }
+  return pResult;
+}
+
+void CreateDataBinding(CXFA_Node* pFormNode,
+                       CXFA_Node* pDataNode,
+                       bool bDataToForm) {
+  pFormNode->SetBindingNode(pDataNode);
+  pDataNode->AddBindItem(pFormNode);
+  XFA_Element eType = pFormNode->GetElementType();
+  if (eType != XFA_Element::Field && eType != XFA_Element::ExclGroup)
+    return;
+
+  ASSERT(pFormNode->IsWidgetReady());
+  auto* defValue = pFormNode->JSObject()->GetOrCreateProperty<CXFA_Value>(
+      0, XFA_Element::Value);
+  if (!bDataToForm) {
+    WideString wsValue;
+    switch (pFormNode->GetFFWidgetType()) {
+      case XFA_FFWidgetType::kImageEdit: {
+        CXFA_Image* image = defValue ? defValue->GetImageIfExists() : nullptr;
+        WideString wsContentType;
+        WideString wsHref;
+        if (image) {
+          wsValue = image->GetContent();
+          wsContentType = image->GetContentType();
+          wsHref = image->GetHref();
+        }
+        CFX_XMLElement* pXMLDataElement =
+            ToXMLElement(pDataNode->GetXMLMappingNode());
+        ASSERT(pXMLDataElement);
+        pDataNode->JSObject()->SetAttributeValue(
+            wsValue, pFormNode->GetFormatDataValue(wsValue), false, false);
+        pDataNode->JSObject()->SetCData(XFA_Attribute::ContentType,
+                                        wsContentType, false, false);
+        if (!wsHref.IsEmpty())
+          pXMLDataElement->SetAttribute(L"href", wsHref);
+
+        break;
+      }
+      case XFA_FFWidgetType::kChoiceList:
+        wsValue = defValue ? defValue->GetChildValueContent() : WideString();
+        if (pFormNode->IsChoiceListMultiSelect()) {
+          std::vector<WideString> wsSelTextArray =
+              pFormNode->GetSelectedItemsValue();
+          if (!wsSelTextArray.empty()) {
+            for (const auto& text : wsSelTextArray) {
+              CXFA_Node* pValue =
+                  pDataNode->CreateSamePacketNode(XFA_Element::DataValue);
+              pValue->JSObject()->SetCData(XFA_Attribute::Name, L"value", false,
+                                           false);
+              pValue->CreateXMLMappingNode();
+              pDataNode->InsertChildAndNotify(pValue, nullptr);
+              pValue->JSObject()->SetCData(XFA_Attribute::Value, text, false,
+                                           false);
+            }
+          } else {
+            CFX_XMLElement* pElement =
+                ToXMLElement(pDataNode->GetXMLMappingNode());
+            pElement->SetAttribute(L"xfa:dataNode", L"dataGroup");
+          }
+        } else if (!wsValue.IsEmpty()) {
+          pDataNode->JSObject()->SetAttributeValue(
+              wsValue, pFormNode->GetFormatDataValue(wsValue), false, false);
+        }
+        break;
+      case XFA_FFWidgetType::kCheckButton:
+        wsValue = defValue ? defValue->GetChildValueContent() : WideString();
+        if (wsValue.IsEmpty())
+          break;
+
+        pDataNode->JSObject()->SetAttributeValue(
+            wsValue, pFormNode->GetFormatDataValue(wsValue), false, false);
+        break;
+      case XFA_FFWidgetType::kExclGroup: {
+        CXFA_Node* pChecked = nullptr;
+        CXFA_Node* pChild = pFormNode->GetFirstChild();
+        for (; pChild; pChild = pChild->GetNextSibling()) {
+          if (pChild->GetElementType() != XFA_Element::Field)
+            continue;
+
+          auto* pValue =
+              pChild->GetChild<CXFA_Value>(0, XFA_Element::Value, false);
+          if (!pValue)
+            continue;
+
+          wsValue = pValue->GetChildValueContent();
+          if (wsValue.IsEmpty())
+            continue;
+
+          CXFA_Items* pItems =
+              pChild->GetChild<CXFA_Items>(0, XFA_Element::Items, false);
+          if (!pItems)
+            continue;
+
+          CXFA_Node* pText = pItems->GetFirstChild();
+          if (!pText)
+            continue;
+
+          WideString wsContent = pText->JSObject()->GetContent(false);
+          if (wsContent == wsValue) {
+            pChecked = pChild;
+            pDataNode->JSObject()->SetAttributeValue(wsValue, wsValue, false,
+                                                     false);
+            pFormNode->JSObject()->SetCData(XFA_Attribute::Value, wsContent,
+                                            false, false);
+            break;
+          }
+        }
+        if (!pChecked)
+          break;
+
+        pChild = pFormNode->GetFirstChild();
+        for (; pChild; pChild = pChild->GetNextSibling()) {
+          if (pChild == pChecked)
+            continue;
+          if (pChild->GetElementType() != XFA_Element::Field)
+            continue;
+
+          CXFA_Value* pValue =
+              pChild->JSObject()->GetOrCreateProperty<CXFA_Value>(
+                  0, XFA_Element::Value);
+          CXFA_Items* pItems =
+              pChild->GetChild<CXFA_Items>(0, XFA_Element::Items, false);
+          CXFA_Node* pText = pItems ? pItems->GetFirstChild() : nullptr;
+          if (pText)
+            pText = pText->GetNextSibling();
+
+          WideString wsContent;
+          if (pText)
+            wsContent = pText->JSObject()->GetContent(false);
+
+          FormValueNode_SetChildContent(pValue, wsContent, XFA_Element::Text);
+        }
+        break;
+      }
+      case XFA_FFWidgetType::kNumericEdit: {
+        wsValue = defValue ? defValue->GetChildValueContent() : WideString();
+        if (wsValue.IsEmpty())
+          break;
+
+        wsValue = pFormNode->NormalizeNumStr(wsValue);
+        pDataNode->JSObject()->SetAttributeValue(
+            wsValue, pFormNode->GetFormatDataValue(wsValue), false, false);
+        CXFA_Value* pValue =
+            pFormNode->JSObject()->GetOrCreateProperty<CXFA_Value>(
+                0, XFA_Element::Value);
+        FormValueNode_SetChildContent(pValue, wsValue, XFA_Element::Float);
+        break;
+      }
+      default:
+        wsValue = defValue ? defValue->GetChildValueContent() : WideString();
+        if (wsValue.IsEmpty())
+          break;
+
+        pDataNode->JSObject()->SetAttributeValue(
+            wsValue, pFormNode->GetFormatDataValue(wsValue), false, false);
+        break;
+    }
+    return;
+  }
+
+  WideString wsXMLValue = pDataNode->JSObject()->GetContent(false);
+  WideString wsNormalizeValue = pFormNode->GetNormalizeDataValue(wsXMLValue);
+
+  pDataNode->JSObject()->SetAttributeValue(wsNormalizeValue, wsXMLValue, false,
+                                           false);
+  switch (pFormNode->GetFFWidgetType()) {
+    case XFA_FFWidgetType::kImageEdit: {
+      FormValueNode_SetChildContent(defValue, wsNormalizeValue,
+                                    XFA_Element::Image);
+      CXFA_Image* image = defValue ? defValue->GetImageIfExists() : nullptr;
+      if (image) {
+        CFX_XMLElement* pXMLDataElement =
+            ToXMLElement(pDataNode->GetXMLMappingNode());
+        WideString wsContentType =
+            pXMLDataElement->GetAttribute(L"xfa:contentType");
+        if (!wsContentType.IsEmpty()) {
+          pDataNode->JSObject()->SetCData(XFA_Attribute::ContentType,
+                                          wsContentType, false, false);
+          image->SetContentType(wsContentType);
+        }
+
+        WideString wsHref = pXMLDataElement->GetAttribute(L"href");
+        if (!wsHref.IsEmpty())
+          image->SetHref(wsHref);
+      }
+      break;
+    }
+    case XFA_FFWidgetType::kChoiceList:
+      if (pFormNode->IsChoiceListMultiSelect()) {
+        std::vector<CXFA_Node*> items = pDataNode->GetNodeListWithFilter(
+            XFA_NODEFILTER_Children | XFA_NODEFILTER_Properties);
+        if (!items.empty()) {
+          bool single = items.size() == 1;
+          wsNormalizeValue.clear();
+
+          for (CXFA_Node* pNode : items) {
+            WideString wsItem = pNode->JSObject()->GetContent(false);
+            if (single)
+              wsItem += L"\n";
+
+            wsNormalizeValue += wsItem;
+          }
+          CXFA_ExData* exData =
+              defValue ? defValue->GetExDataIfExists() : nullptr;
+          if (exData)
+            exData->SetContentType(single ? L"text/plain" : L"text/xml");
+        }
+        FormValueNode_SetChildContent(defValue, wsNormalizeValue,
+                                      XFA_Element::ExData);
+      } else {
+        FormValueNode_SetChildContent(defValue, wsNormalizeValue,
+                                      XFA_Element::Text);
+      }
+      break;
+    case XFA_FFWidgetType::kExclGroup: {
+      pFormNode->SetSelectedMemberByValue(wsNormalizeValue.AsStringView(),
+                                          false, false, false);
+      break;
+    }
+    case XFA_FFWidgetType::kDateTimeEdit:
+      FormValueNode_SetChildContent(defValue, wsNormalizeValue,
+                                    XFA_Element::DateTime);
+      break;
+    case XFA_FFWidgetType::kNumericEdit: {
+      WideString wsPicture =
+          pFormNode->GetPictureContent(XFA_VALUEPICTURE_DataBind);
+      if (wsPicture.IsEmpty())
+        wsNormalizeValue = pFormNode->NormalizeNumStr(wsNormalizeValue);
+
+      FormValueNode_SetChildContent(defValue, wsNormalizeValue,
+                                    XFA_Element::Float);
+      break;
+    }
+    default:
+      FormValueNode_SetChildContent(defValue, wsNormalizeValue,
+                                    XFA_Element::Text);
+      break;
+  }
+}
+
+CXFA_Node* MaybeCreateDataNode(CXFA_Document* pDocument,
+                               CXFA_Node* pDataParent,
+                               XFA_Element eNodeType,
+                               const WideString& wsName) {
+  if (!pDataParent)
+    return nullptr;
+
+  CXFA_Node* pParentDDNode = pDataParent->GetDataDescriptionNode();
+  if (!pParentDDNode) {
+    CXFA_Node* pDataNode =
+        pDocument->CreateNode(XFA_PacketType::Datasets, eNodeType);
+    pDataNode->JSObject()->SetCData(XFA_Attribute::Name, wsName, false, false);
+    pDataNode->CreateXMLMappingNode();
+    pDataParent->InsertChildAndNotify(pDataNode, nullptr);
+    pDataNode->SetFlag(XFA_NodeFlag_Initialized);
+    return pDataNode;
+  }
+
+  CXFA_NodeIteratorTemplate<CXFA_Node, CXFA_TraverseStrategy_DDGroup> sIterator(
+      pParentDDNode);
+  for (CXFA_Node* pDDGroupNode = sIterator.GetCurrent(); pDDGroupNode;
+       pDDGroupNode = sIterator.MoveToNext()) {
+    if (pDDGroupNode != pParentDDNode) {
+      if (pDDGroupNode->GetElementType() != XFA_Element::DataGroup)
+        continue;
+
+      Optional<WideString> ns = pDDGroupNode->JSObject()->TryNamespace();
+      if (!ns.has_value() ||
+          !ns.value().EqualsASCII("http://ns.adobe.com/data-description/")) {
+        continue;
+      }
+    }
+
+    CXFA_Node* pDDNode =
+        pDDGroupNode->GetFirstChildByName(wsName.AsStringView());
+    if (!pDDNode)
+      continue;
+    if (pDDNode->GetElementType() != eNodeType)
+      break;
+
+    CXFA_Node* pDataNode =
+        pDocument->CreateNode(XFA_PacketType::Datasets, eNodeType);
+    pDataNode->JSObject()->SetCData(XFA_Attribute::Name, wsName, false, false);
+    pDataNode->CreateXMLMappingNode();
+    if (eNodeType == XFA_Element::DataValue &&
+        pDDNode->JSObject()->GetEnum(XFA_Attribute::Contains) ==
+            XFA_AttributeValue::MetaData) {
+      pDataNode->JSObject()->SetEnum(XFA_Attribute::Contains,
+                                     XFA_AttributeValue::MetaData, false);
+    }
+    pDataParent->InsertChildAndNotify(pDataNode, nullptr);
+    pDataNode->SetDataDescriptionNode(pDDNode);
+    pDataNode->SetFlag(XFA_NodeFlag_Initialized);
+    return pDataNode;
+  }
+  return nullptr;
+}
+
+CXFA_Node* CopyContainer_Field(CXFA_Document* pDocument,
+                               CXFA_Node* pTemplateNode,
+                               CXFA_Node* pFormNode,
+                               CXFA_Node* pDataScope,
+                               bool bDataMerge,
+                               bool bUpLevel) {
+  CXFA_Node* pFieldNode = XFA_NodeMerge_CloneOrMergeContainer(
+      pDocument, pFormNode, pTemplateNode, false, nullptr);
+  ASSERT(pFieldNode);
+  for (CXFA_Node* pTemplateChildNode = pTemplateNode->GetFirstChild();
+       pTemplateChildNode;
+       pTemplateChildNode = pTemplateChildNode->GetNextSibling()) {
+    if (XFA_DataMerge_NeedGenerateForm(pTemplateChildNode, true)) {
+      XFA_NodeMerge_CloneOrMergeContainer(pDocument, pFieldNode,
+                                          pTemplateChildNode, true, nullptr);
+    } else if (pTemplateNode->GetElementType() == XFA_Element::ExclGroup &&
+               pTemplateChildNode->IsContainerNode()) {
+      if (pTemplateChildNode->GetElementType() == XFA_Element::Field) {
+        CopyContainer_Field(pDocument, pTemplateChildNode, pFieldNode, nullptr,
+                            false, true);
+      }
+    }
+  }
+  if (bDataMerge) {
+    bool bAccessedDataDOM = false;
+    bool bSelfMatch = false;
+    XFA_AttributeValue eBindMatch;
+    CXFA_NodeIteratorTemplate<CXFA_Node, CXFA_TraverseStrategy_XFAContainerNode>
+        sNodeIter(pTemplateNode);
+    CXFA_Node* pDataNode = FindMatchingDataNode(
+        pDocument, pTemplateNode, pDataScope, bAccessedDataDOM, true,
+        &sNodeIter, bSelfMatch, eBindMatch, bUpLevel);
+    if (pDataNode)
+      CreateDataBinding(pFieldNode, pDataNode, true);
+  } else {
+    FormValueNode_MatchNoneCreateChild(pFieldNode);
+  }
+  return pFieldNode;
+}
+
+CXFA_Node* CopyContainer_SubformSet(CXFA_Document* pDocument,
+                                    CXFA_Node* pTemplateNode,
+                                    CXFA_Node* pFormParentNode,
+                                    CXFA_Node* pDataScope,
+                                    bool bOneInstance,
+                                    bool bDataMerge) {
+  XFA_Element eType = pTemplateNode->GetElementType();
+  CXFA_Node* pOccurNode = nullptr;
+  CXFA_Node* pFirstInstance = nullptr;
+  bool bUseInstanceManager =
+      pFormParentNode->GetElementType() != XFA_Element::Area;
+  CXFA_Node* pInstMgrNode = nullptr;
+  std::vector<CXFA_Node*> subformArray;
+  std::vector<CXFA_Node*>* pSearchArray = nullptr;
+  if (!bOneInstance &&
+      (eType == XFA_Element::SubformSet || eType == XFA_Element::Subform)) {
+    pInstMgrNode = bUseInstanceManager ? CloneOrMergeInstanceManager(
+                                             pDocument, pFormParentNode,
+                                             pTemplateNode, &subformArray)
+                                       : nullptr;
+    if (CXFA_Occur* pOccurTemplateNode =
+            pTemplateNode->GetFirstChildByClass<CXFA_Occur>(
+                XFA_Element::Occur)) {
+      pOccurNode = pInstMgrNode ? XFA_NodeMerge_CloneOrMergeContainer(
+                                      pDocument, pInstMgrNode,
+                                      pOccurTemplateNode, false, nullptr)
+                                : pOccurTemplateNode;
+    } else if (pInstMgrNode) {
+      pOccurNode =
+          pInstMgrNode->GetFirstChildByClass<CXFA_Occur>(XFA_Element::Occur);
+      if (pOccurNode)
+        pOccurNode->ClearFlag(XFA_NodeFlag_UnusedNode);
+    }
+    if (pInstMgrNode) {
+      pInstMgrNode->SetFlagAndNotify(XFA_NodeFlag_Initialized);
+      pSearchArray = &subformArray;
+      if (pFormParentNode->GetElementType() == XFA_Element::PageArea) {
+        bOneInstance = true;
+        if (subformArray.empty())
+          pSearchArray = nullptr;
+      } else if (pTemplateNode->GetNameHash() == 0 && subformArray.empty()) {
+        pSearchArray = nullptr;
+      }
+    }
+  }
+
+  int32_t iMax = 1;
+  int32_t iInit = 1;
+  int32_t iMin = 1;
+  if (!bOneInstance && pOccurNode) {
+    std::tie(iMin, iMax, iInit) =
+        static_cast<CXFA_Occur*>(pOccurNode)->GetOccurInfo();
+  }
+
+  XFA_AttributeValue eRelation =
+      eType == XFA_Element::SubformSet
+          ? pTemplateNode->JSObject()->GetEnum(XFA_Attribute::Relation)
+          : XFA_AttributeValue::Ordered;
+  int32_t iCurRepeatIndex = 0;
+  XFA_AttributeValue eParentBindMatch = XFA_AttributeValue::None;
+  if (bDataMerge) {
+    CXFA_NodeIteratorTemplate<CXFA_Node, CXFA_TraverseStrategy_XFAContainerNode>
+        sNodeIterator(pTemplateNode);
+    bool bAccessedDataDOM = false;
+    if (eType == XFA_Element::SubformSet || eType == XFA_Element::Area) {
+      sNodeIterator.MoveToNext();
+    } else {
+      std::map<CXFA_Node*, CXFA_Node*> subformMapArray;
+      std::vector<CXFA_Node*> nodeArray;
+      for (; iMax < 0 || iCurRepeatIndex < iMax; iCurRepeatIndex++) {
+        bool bSelfMatch = false;
+        XFA_AttributeValue eBindMatch = XFA_AttributeValue::None;
+        CXFA_Node* pDataNode = FindMatchingDataNode(
+            pDocument, pTemplateNode, pDataScope, bAccessedDataDOM, false,
+            &sNodeIterator, bSelfMatch, eBindMatch, true);
+        if (!pDataNode || sNodeIterator.GetCurrent() != pTemplateNode)
+          break;
+
+        eParentBindMatch = eBindMatch;
+        CXFA_Node* pSubformNode = XFA_NodeMerge_CloneOrMergeContainer(
+            pDocument, pFormParentNode, pTemplateNode, false, pSearchArray);
+        if (!pFirstInstance)
+          pFirstInstance = pSubformNode;
+
+        CreateDataBinding(pSubformNode, pDataNode, true);
+        ASSERT(pSubformNode);
+        subformMapArray[pSubformNode] = pDataNode;
+        nodeArray.push_back(pSubformNode);
+      }
+
+      for (CXFA_Node* pSubform : nodeArray) {
+        CXFA_Node* pDataNode = nullptr;
+        auto it = subformMapArray.find(pSubform);
+        if (it != subformMapArray.end())
+          pDataNode = it->second;
+        for (CXFA_Node* pTemplateChild = pTemplateNode->GetFirstChild();
+             pTemplateChild;
+             pTemplateChild = pTemplateChild->GetNextSibling()) {
+          if (XFA_DataMerge_NeedGenerateForm(pTemplateChild,
+                                             bUseInstanceManager)) {
+            XFA_NodeMerge_CloneOrMergeContainer(pDocument, pSubform,
+                                                pTemplateChild, true, nullptr);
+          } else if (pTemplateChild->IsContainerNode()) {
+            pDocument->DataMerge_CopyContainer(pTemplateChild, pSubform,
+                                               pDataNode, false, true, false);
+          }
+        }
+      }
+      subformMapArray.clear();
+    }
+
+    for (; iMax < 0 || iCurRepeatIndex < iMax; iCurRepeatIndex++) {
+      bool bSelfMatch = false;
+      XFA_AttributeValue eBindMatch = XFA_AttributeValue::None;
+      if (!FindMatchingDataNode(pDocument, pTemplateNode, pDataScope,
+                                bAccessedDataDOM, false, &sNodeIterator,
+                                bSelfMatch, eBindMatch, true)) {
+        break;
+      }
+      if (eBindMatch == XFA_AttributeValue::DataRef &&
+          eParentBindMatch == XFA_AttributeValue::DataRef) {
+        break;
+      }
+
+      if (eRelation == XFA_AttributeValue::Choice ||
+          eRelation == XFA_AttributeValue::Unordered) {
+        CXFA_Node* pSubformSetNode = XFA_NodeMerge_CloneOrMergeContainer(
+            pDocument, pFormParentNode, pTemplateNode, false, pSearchArray);
+        ASSERT(pSubformSetNode);
+        if (!pFirstInstance)
+          pFirstInstance = pSubformSetNode;
+
+        std::vector<RecurseRecord> rgItemMatchList;
+        std::vector<CXFA_Node*> rgItemUnmatchList;
+        for (CXFA_Node* pTemplateChild = pTemplateNode->GetFirstChild();
+             pTemplateChild;
+             pTemplateChild = pTemplateChild->GetNextSibling()) {
+          if (XFA_DataMerge_NeedGenerateForm(pTemplateChild,
+                                             bUseInstanceManager)) {
+            XFA_NodeMerge_CloneOrMergeContainer(pDocument, pSubformSetNode,
+                                                pTemplateChild, true, nullptr);
+          } else if (pTemplateChild->IsContainerNode()) {
+            bSelfMatch = false;
+            eBindMatch = XFA_AttributeValue::None;
+            if (eRelation != XFA_AttributeValue::Ordered) {
+              CXFA_NodeIteratorTemplate<CXFA_Node,
+                                        CXFA_TraverseStrategy_XFAContainerNode>
+                  sChildIter(pTemplateChild);
+              CXFA_Node* pDataMatch = FindMatchingDataNode(
+                  pDocument, pTemplateChild, pDataScope, bAccessedDataDOM,
+                  false, &sChildIter, bSelfMatch, eBindMatch, true);
+              if (pDataMatch) {
+                RecurseRecord sNewRecord = {pTemplateChild, pDataMatch};
+                if (bSelfMatch)
+                  rgItemMatchList.insert(rgItemMatchList.begin(), sNewRecord);
+                else
+                  rgItemMatchList.push_back(sNewRecord);
+              } else {
+                rgItemUnmatchList.push_back(pTemplateChild);
+              }
+            } else {
+              rgItemUnmatchList.push_back(pTemplateChild);
+            }
+          }
+        }
+
+        switch (eRelation) {
+          case XFA_AttributeValue::Choice: {
+            ASSERT(!rgItemMatchList.empty());
+            SortRecurseRecord(&rgItemMatchList, pDataScope, true);
+            pDocument->DataMerge_CopyContainer(
+                rgItemMatchList.front().pTemplateChild, pSubformSetNode,
+                pDataScope, false, true, true);
+            break;
+          }
+          case XFA_AttributeValue::Unordered: {
+            if (!rgItemMatchList.empty()) {
+              SortRecurseRecord(&rgItemMatchList, pDataScope, false);
+              for (const auto& matched : rgItemMatchList) {
+                pDocument->DataMerge_CopyContainer(matched.pTemplateChild,
+                                                   pSubformSetNode, pDataScope,
+                                                   false, true, true);
+              }
+            }
+            for (auto* unmatched : rgItemUnmatchList) {
+              pDocument->DataMerge_CopyContainer(unmatched, pSubformSetNode,
+                                                 pDataScope, false, true, true);
+            }
+            break;
+          }
+          default:
+            break;
+        }
+      } else {
+        CXFA_Node* pSubformSetNode = XFA_NodeMerge_CloneOrMergeContainer(
+            pDocument, pFormParentNode, pTemplateNode, false, pSearchArray);
+        ASSERT(pSubformSetNode);
+        if (!pFirstInstance)
+          pFirstInstance = pSubformSetNode;
+
+        for (CXFA_Node* pTemplateChild = pTemplateNode->GetFirstChild();
+             pTemplateChild;
+             pTemplateChild = pTemplateChild->GetNextSibling()) {
+          if (XFA_DataMerge_NeedGenerateForm(pTemplateChild,
+                                             bUseInstanceManager)) {
+            XFA_NodeMerge_CloneOrMergeContainer(pDocument, pSubformSetNode,
+                                                pTemplateChild, true, nullptr);
+          } else if (pTemplateChild->IsContainerNode()) {
+            pDocument->DataMerge_CopyContainer(pTemplateChild, pSubformSetNode,
+                                               pDataScope, false, true, true);
+          }
+        }
+      }
+    }
+
+    if (iCurRepeatIndex == 0 && !bAccessedDataDOM) {
+      int32_t iLimit = iMax;
+      if (pInstMgrNode && pTemplateNode->GetNameHash() == 0) {
+        iLimit = pdfium::CollectionSize<int32_t>(subformArray);
+        if (iLimit < iMin)
+          iLimit = iInit;
+      }
+
+      for (; (iLimit < 0 || iCurRepeatIndex < iLimit); iCurRepeatIndex++) {
+        if (pInstMgrNode) {
+          if (pSearchArray && pSearchArray->empty()) {
+            if (pTemplateNode->GetNameHash() != 0)
+              break;
+            pSearchArray = nullptr;
+          }
+        } else if (!XFA_DataMerge_FindFormDOMInstance(
+                       pDocument, pTemplateNode->GetElementType(),
+                       pTemplateNode->GetNameHash(), pFormParentNode)) {
+          break;
+        }
+        CXFA_Node* pSubformNode = XFA_NodeMerge_CloneOrMergeContainer(
+            pDocument, pFormParentNode, pTemplateNode, false, pSearchArray);
+        ASSERT(pSubformNode);
+        if (!pFirstInstance)
+          pFirstInstance = pSubformNode;
+
+        for (CXFA_Node* pTemplateChild = pTemplateNode->GetFirstChild();
+             pTemplateChild;
+             pTemplateChild = pTemplateChild->GetNextSibling()) {
+          if (XFA_DataMerge_NeedGenerateForm(pTemplateChild,
+                                             bUseInstanceManager)) {
+            XFA_NodeMerge_CloneOrMergeContainer(pDocument, pSubformNode,
+                                                pTemplateChild, true, nullptr);
+          } else if (pTemplateChild->IsContainerNode()) {
+            pDocument->DataMerge_CopyContainer(pTemplateChild, pSubformNode,
+                                               pDataScope, false, true, true);
+          }
+        }
+      }
+    }
+  }
+
+  int32_t iMinimalLimit = iCurRepeatIndex == 0 ? iInit : iMin;
+  for (; iCurRepeatIndex < iMinimalLimit; iCurRepeatIndex++) {
+    CXFA_Node* pSubformSetNode = XFA_NodeMerge_CloneOrMergeContainer(
+        pDocument, pFormParentNode, pTemplateNode, false, pSearchArray);
+    ASSERT(pSubformSetNode);
+    if (!pFirstInstance)
+      pFirstInstance = pSubformSetNode;
+
+    bool bFound = false;
+    for (CXFA_Node* pTemplateChild = pTemplateNode->GetFirstChild();
+         pTemplateChild; pTemplateChild = pTemplateChild->GetNextSibling()) {
+      if (XFA_DataMerge_NeedGenerateForm(pTemplateChild, bUseInstanceManager)) {
+        XFA_NodeMerge_CloneOrMergeContainer(pDocument, pSubformSetNode,
+                                            pTemplateChild, true, nullptr);
+      } else if (pTemplateChild->IsContainerNode()) {
+        if (bFound && eRelation == XFA_AttributeValue::Choice)
+          continue;
+
+        pDocument->DataMerge_CopyContainer(pTemplateChild, pSubformSetNode,
+                                           pDataScope, false, bDataMerge, true);
+        bFound = true;
+      }
+    }
+  }
+  return pFirstInstance;
+}
+
+void UpdateBindingRelations(CXFA_Document* pDocument,
+                            CXFA_Node* pFormNode,
+                            CXFA_Node* pDataScope,
+                            bool bDataRef,
+                            bool bParentDataRef) {
+  bool bMatchRef = true;
+  XFA_Element eType = pFormNode->GetElementType();
+  CXFA_Node* pDataNode = pFormNode->GetBindData();
+  if (eType == XFA_Element::Subform || eType == XFA_Element::ExclGroup ||
+      eType == XFA_Element::Field) {
+    CXFA_Node* pTemplateNode = pFormNode->GetTemplateNodeIfExists();
+    CXFA_Bind* pTemplateNodeBind =
+        pTemplateNode
+            ? pTemplateNode->GetFirstChildByClass<CXFA_Bind>(XFA_Element::Bind)
+            : nullptr;
+    XFA_AttributeValue eMatch =
+        pTemplateNodeBind
+            ? pTemplateNodeBind->JSObject()->GetEnum(XFA_Attribute::Match)
+            : XFA_AttributeValue::Once;
+    switch (eMatch) {
+      case XFA_AttributeValue::None:
+        if (!bDataRef || bParentDataRef)
+          FormValueNode_MatchNoneCreateChild(pFormNode);
+        break;
+      case XFA_AttributeValue::Once:
+        if (!bDataRef || bParentDataRef) {
+          if (!pDataNode) {
+            if (pFormNode->GetNameHash() != 0 &&
+                pFormNode->JSObject()->GetEnum(XFA_Attribute::Scope) !=
+                    XFA_AttributeValue::None) {
+              XFA_Element eDataNodeType = (eType == XFA_Element::Subform ||
+                                           XFA_FieldIsMultiListBox(pFormNode))
+                                              ? XFA_Element::DataGroup
+                                              : XFA_Element::DataValue;
+              pDataNode = MaybeCreateDataNode(
+                  pDocument, pDataScope, eDataNodeType,
+                  WideString(
+                      pFormNode->JSObject()->GetCData(XFA_Attribute::Name)));
+              if (pDataNode)
+                CreateDataBinding(pFormNode, pDataNode, false);
+            }
+            if (!pDataNode)
+              FormValueNode_MatchNoneCreateChild(pFormNode);
+
+          } else {
+            CXFA_Node* pDataParent = pDataNode->GetParent();
+            if (pDataParent != pDataScope) {
+              ASSERT(pDataParent);
+              pDataParent->RemoveChildAndNotify(pDataNode, true);
+              pDataScope->InsertChildAndNotify(pDataNode, nullptr);
+            }
+          }
+        }
+        break;
+      case XFA_AttributeValue::Global:
+        if (!bDataRef || bParentDataRef) {
+          uint32_t dwNameHash = pFormNode->GetNameHash();
+          if (dwNameHash != 0 && !pDataNode) {
+            pDataNode = pDocument->GetGlobalBinding(dwNameHash);
+            if (!pDataNode) {
+              XFA_Element eDataNodeType = (eType == XFA_Element::Subform ||
+                                           XFA_FieldIsMultiListBox(pFormNode))
+                                              ? XFA_Element::DataGroup
+                                              : XFA_Element::DataValue;
+              CXFA_Node* pRecordNode =
+                  ToNode(pDocument->GetXFAObject(XFA_HASHCODE_Record));
+              pDataNode = MaybeCreateDataNode(
+                  pDocument, pRecordNode, eDataNodeType,
+                  WideString(
+                      pFormNode->JSObject()->GetCData(XFA_Attribute::Name)));
+              if (pDataNode) {
+                CreateDataBinding(pFormNode, pDataNode, false);
+                pDocument->RegisterGlobalBinding(pFormNode->GetNameHash(),
+                                                 pDataNode);
+              }
+            } else {
+              CreateDataBinding(pFormNode, pDataNode, true);
+            }
+          }
+          if (!pDataNode)
+            FormValueNode_MatchNoneCreateChild(pFormNode);
+        }
+        break;
+      case XFA_AttributeValue::DataRef: {
+        bMatchRef = bDataRef;
+        bParentDataRef = true;
+        if (!pDataNode && bDataRef) {
+          WideString wsRef =
+              pTemplateNodeBind
+                  ? pTemplateNodeBind->JSObject()->GetCData(XFA_Attribute::Ref)
+                  : WideString();
+          uint32_t dFlags =
+              XFA_RESOLVENODE_Children | XFA_RESOLVENODE_CreateNode;
+          XFA_RESOLVENODE_RS rs;
+          pDocument->GetScriptContext()->ResolveObjects(
+              pDataScope, wsRef.AsStringView(), &rs, dFlags, pTemplateNode);
+          CXFA_Object* pObject =
+              !rs.objects.empty() ? rs.objects.front().Get() : nullptr;
+          pDataNode = ToNode(pObject);
+          if (pDataNode) {
+            CreateDataBinding(pFormNode, pDataNode,
+                              rs.dwFlags == XFA_ResolveNode_RSType_ExistNodes);
+          } else {
+            FormValueNode_MatchNoneCreateChild(pFormNode);
+          }
+        }
+        break;
+      }
+      default:
+        break;
+    }
+  }
+
+  if (bMatchRef &&
+      (eType == XFA_Element::Subform || eType == XFA_Element::SubformSet ||
+       eType == XFA_Element::Area || eType == XFA_Element::PageArea ||
+       eType == XFA_Element::PageSet)) {
+    for (CXFA_Node* pFormChild = pFormNode->GetFirstChild(); pFormChild;
+         pFormChild = pFormChild->GetNextSibling()) {
+      if (!pFormChild->IsContainerNode())
+        continue;
+      if (pFormChild->IsUnusedNode())
+        continue;
+
+      UpdateBindingRelations(pDocument, pFormChild,
+                             pDataNode ? pDataNode : pDataScope, bDataRef,
+                             bParentDataRef);
+    }
+  }
+}
+
+void UpdateDataRelation(CXFA_Node* pDataNode, CXFA_Node* pDataDescriptionNode) {
+  ASSERT(pDataDescriptionNode);
+  for (CXFA_Node* pDataChild = pDataNode->GetFirstChild(); pDataChild;
+       pDataChild = pDataChild->GetNextSibling()) {
+    uint32_t dwNameHash = pDataChild->GetNameHash();
+    if (!dwNameHash)
+      continue;
+
+    CXFA_NodeIteratorTemplate<CXFA_Node, CXFA_TraverseStrategy_DDGroup>
+        sIterator(pDataDescriptionNode);
+    for (CXFA_Node* pDDGroupNode = sIterator.GetCurrent(); pDDGroupNode;
+         pDDGroupNode = sIterator.MoveToNext()) {
+      if (pDDGroupNode != pDataDescriptionNode) {
+        if (pDDGroupNode->GetElementType() != XFA_Element::DataGroup)
+          continue;
+
+        Optional<WideString> ns = pDDGroupNode->JSObject()->TryNamespace();
+        if (!ns.has_value() ||
+            !ns.value().EqualsASCII("http://ns.adobe.com/data-description/")) {
+          continue;
+        }
+      }
+
+      CXFA_Node* pDDNode = pDDGroupNode->GetFirstChildByName(dwNameHash);
+      if (!pDDNode)
+        continue;
+      if (pDDNode->GetElementType() != pDataChild->GetElementType())
+        break;
+
+      pDataChild->SetDataDescriptionNode(pDDNode);
+      UpdateDataRelation(pDataChild, pDDNode);
+      break;
+    }
+  }
+}
+
 }  // namespace
 
-CXFA_Document::CXFA_Document(CXFA_DocumentParser* pParser)
-    : m_pParser(pParser),
-      m_pRootNode(nullptr),
-      m_eCurVersionMode(XFA_VERSION_DEFAULT),
-      m_dwDocFlags(0) {
-  ASSERT(m_pParser);
+CXFA_Document::CXFA_Document(CXFA_FFNotify* notify,
+                             std::unique_ptr<LayoutProcessorIface> pLayout)
+    : CXFA_NodeOwner(),
+      notify_(notify),
+      m_pLayoutProcessor(std::move(pLayout)) {
+  if (m_pLayoutProcessor)
+    m_pLayoutProcessor->SetDocument(this);
 }
 
-CXFA_Document::~CXFA_Document() {
-  // Remove all the bindings before freeing the node as the ownership is wonky.
-  if (m_pRootNode)
-    m_pRootNode->ReleaseBindingNodes();
-
-  delete m_pRootNode;
-
-  for (CXFA_Node* pNode : m_PurgeNodes)
-    delete pNode;
-  m_PurgeNodes.clear();
-}
-
-CXFA_LayoutProcessor* CXFA_Document::GetLayoutProcessor() {
-  if (!m_pLayoutProcessor)
-    m_pLayoutProcessor = pdfium::MakeUnique<CXFA_LayoutProcessor>(this);
-  return m_pLayoutProcessor.get();
-}
-
-CXFA_LayoutProcessor* CXFA_Document::GetDocLayout() {
-  return GetLayoutProcessor();
-}
+CXFA_Document::~CXFA_Document() = default;
 
 void CXFA_Document::ClearLayoutData() {
   m_pLayoutProcessor.reset();
   m_pScriptContext.reset();
-  m_pLocalMgr.reset();
+  m_pLocaleMgr.reset();
   m_pScriptDataWindow.reset();
   m_pScriptEvent.reset();
   m_pScriptHost.reset();
@@ -128,22 +1296,6 @@
   m_pScriptSignature.reset();
 }
 
-void CXFA_Document::SetRoot(CXFA_Node* pNewRoot) {
-  if (m_pRootNode)
-    AddPurgeNode(m_pRootNode);
-
-  m_pRootNode = pNewRoot;
-  RemovePurgeNode(pNewRoot);
-}
-
-CFX_XMLDoc* CXFA_Document::GetXMLDoc() const {
-  return m_pParser->GetXMLDoc();
-}
-
-CXFA_FFNotify* CXFA_Document::GetNotify() const {
-  return m_pParser->GetNotify();
-}
-
 CXFA_Object* CXFA_Document::GetXFAObject(XFA_HashCode dwNodeNameHash) {
   switch (dwNodeNameHash) {
     case XFA_HASHCODE_Data: {
@@ -221,34 +1373,12 @@
                                      XFA_Element eElement) {
   if (eElement == XFA_Element::Unknown)
     return nullptr;
-
-  std::unique_ptr<CXFA_Node> pNode = CXFA_Node::Create(this, eElement, packet);
-  if (!pNode)
-    return nullptr;
-
-  // TODO(dsinclair): AddPrugeNode should take ownership of the pointer.
-  AddPurgeNode(pNode.get());
-  return pNode.release();
-}
-
-void CXFA_Document::AddPurgeNode(CXFA_Node* pNode) {
-  m_PurgeNodes.insert(pNode);
-}
-
-bool CXFA_Document::RemovePurgeNode(CXFA_Node* pNode) {
-  return !!m_PurgeNodes.erase(pNode);
-}
-
-void CXFA_Document::SetFlag(uint32_t dwFlag, bool bOn) {
-  if (bOn)
-    m_dwDocFlags |= dwFlag;
-  else
-    m_dwDocFlags &= ~dwFlag;
+  return AddOwnedNode(CXFA_Node::Create(this, eElement, packet));
 }
 
 bool CXFA_Document::IsInteractive() {
-  if (m_dwDocFlags & XFA_DOCFLAG_HasInteractive)
-    return !!(m_dwDocFlags & XFA_DOCFLAG_Interactive);
+  if (m_Interactive.has_value())
+    return m_Interactive.value();
 
   CXFA_Node* pConfig = ToNode(GetXFAObject(XFA_HASHCODE_Config));
   if (!pConfig)
@@ -265,36 +1395,31 @@
 
   CXFA_Interactive* pFormFiller =
       pPDF->GetChild<CXFA_Interactive>(0, XFA_Element::Interactive, false);
-  if (pFormFiller) {
-    m_dwDocFlags |= XFA_DOCFLAG_HasInteractive;
+  if (!pFormFiller)
+    return false;
 
-    WideString wsInteractive = pFormFiller->JSObject()->GetContent(false);
-    if (wsInteractive == L"1") {
-      m_dwDocFlags |= XFA_DOCFLAG_Interactive;
-      return true;
-    }
-  }
-  return false;
+  WideString wsInteractive = pFormFiller->JSObject()->GetContent(false);
+  bool bInteractive = wsInteractive.EqualsASCII("1");
+  m_Interactive = bInteractive;
+  return bInteractive;
 }
 
-CXFA_LocaleMgr* CXFA_Document::GetLocalMgr() {
-  if (!m_pLocalMgr) {
-    m_pLocalMgr = pdfium::MakeUnique<CXFA_LocaleMgr>(
+CXFA_LocaleMgr* CXFA_Document::GetLocaleMgr() {
+  if (!m_pLocaleMgr) {
+    m_pLocaleMgr = pdfium::MakeUnique<CXFA_LocaleMgr>(
         ToNode(GetXFAObject(XFA_HASHCODE_LocaleSet)),
         GetNotify()->GetAppProvider()->GetLanguage());
   }
-  return m_pLocalMgr.get();
+  return m_pLocaleMgr.get();
 }
 
-CFXJSE_Engine* CXFA_Document::InitScriptContext(v8::Isolate* pIsolate) {
+CFXJSE_Engine* CXFA_Document::InitScriptContext(CJS_Runtime* fxjs_runtime) {
   ASSERT(!m_pScriptContext);
-  m_pScriptContext = pdfium::MakeUnique<CFXJSE_Engine>(this, pIsolate);
+  m_pScriptContext = pdfium::MakeUnique<CFXJSE_Engine>(this, fxjs_runtime);
   return m_pScriptContext.get();
 }
 
-// We have to call |InitScriptContext| before any calls to |GetScriptContext|
-// or the context won't have an isolate set into it.
-CFXJSE_Engine* CXFA_Document::GetScriptContext() {
+CFXJSE_Engine* CXFA_Document::GetScriptContext() const {
   ASSERT(m_pScriptContext);
   return m_pScriptContext.get();
 }
@@ -302,21 +1427,24 @@
 XFA_VERSION CXFA_Document::RecognizeXFAVersionNumber(
     const WideString& wsTemplateNS) {
   WideStringView wsTemplateURIPrefix(kTemplateNS);
-  size_t nPrefixLength = wsTemplateURIPrefix.GetLength();
-  if (WideStringView(wsTemplateNS.c_str(), wsTemplateNS.GetLength()) !=
-      wsTemplateURIPrefix) {
+  if (wsTemplateNS.GetLength() <= wsTemplateURIPrefix.GetLength())
     return XFA_VERSION_UNKNOWN;
-  }
-  auto nDotPos = wsTemplateNS.Find('.', nPrefixLength);
+
+  size_t prefixLength = wsTemplateURIPrefix.GetLength();
+  if (WideStringView(wsTemplateNS.c_str(), prefixLength) != wsTemplateURIPrefix)
+    return XFA_VERSION_UNKNOWN;
+
+  auto nDotPos = wsTemplateNS.Find('.', prefixLength);
   if (!nDotPos.has_value())
     return XFA_VERSION_UNKNOWN;
 
   int8_t iMajor = FXSYS_wtoi(
-      wsTemplateNS.Mid(nPrefixLength, nDotPos.value() - nPrefixLength).c_str());
+      wsTemplateNS.Substr(prefixLength, nDotPos.value() - prefixLength)
+          .c_str());
   int8_t iMinor =
       FXSYS_wtoi(wsTemplateNS
-                     .Mid(nDotPos.value() + 1,
-                          wsTemplateNS.GetLength() - nDotPos.value() - 2)
+                     .Substr(nDotPos.value() + 1,
+                             wsTemplateNS.GetLength() - nDotPos.value() - 2)
                      .c_str());
   XFA_VERSION eVersion = (XFA_VERSION)((int32_t)iMajor * 100 + iMinor);
   if (eVersion < XFA_VERSION_MIN || eVersion > XFA_VERSION_MAX)
@@ -326,8 +1454,12 @@
   return eVersion;
 }
 
+FormType CXFA_Document::GetFormType() const {
+  return GetNotify()->GetHDOC()->GetFormType();
+}
+
 CXFA_Node* CXFA_Document::GetNodeByID(CXFA_Node* pRoot,
-                                      const WideStringView& wsID) {
+                                      WideStringView wsID) const {
   if (!pRoot || wsID.IsEmpty())
     return nullptr;
 
@@ -366,12 +1498,13 @@
   }
 
   for (CXFA_Node* pUseHrefNode : sUseNodes) {
+    // Must outlive the WideStringViews below.
+    WideString wsUseVal =
+        pUseHrefNode->JSObject()->GetCData(XFA_Attribute::Usehref);
     WideStringView wsURI;
     WideStringView wsID;
     WideStringView wsSOM;
 
-    WideString wsUseVal =
-        pUseHrefNode->JSObject()->GetCData(XFA_Attribute::Usehref);
     if (!wsUseVal.IsEmpty()) {
       auto uSharpPos = wsUseVal.Find('#');
       if (!uSharpPos.has_value()) {
@@ -399,8 +1532,7 @@
           wsSOM = WideStringView(wsUseVal.c_str(), wsUseVal.GetLength());
       }
     }
-
-    if (!wsURI.IsEmpty() && wsURI != L".")
+    if (!wsURI.IsEmpty() && !wsURI.EqualsASCII("."))
       continue;
 
     CXFA_Node* pProtoNode = nullptr;
@@ -409,10 +1541,12 @@
                         XFA_RESOLVENODE_Properties | XFA_RESOLVENODE_Parent |
                         XFA_RESOLVENODE_Siblings;
       XFA_RESOLVENODE_RS resolveNodeRS;
-      int32_t iRet = m_pScriptContext->ResolveObjects(
-          pUseHrefNode, wsSOM, &resolveNodeRS, dwFlag, nullptr);
-      if (iRet > 0 && resolveNodeRS.objects.front()->IsNode())
-        pProtoNode = resolveNodeRS.objects.front()->AsNode();
+      if (m_pScriptContext->ResolveObjects(pUseHrefNode, wsSOM, &resolveNodeRS,
+                                           dwFlag, nullptr)) {
+        auto* pFirstObject = resolveNodeRS.objects.front().Get();
+        if (pFirstObject && pFirstObject->IsNode())
+          pProtoNode = pFirstObject->AsNode();
+      }
     } else if (!wsID.IsEmpty()) {
       auto it = mIDMap.find(FX_HashCode_GetW(wsID, false));
       if (it == mIDMap.end())
@@ -422,6 +1556,275 @@
     if (!pProtoNode)
       continue;
 
-    MergeNode(this, pUseHrefNode, pProtoNode);
+    MergeNode(pUseHrefNode, pProtoNode);
   }
 }
+
+CXFA_Node* CXFA_Document::DataMerge_CopyContainer(CXFA_Node* pTemplateNode,
+                                                  CXFA_Node* pFormNode,
+                                                  CXFA_Node* pDataScope,
+                                                  bool bOneInstance,
+                                                  bool bDataMerge,
+                                                  bool bUpLevel) {
+  ASSERT(pTemplateNode->IsContainerNode());
+  switch (pTemplateNode->GetElementType()) {
+    case XFA_Element::Area:
+    case XFA_Element::PageArea:
+    case XFA_Element::Subform:
+    case XFA_Element::SubformSet:
+      return CopyContainer_SubformSet(this, pTemplateNode, pFormNode,
+                                      pDataScope, bOneInstance, bDataMerge);
+    case XFA_Element::ContentArea:
+    case XFA_Element::Draw:
+    case XFA_Element::ExclGroup:
+    case XFA_Element::Field:
+      return CopyContainer_Field(this, pTemplateNode, pFormNode, pDataScope,
+                                 bDataMerge, bUpLevel);
+    case XFA_Element::PageSet:
+    case XFA_Element::Variables:
+      return nullptr;
+    default:
+      NOTREACHED();
+      return nullptr;
+  }
+}
+
+void CXFA_Document::DataMerge_UpdateBindingRelations(
+    CXFA_Node* pFormUpdateRoot) {
+  CXFA_Node* pDataScope =
+      XFA_DataMerge_FindDataScope(pFormUpdateRoot->GetParent());
+  if (!pDataScope)
+    return;
+
+  UpdateBindingRelations(this, pFormUpdateRoot, pDataScope, false, false);
+  UpdateBindingRelations(this, pFormUpdateRoot, pDataScope, true, false);
+}
+
+CXFA_Node* CXFA_Document::GetNotBindNode(
+    const std::vector<UnownedPtr<CXFA_Object>>& arrayObjects) const {
+  for (auto& pObject : arrayObjects) {
+    CXFA_Node* pNode = pObject->AsNode();
+    if (pNode && !pNode->HasBindItem())
+      return pNode;
+  }
+  return nullptr;
+}
+
+void CXFA_Document::DoDataMerge() {
+  CXFA_Node* pDatasetsRoot = ToNode(GetXFAObject(XFA_HASHCODE_Datasets));
+  if (!pDatasetsRoot) {
+    // Ownership will be passed in the AppendChild below to the XML tree.
+    auto* pDatasetsXMLNode =
+        notify_->GetHDOC()->GetXMLDocument()->CreateNode<CFX_XMLElement>(
+            L"xfa:datasets");
+    pDatasetsXMLNode->SetAttribute(L"xmlns:xfa",
+                                   L"http://www.xfa.org/schema/xfa-data/1.0/");
+    pDatasetsRoot =
+        CreateNode(XFA_PacketType::Datasets, XFA_Element::DataModel);
+    pDatasetsRoot->JSObject()->SetCData(XFA_Attribute::Name, L"datasets", false,
+                                        false);
+
+    m_pRootNode->GetXMLMappingNode()->AppendLastChild(pDatasetsXMLNode);
+    m_pRootNode->InsertChildAndNotify(pDatasetsRoot, nullptr);
+    pDatasetsRoot->SetXMLMappingNode(pDatasetsXMLNode);
+  }
+
+  CXFA_Node* pDataRoot = nullptr;
+  CXFA_Node* pDDRoot = nullptr;
+  WideString wsDatasetsURI =
+      pDatasetsRoot->JSObject()->TryNamespace().value_or(WideString());
+  for (CXFA_Node* pChildNode = pDatasetsRoot->GetFirstChild(); pChildNode;
+       pChildNode = pChildNode->GetNextSibling()) {
+    if (pChildNode->GetElementType() != XFA_Element::DataGroup)
+      continue;
+
+    if (!pDDRoot && pChildNode->GetNameHash() == XFA_HASHCODE_DataDescription) {
+      Optional<WideString> namespaceURI =
+          pChildNode->JSObject()->TryNamespace();
+      if (!namespaceURI.has_value())
+        continue;
+      if (namespaceURI.value().EqualsASCII(
+              "http://ns.adobe.com/data-description/")) {
+        pDDRoot = pChildNode;
+      }
+    } else if (!pDataRoot && pChildNode->GetNameHash() == XFA_HASHCODE_Data) {
+      Optional<WideString> namespaceURI =
+          pChildNode->JSObject()->TryNamespace();
+      if (!namespaceURI)
+        continue;
+      if (*namespaceURI == wsDatasetsURI)
+        pDataRoot = pChildNode;
+    }
+    if (pDataRoot && pDDRoot)
+      break;
+  }
+
+  if (!pDataRoot) {
+    pDataRoot = CreateNode(XFA_PacketType::Datasets, XFA_Element::DataGroup);
+    pDataRoot->JSObject()->SetCData(XFA_Attribute::Name, L"data", false, false);
+
+    auto* elem =
+        notify_->GetHDOC()->GetXMLDocument()->CreateNode<CFX_XMLElement>(
+            L"xfa:data");
+    pDataRoot->SetXMLMappingNode(elem);
+    pDatasetsRoot->InsertChildAndNotify(pDataRoot, nullptr);
+  }
+
+  CXFA_DataGroup* pDataTopLevel =
+      pDataRoot->GetFirstChildByClass<CXFA_DataGroup>(XFA_Element::DataGroup);
+  uint32_t dwNameHash = pDataTopLevel ? pDataTopLevel->GetNameHash() : 0;
+  CXFA_Template* pTemplateRoot =
+      m_pRootNode->GetFirstChildByClass<CXFA_Template>(XFA_Element::Template);
+  if (!pTemplateRoot)
+    return;
+
+  CXFA_Node* pTemplateChosen =
+      dwNameHash != 0 ? pTemplateRoot->GetFirstChildByName(dwNameHash)
+                      : nullptr;
+  if (!pTemplateChosen ||
+      pTemplateChosen->GetElementType() != XFA_Element::Subform) {
+    pTemplateChosen =
+        pTemplateRoot->GetFirstChildByClass<CXFA_Subform>(XFA_Element::Subform);
+  }
+  if (!pTemplateChosen)
+    return;
+
+  CXFA_Form* pFormRoot =
+      m_pRootNode->GetFirstChildByClass<CXFA_Form>(XFA_Element::Form);
+  bool bEmptyForm = false;
+  if (!pFormRoot) {
+    bEmptyForm = true;
+    pFormRoot = static_cast<CXFA_Form*>(
+        CreateNode(XFA_PacketType::Form, XFA_Element::Form));
+    ASSERT(pFormRoot);
+    pFormRoot->JSObject()->SetCData(XFA_Attribute::Name, L"form", false, false);
+    m_pRootNode->InsertChildAndNotify(pFormRoot, nullptr);
+  } else {
+    CXFA_NodeIteratorTemplate<CXFA_Node, CXFA_TraverseStrategy_XFANode>
+        sIterator(pFormRoot);
+    for (CXFA_Node* pNode = sIterator.MoveToNext(); pNode;
+         pNode = sIterator.MoveToNext()) {
+      pNode->SetFlag(XFA_NodeFlag_UnusedNode);
+    }
+  }
+
+  CXFA_Node* pSubformSetNode = XFA_NodeMerge_CloneOrMergeContainer(
+      this, pFormRoot, pTemplateChosen, false, nullptr);
+  ASSERT(pSubformSetNode);
+  if (!pDataTopLevel) {
+    WideString wsFormName =
+        pSubformSetNode->JSObject()->GetCData(XFA_Attribute::Name);
+    WideString wsDataTopLevelName(wsFormName.IsEmpty() ? L"form" : wsFormName);
+
+    pDataTopLevel = static_cast<CXFA_DataGroup*>(
+        CreateNode(XFA_PacketType::Datasets, XFA_Element::DataGroup));
+    pDataTopLevel->JSObject()->SetCData(XFA_Attribute::Name, wsDataTopLevelName,
+                                        false, false);
+
+    auto* elem =
+        notify_->GetHDOC()->GetXMLDocument()->CreateNode<CFX_XMLElement>(
+            wsDataTopLevelName);
+    pDataTopLevel->SetXMLMappingNode(elem);
+
+    CXFA_Node* pBeforeNode = pDataRoot->GetFirstChild();
+    pDataRoot->InsertChildAndNotify(pDataTopLevel, pBeforeNode);
+  }
+
+  ASSERT(pDataTopLevel);
+  CreateDataBinding(pSubformSetNode, pDataTopLevel, true);
+  for (CXFA_Node* pTemplateChild = pTemplateChosen->GetFirstChild();
+       pTemplateChild; pTemplateChild = pTemplateChild->GetNextSibling()) {
+    if (XFA_DataMerge_NeedGenerateForm(pTemplateChild, true)) {
+      XFA_NodeMerge_CloneOrMergeContainer(this, pSubformSetNode, pTemplateChild,
+                                          true, nullptr);
+    } else if (pTemplateChild->IsContainerNode()) {
+      DataMerge_CopyContainer(pTemplateChild, pSubformSetNode, pDataTopLevel,
+                              false, true, true);
+    }
+  }
+  if (pDDRoot)
+    UpdateDataRelation(pDataRoot, pDDRoot);
+
+  DataMerge_UpdateBindingRelations(pSubformSetNode);
+  CXFA_PageSet* pPageSetNode =
+      pSubformSetNode->GetFirstChildByClass<CXFA_PageSet>(XFA_Element::PageSet);
+  while (pPageSetNode) {
+    m_pPendingPageSet.push_back(pPageSetNode);
+    CXFA_PageSet* pNextPageSetNode =
+        pPageSetNode->GetNextSameClassSibling<CXFA_PageSet>(
+            XFA_Element::PageSet);
+    pSubformSetNode->RemoveChildAndNotify(pPageSetNode, true);
+    pPageSetNode = pNextPageSetNode;
+  }
+
+  if (bEmptyForm)
+    return;
+
+  CXFA_NodeIteratorTemplate<CXFA_Node, CXFA_TraverseStrategy_XFANode> sIterator(
+      pFormRoot);
+  CXFA_Node* pNode = sIterator.MoveToNext();
+  while (pNode) {
+    if (pNode->IsUnusedNode()) {
+      if (pNode->IsContainerNode() ||
+          pNode->GetElementType() == XFA_Element::InstanceManager) {
+        CXFA_Node* pNext = sIterator.SkipChildrenAndMoveToNext();
+        pNode->GetParent()->RemoveChildAndNotify(pNode, true);
+        pNode = pNext;
+      } else {
+        pNode->ClearFlag(XFA_NodeFlag_UnusedNode);
+        pNode->SetFlagAndNotify(XFA_NodeFlag_Initialized);
+        pNode = sIterator.MoveToNext();
+      }
+    } else {
+      pNode->SetFlagAndNotify(XFA_NodeFlag_Initialized);
+      pNode = sIterator.MoveToNext();
+    }
+  }
+}
+
+void CXFA_Document::DoDataRemerge(bool bDoDataMerge) {
+  CXFA_Node* pFormRoot = ToNode(GetXFAObject(XFA_HASHCODE_Form));
+  if (pFormRoot) {
+    while (CXFA_Node* pNode = pFormRoot->GetFirstChild())
+      pFormRoot->RemoveChildAndNotify(pNode, true);
+
+    pFormRoot->SetBindingNode(nullptr);
+  }
+  m_rgGlobalBinding.clear();
+
+  if (bDoDataMerge)
+    DoDataMerge();
+
+  GetLayoutProcessor()->SetForceRelayout(true);
+}
+
+CXFA_Node* CXFA_Document::GetGlobalBinding(uint32_t dwNameHash) {
+  auto it = m_rgGlobalBinding.find(dwNameHash);
+  return it != m_rgGlobalBinding.end() ? it->second : nullptr;
+}
+
+void CXFA_Document::RegisterGlobalBinding(uint32_t dwNameHash,
+                                          CXFA_Node* pDataNode) {
+  m_rgGlobalBinding[dwNameHash] = pDataNode;
+}
+
+void CXFA_Document::SetPendingNodesUnusedAndUnbound() {
+  for (CXFA_Node* pPageNode : m_pPendingPageSet) {
+    CXFA_NodeIterator sIterator(pPageNode);
+    for (CXFA_Node* pNode = sIterator.GetCurrent(); pNode;
+         pNode = sIterator.MoveToNext()) {
+      if (pNode->IsContainerNode()) {
+        CXFA_Node* pBindNode = pNode->GetBindData();
+        if (pBindNode) {
+          pBindNode->RemoveBindItem(pNode);
+          pNode->SetBindingNode(nullptr);
+        }
+      }
+      pNode->SetFlag(XFA_NodeFlag_UnusedNode);
+    }
+  }
+}
+
+CXFA_Document::LayoutProcessorIface::LayoutProcessorIface() = default;
+
+CXFA_Document::LayoutProcessorIface::~LayoutProcessorIface() = default;
diff --git a/xfa/fxfa/parser/cxfa_document.h b/xfa/fxfa/parser/cxfa_document.h
index bd576e6..ea80475 100644
--- a/xfa/fxfa/parser/cxfa_document.h
+++ b/xfa/fxfa/parser/cxfa_document.h
@@ -9,11 +9,13 @@
 
 #include <map>
 #include <memory>
-#include <set>
 #include <vector>
 
+#include "core/fxcrt/unowned_ptr.h"
+#include "third_party/base/optional.h"
 #include "xfa/fxfa/fxfa.h"
 #include "xfa/fxfa/parser/cxfa_localemgr.h"
+#include "xfa/fxfa/parser/cxfa_nodeowner.h"
 
 enum XFA_VERSION {
   XFA_VERSION_UNKNOWN = 0,
@@ -33,59 +35,71 @@
   XFA_VERSION_MAX = 400,
 };
 
-enum XFA_DocFlag {
-  XFA_DOCFLAG_StrictScoping = 0x0001,
-  XFA_DOCFLAG_HasInteractive = 0x0002,
-  XFA_DOCFLAG_Interactive = 0x0004,
-  XFA_DOCFLAG_Scripting = 0x0008
-};
-
-class CFX_XMLDoc;
 class CFXJSE_Engine;
+class CJS_Runtime;
 class CScript_DataWindow;
 class CScript_EventPseudoModel;
 class CScript_HostPseudoModel;
-class CScript_LogPseudoModel;
 class CScript_LayoutPseudoModel;
+class CScript_LogPseudoModel;
 class CScript_SignaturePseudoModel;
-class CXFA_ContainerLayoutItem;
-class CXFA_DocumentParser;
 class CXFA_FFNotify;
-class CXFA_LayoutItem;
-class CXFA_LayoutProcessor;
 class CXFA_Node;
 class CXFA_Object;
 
-class CXFA_Document {
+class CXFA_Document final : public CXFA_NodeOwner {
  public:
-  explicit CXFA_Document(CXFA_DocumentParser* pParser);
-  ~CXFA_Document();
+  class LayoutProcessorIface {
+   public:
+    LayoutProcessorIface();
+    virtual ~LayoutProcessorIface();
+    virtual void SetForceRelayout(bool enable) = 0;
+    virtual void AddChangedContainer(CXFA_Node* pContainer) = 0;
 
-  CFXJSE_Engine* InitScriptContext(v8::Isolate* pIsolate);
+    void SetDocument(CXFA_Document* pDocument) { m_pDocument = pDocument; }
+    CXFA_Document* GetDocument() const { return m_pDocument.Get(); }
+
+   private:
+    UnownedPtr<CXFA_Document> m_pDocument;
+  };
+
+  CXFA_Document(CXFA_FFNotify* notify,
+                std::unique_ptr<LayoutProcessorIface> pLayout);
+  ~CXFA_Document() override;
+
+  bool HasScriptContext() const { return !!m_pScriptContext; }
+  CFXJSE_Engine* InitScriptContext(CJS_Runtime* fxjs_runtime);
+
+  // Only safe to call in situations where the context is known to exist,
+  // and always returns non-NULL in those situations. In other words, we have
+  // to call InitScriptContext() first to avoid a situation where the context
+  // won't have an isolate set into it.
+  CFXJSE_Engine* GetScriptContext() const;
+
+  CXFA_FFNotify* GetNotify() const { return notify_.Get(); }
+  CXFA_LocaleMgr* GetLocaleMgr();
+  CXFA_Object* GetXFAObject(XFA_HashCode wsNodeNameHash);
+  CXFA_Node* GetNodeByID(CXFA_Node* pRoot, WideStringView wsID) const;
+  CXFA_Node* GetNotBindNode(
+      const std::vector<UnownedPtr<CXFA_Object>>& arrayNodes) const;
+
+  LayoutProcessorIface* GetLayoutProcessor() const {
+    return m_pLayoutProcessor.get();
+  }
 
   CXFA_Node* GetRoot() const { return m_pRootNode; }
+  void SetRoot(CXFA_Node* pNewRoot) { m_pRootNode = pNewRoot; }
 
-  CFX_XMLDoc* GetXMLDoc() const;
-  CXFA_FFNotify* GetNotify() const;
-  CXFA_LocaleMgr* GetLocalMgr();
-  CXFA_Object* GetXFAObject(XFA_HashCode wsNodeNameHash);
-  CXFA_Node* GetNodeByID(CXFA_Node* pRoot, const WideStringView& wsID);
-  CXFA_Node* GetNotBindNode(const std::vector<CXFA_Object*>& arrayNodes);
-  CXFA_LayoutProcessor* GetLayoutProcessor();
-  CXFA_LayoutProcessor* GetDocLayout();
-  CFXJSE_Engine* GetScriptContext();
+  bool is_strict_scoping() const { return m_bStrictScoping; }
+  void set_is_strict_scoping() { m_bStrictScoping = true; }
 
-  void SetRoot(CXFA_Node* pNewRoot);
-
-  void AddPurgeNode(CXFA_Node* pNode);
-  bool RemovePurgeNode(CXFA_Node* pNode);
-
-  bool HasFlag(uint32_t dwFlag) { return (m_dwDocFlags & dwFlag) == dwFlag; }
-  void SetFlag(uint32_t dwFlag, bool bOn);
+  bool is_scripting() const { return m_bScripting; }
+  void set_is_scripting() { m_bScripting = true; }
 
   bool IsInteractive();
   XFA_VERSION GetCurVersionMode() { return m_eCurVersionMode; }
   XFA_VERSION RecognizeXFAVersionNumber(const WideString& wsTemplateNS);
+  FormType GetFormType() const;
 
   CXFA_Node* CreateNode(XFA_PacketType packet, XFA_Element eElement);
 
@@ -102,24 +116,29 @@
 
   void ClearLayoutData();
 
-  std::map<uint32_t, CXFA_Node*> m_rgGlobalBinding;
+  CXFA_Node* GetGlobalBinding(uint32_t dwNameHash);
+  void RegisterGlobalBinding(uint32_t dwNameHash, CXFA_Node* pDataNode);
+  void SetPendingNodesUnusedAndUnbound();
+
   std::vector<CXFA_Node*> m_pPendingPageSet;
 
  private:
-  CXFA_DocumentParser* m_pParser;
-  CXFA_Node* m_pRootNode;
+  UnownedPtr<CXFA_FFNotify> const notify_;
+  CXFA_Node* m_pRootNode = nullptr;
+  std::map<uint32_t, CXFA_Node*> m_rgGlobalBinding;
   std::unique_ptr<CFXJSE_Engine> m_pScriptContext;
-  std::unique_ptr<CXFA_LayoutProcessor> m_pLayoutProcessor;
-  std::unique_ptr<CXFA_LocaleMgr> m_pLocalMgr;
+  std::unique_ptr<LayoutProcessorIface> m_pLayoutProcessor;
+  std::unique_ptr<CXFA_LocaleMgr> m_pLocaleMgr;
   std::unique_ptr<CScript_DataWindow> m_pScriptDataWindow;
   std::unique_ptr<CScript_EventPseudoModel> m_pScriptEvent;
   std::unique_ptr<CScript_HostPseudoModel> m_pScriptHost;
   std::unique_ptr<CScript_LogPseudoModel> m_pScriptLog;
   std::unique_ptr<CScript_LayoutPseudoModel> m_pScriptLayout;
   std::unique_ptr<CScript_SignaturePseudoModel> m_pScriptSignature;
-  std::set<CXFA_Node*> m_PurgeNodes;
-  XFA_VERSION m_eCurVersionMode;
-  uint32_t m_dwDocFlags;
+  XFA_VERSION m_eCurVersionMode = XFA_VERSION_DEFAULT;
+  Optional<bool> m_Interactive;
+  bool m_bStrictScoping = false;
+  bool m_bScripting = false;
 };
 
 #endif  // XFA_FXFA_PARSER_CXFA_DOCUMENT_H_
diff --git a/xfa/fxfa/parser/cxfa_document_parser.cpp b/xfa/fxfa/parser/cxfa_document_parser.cpp
index 6446ea3..e210b94 100644
--- a/xfa/fxfa/parser/cxfa_document_parser.cpp
+++ b/xfa/fxfa/parser/cxfa_document_parser.cpp
@@ -6,48 +6,1035 @@
 
 #include "xfa/fxfa/parser/cxfa_document_parser.h"
 
-#include "core/fxcrt/xml/cfx_xmldoc.h"
-#include "third_party/base/ptr_util.h"
+#include <utility>
+#include <vector>
+
+#include "core/fxcrt/autorestorer.h"
+#include "core/fxcrt/cfx_readonlymemorystream.h"
+#include "core/fxcrt/cfx_widetextbuf.h"
+#include "core/fxcrt/fx_codepage.h"
+#include "core/fxcrt/fx_extension.h"
+#include "core/fxcrt/xml/cfx_xmlchardata.h"
+#include "core/fxcrt/xml/cfx_xmldocument.h"
+#include "core/fxcrt/xml/cfx_xmlelement.h"
+#include "core/fxcrt/xml/cfx_xmlinstruction.h"
+#include "core/fxcrt/xml/cfx_xmlnode.h"
+#include "core/fxcrt/xml/cfx_xmlparser.h"
+#include "core/fxcrt/xml/cfx_xmltext.h"
+#include "fxjs/xfa/cjx_object.h"
+#include "third_party/base/logging.h"
+#include "third_party/base/optional.h"
 #include "xfa/fxfa/fxfa.h"
 #include "xfa/fxfa/parser/cxfa_document.h"
+#include "xfa/fxfa/parser/cxfa_node.h"
+#include "xfa/fxfa/parser/cxfa_subform.h"
+#include "xfa/fxfa/parser/cxfa_template.h"
+#include "xfa/fxfa/parser/xfa_basic_data.h"
+#include "xfa/fxfa/parser/xfa_utils.h"
 
-CXFA_DocumentParser::CXFA_DocumentParser(CXFA_FFNotify* pNotify)
-    : m_pNotify(pNotify) {}
+namespace {
 
-CXFA_DocumentParser::~CXFA_DocumentParser() {
+CFX_XMLNode* GetDocumentNode(CFX_XMLNode* pRootNode) {
+  for (CFX_XMLNode* pXMLNode = pRootNode->GetFirstChild(); pXMLNode;
+       pXMLNode = pXMLNode->GetNextSibling()) {
+    if (pXMLNode->GetType() == CFX_XMLNode::Type::kElement)
+      return pXMLNode;
+  }
+  return nullptr;
 }
 
-int32_t CXFA_DocumentParser::StartParse(
-    const RetainPtr<IFX_SeekableStream>& pStream,
+bool MatchNodeName(CFX_XMLNode* pNode,
+                   WideStringView wsLocalTagName,
+                   WideStringView wsNamespaceURIPrefix,
+                   uint32_t eMatchFlags = XFA_XDPPACKET_FLAGS_NOMATCH) {
+  CFX_XMLElement* pElement = ToXMLElement(pNode);
+  if (!pElement)
+    return false;
+
+  WideString wsNodeStr = pElement->GetLocalTagName();
+  if (wsNodeStr != wsLocalTagName)
+    return false;
+
+  wsNodeStr = pElement->GetNamespaceURI();
+  if (eMatchFlags & XFA_XDPPACKET_FLAGS_NOMATCH)
+    return true;
+  if (eMatchFlags & XFA_XDPPACKET_FLAGS_PREFIXMATCH) {
+    return wsNodeStr.First(wsNamespaceURIPrefix.GetLength()) ==
+           wsNamespaceURIPrefix;
+  }
+
+  return wsNodeStr == wsNamespaceURIPrefix;
+}
+
+bool GetAttributeLocalName(WideStringView wsAttributeName,
+                           WideString& wsLocalAttrName) {
+  WideString wsAttrName(wsAttributeName);
+  auto pos = wsAttrName.Find(L':', 0);
+  if (!pos.has_value()) {
+    wsLocalAttrName = std::move(wsAttrName);
+    return false;
+  }
+  wsLocalAttrName = wsAttrName.Last(wsAttrName.GetLength() - pos.value() - 1);
+  return true;
+}
+
+bool ResolveAttribute(CFX_XMLElement* pElement,
+                      const WideString& wsAttrName,
+                      WideString& wsLocalAttrName,
+                      WideString& wsNamespaceURI) {
+  WideString wsNSPrefix;
+  if (GetAttributeLocalName(wsAttrName.AsStringView(), wsLocalAttrName)) {
+    wsNSPrefix = wsAttrName.First(wsAttrName.GetLength() -
+                                  wsLocalAttrName.GetLength() - 1);
+  }
+  if (wsLocalAttrName.EqualsASCII("xmlns") || wsNSPrefix.EqualsASCII("xmlns") ||
+      wsNSPrefix.EqualsASCII("xml")) {
+    return false;
+  }
+  if (!XFA_FDEExtension_ResolveNamespaceQualifier(pElement, wsNSPrefix,
+                                                  &wsNamespaceURI)) {
+    wsNamespaceURI.clear();
+    return false;
+  }
+  return true;
+}
+
+Optional<WideString> FindAttributeWithNS(CFX_XMLElement* pElement,
+                                         WideStringView wsLocalAttributeName,
+                                         WideStringView wsNamespaceURIPrefix) {
+  WideString wsAttrNS;
+  for (auto it : pElement->GetAttributes()) {
+    auto pos = it.first.Find(L':', 0);
+    WideString wsNSPrefix;
+    if (!pos.has_value()) {
+      if (wsLocalAttributeName != it.first)
+        continue;
+    } else {
+      if (wsLocalAttributeName !=
+          it.first.Last(it.first.GetLength() - pos.value() - 1)) {
+        continue;
+      }
+      wsNSPrefix = it.first.First(pos.value());
+    }
+    if (!XFA_FDEExtension_ResolveNamespaceQualifier(pElement, wsNSPrefix,
+                                                    &wsAttrNS) ||
+        wsAttrNS != wsNamespaceURIPrefix) {
+      continue;
+    }
+    return it.second;
+  }
+  return {};
+}
+
+CFX_XMLNode* GetDataSetsFromXDP(CFX_XMLNode* pXMLDocumentNode) {
+  XFA_PACKETINFO datasets_packet =
+      XFA_GetPacketByIndex(XFA_PacketType::Datasets);
+  if (MatchNodeName(pXMLDocumentNode, datasets_packet.name, datasets_packet.uri,
+                    datasets_packet.flags)) {
+    return pXMLDocumentNode;
+  }
+  XFA_PACKETINFO xdp_packet = XFA_GetPacketByIndex(XFA_PacketType::Xdp);
+  if (!MatchNodeName(pXMLDocumentNode, xdp_packet.name, xdp_packet.uri,
+                     xdp_packet.flags)) {
+    return nullptr;
+  }
+  for (CFX_XMLNode* pDatasetsNode = pXMLDocumentNode->GetFirstChild();
+       pDatasetsNode; pDatasetsNode = pDatasetsNode->GetNextSibling()) {
+    if (MatchNodeName(pDatasetsNode, datasets_packet.name, datasets_packet.uri,
+                      datasets_packet.flags)) {
+      return pDatasetsNode;
+    }
+  }
+  return nullptr;
+}
+
+bool IsStringAllWhitespace(WideString wsText) {
+  wsText.TrimRight(L"\x20\x9\xD\xA");
+  return wsText.IsEmpty();
+}
+
+void ConvertXMLToPlainText(CFX_XMLElement* pRootXMLNode, WideString& wsOutput) {
+  for (CFX_XMLNode* pXMLChild = pRootXMLNode->GetFirstChild(); pXMLChild;
+       pXMLChild = pXMLChild->GetNextSibling()) {
+    switch (pXMLChild->GetType()) {
+      case CFX_XMLNode::Type::kElement: {
+        WideString wsTextData = ToXMLElement(pXMLChild)->GetTextData();
+        wsTextData += L"\n";
+        wsOutput += wsTextData;
+        break;
+      }
+      case CFX_XMLNode::Type::kText:
+      case CFX_XMLNode::Type::kCharData: {
+        WideString wsText = ToXMLText(pXMLChild)->GetText();
+        if (IsStringAllWhitespace(wsText))
+          continue;
+        wsOutput = std::move(wsText);
+        break;
+      }
+      default:
+        NOTREACHED();
+        break;
+    }
+  }
+}
+
+WideString GetPlainTextFromRichText(CFX_XMLNode* pXMLNode) {
+  if (!pXMLNode)
+    return WideString();
+
+  WideString wsPlainText;
+  switch (pXMLNode->GetType()) {
+    case CFX_XMLNode::Type::kElement: {
+      CFX_XMLElement* pXMLElement = static_cast<CFX_XMLElement*>(pXMLNode);
+      WideString wsTag = pXMLElement->GetLocalTagName();
+      uint32_t uTag = FX_HashCode_GetW(wsTag.AsStringView(), true);
+      if (uTag == 0x0001f714) {
+        wsPlainText += L"\n";
+      } else if (uTag == 0x00000070) {
+        if (!wsPlainText.IsEmpty()) {
+          wsPlainText += L"\n";
+        }
+      } else if (uTag == 0xa48ac63) {
+        if (!wsPlainText.IsEmpty() && wsPlainText.Back() != '\n') {
+          wsPlainText += L"\n";
+        }
+      }
+      break;
+    }
+    case CFX_XMLNode::Type::kText:
+    case CFX_XMLNode::Type::kCharData: {
+      WideString wsContent = ToXMLText(pXMLNode)->GetText();
+      wsPlainText += wsContent;
+      break;
+    }
+    default:
+      break;
+  }
+  for (CFX_XMLNode* pChildXML = pXMLNode->GetFirstChild(); pChildXML;
+       pChildXML = pChildXML->GetNextSibling()) {
+    wsPlainText += GetPlainTextFromRichText(pChildXML);
+  }
+
+  return wsPlainText;
+}
+
+}  // namespace
+
+bool XFA_RecognizeRichText(CFX_XMLElement* pRichTextXMLNode) {
+  return pRichTextXMLNode && pRichTextXMLNode->GetNamespaceURI().EqualsASCII(
+                                 "http://www.w3.org/1999/xhtml");
+}
+
+CXFA_DocumentParser::CXFA_DocumentParser(CXFA_Document* pFactory)
+    : m_pFactory(pFactory) {}
+
+CXFA_DocumentParser::~CXFA_DocumentParser() = default;
+
+bool CXFA_DocumentParser::Parse(
+    const RetainPtr<IFX_SeekableReadStream>& pStream,
     XFA_PacketType ePacketID) {
-  m_pDocument.reset();
-  m_nodeParser.CloseParser();
+  xml_doc_ = LoadXML(pStream);
+  if (!xml_doc_)
+    return false;
 
-  int32_t nRetStatus = m_nodeParser.StartParse(pStream, ePacketID);
-  if (nRetStatus == XFA_PARSESTATUS_Ready) {
-    m_pDocument = pdfium::MakeUnique<CXFA_Document>(this);
-    m_nodeParser.SetFactory(m_pDocument.get());
+  CFX_XMLNode* root = GetDocumentNode(xml_doc_->GetRoot());
+  if (!root)
+    return false;
+
+  m_pRootNode = ParseAsXDPPacket(root, ePacketID);
+  return !!m_pRootNode;
+}
+
+CFX_XMLNode* CXFA_DocumentParser::ParseXMLData(const ByteString& wsXML) {
+  auto pStream = pdfium::MakeRetain<CFX_ReadOnlyMemoryStream>(wsXML.raw_span());
+  xml_doc_ = LoadXML(pStream);
+  if (!xml_doc_)
+    return nullptr;
+  return GetDocumentNode(xml_doc_->GetRoot());
+}
+
+std::unique_ptr<CFX_XMLDocument> CXFA_DocumentParser::LoadXML(
+    const RetainPtr<IFX_SeekableReadStream>& pStream) {
+  ASSERT(pStream);
+
+  CFX_XMLParser parser(pStream);
+  std::unique_ptr<CFX_XMLDocument> doc = parser.Parse();
+  if (doc) {
+    doc->GetRoot()->InsertChildNode(doc->CreateNode<CFX_XMLInstruction>(L"xml"),
+                                    0);
   }
-  return nRetStatus;
+  return doc;
 }
 
-int32_t CXFA_DocumentParser::DoParse() {
-  int32_t nRetStatus = m_nodeParser.DoParse();
-  if (nRetStatus >= XFA_PARSESTATUS_Done) {
-    ASSERT(m_pDocument);
-    m_pDocument->SetRoot(m_nodeParser.GetRootNode());
+void CXFA_DocumentParser::ConstructXFANode(CXFA_Node* pXFANode,
+                                           CFX_XMLNode* pXMLNode) {
+  XFA_PacketType ePacketID = pXFANode->GetPacketType();
+  if (ePacketID == XFA_PacketType::Datasets) {
+    if (pXFANode->GetElementType() == XFA_Element::DataValue) {
+      for (CFX_XMLNode* pXMLChild = pXMLNode->GetFirstChild(); pXMLChild;
+           pXMLChild = pXMLChild->GetNextSibling()) {
+        CFX_XMLNode::Type eNodeType = pXMLChild->GetType();
+        if (eNodeType == CFX_XMLNode::Type::kInstruction)
+          continue;
+
+        if (eNodeType == CFX_XMLNode::Type::kElement) {
+          CXFA_Node* pXFAChild = m_pFactory->CreateNode(
+              XFA_PacketType::Datasets, XFA_Element::DataValue);
+          if (!pXFAChild)
+            return;
+
+          CFX_XMLElement* child = static_cast<CFX_XMLElement*>(pXMLChild);
+          WideString wsNodeStr = child->GetLocalTagName();
+          pXFAChild->JSObject()->SetCData(XFA_Attribute::Name, wsNodeStr, false,
+                                          false);
+          WideString wsChildValue = GetPlainTextFromRichText(child);
+          if (!wsChildValue.IsEmpty())
+            pXFAChild->JSObject()->SetCData(XFA_Attribute::Value, wsChildValue,
+                                            false, false);
+
+          pXFANode->InsertChildAndNotify(pXFAChild, nullptr);
+          pXFAChild->SetXMLMappingNode(pXMLChild);
+          pXFAChild->SetFlag(XFA_NodeFlag_Initialized);
+          break;
+        }
+      }
+      m_pRootNode = pXFANode;
+    } else {
+      m_pRootNode = DataLoader(pXFANode, pXMLNode, true);
+    }
+  } else if (pXFANode->IsContentNode()) {
+    ParseContentNode(pXFANode, pXMLNode, ePacketID);
+    m_pRootNode = pXFANode;
+  } else {
+    m_pRootNode = NormalLoader(pXFANode, pXMLNode, ePacketID, true);
   }
-  return nRetStatus;
 }
 
-CFX_XMLDoc* CXFA_DocumentParser::GetXMLDoc() const {
-  return m_nodeParser.GetXMLDoc();
+CXFA_Node* CXFA_DocumentParser::GetRootNode() const {
+  return m_pRootNode;
 }
 
-CXFA_FFNotify* CXFA_DocumentParser::GetNotify() const {
-  return m_pNotify.Get();
+CXFA_Node* CXFA_DocumentParser::ParseAsXDPPacket(CFX_XMLNode* pXMLDocumentNode,
+                                                 XFA_PacketType ePacketID) {
+  switch (ePacketID) {
+    case XFA_PacketType::Xdp:
+      return ParseAsXDPPacket_XDP(pXMLDocumentNode);
+    case XFA_PacketType::Config:
+      return ParseAsXDPPacket_Config(pXMLDocumentNode);
+    case XFA_PacketType::Template:
+      return ParseAsXDPPacket_Template(pXMLDocumentNode);
+    case XFA_PacketType::Form:
+      return ParseAsXDPPacket_Form(pXMLDocumentNode);
+    case XFA_PacketType::Datasets:
+      return ParseAsXDPPacket_Data(pXMLDocumentNode);
+    case XFA_PacketType::Xdc:
+      return ParseAsXDPPacket_Xdc(pXMLDocumentNode);
+    case XFA_PacketType::LocaleSet:
+      return ParseAsXDPPacket_LocaleConnectionSourceSet(
+          pXMLDocumentNode, XFA_PacketType::LocaleSet, XFA_Element::LocaleSet);
+    case XFA_PacketType::ConnectionSet:
+      return ParseAsXDPPacket_LocaleConnectionSourceSet(
+          pXMLDocumentNode, XFA_PacketType::ConnectionSet,
+          XFA_Element::ConnectionSet);
+    case XFA_PacketType::SourceSet:
+      return ParseAsXDPPacket_LocaleConnectionSourceSet(
+          pXMLDocumentNode, XFA_PacketType::SourceSet, XFA_Element::SourceSet);
+    default:
+      return ParseAsXDPPacket_User(pXMLDocumentNode);
+  }
 }
 
-CXFA_Document* CXFA_DocumentParser::GetDocument() const {
-  return m_pDocument.get();
+CXFA_Node* CXFA_DocumentParser::ParseAsXDPPacket_XDP(
+    CFX_XMLNode* pXMLDocumentNode) {
+  XFA_PACKETINFO packet = XFA_GetPacketByIndex(XFA_PacketType::Xdp);
+  if (!MatchNodeName(pXMLDocumentNode, packet.name, packet.uri, packet.flags))
+    return nullptr;
+
+  CXFA_Node* pXFARootNode =
+      m_pFactory->CreateNode(XFA_PacketType::Xdp, XFA_Element::Xfa);
+  if (!pXFARootNode)
+    return nullptr;
+
+  m_pRootNode = pXFARootNode;
+  pXFARootNode->JSObject()->SetCData(XFA_Attribute::Name, L"xfa", false, false);
+
+  for (auto it : ToXMLElement(pXMLDocumentNode)->GetAttributes()) {
+    if (it.first.EqualsASCII("uuid")) {
+      pXFARootNode->JSObject()->SetCData(XFA_Attribute::Uuid, it.second, false,
+                                         false);
+    } else if (it.first.EqualsASCII("timeStamp")) {
+      pXFARootNode->JSObject()->SetCData(XFA_Attribute::TimeStamp, it.second,
+                                         false, false);
+    }
+  }
+
+  CFX_XMLNode* pXMLConfigDOMRoot = nullptr;
+  CXFA_Node* pXFAConfigDOMRoot = nullptr;
+  XFA_PACKETINFO config_packet = XFA_GetPacketByIndex(XFA_PacketType::Config);
+  for (CFX_XMLNode* pChildItem = pXMLDocumentNode->GetFirstChild(); pChildItem;
+       pChildItem = pChildItem->GetNextSibling()) {
+    if (!MatchNodeName(pChildItem, config_packet.name, config_packet.uri,
+                       config_packet.flags)) {
+      continue;
+    }
+    // TODO(tsepez): make GetFirstChildByName() take a name.
+    uint32_t hash = FX_HashCode_GetW(config_packet.name, false);
+    if (pXFARootNode->GetFirstChildByName(hash))
+      return nullptr;
+
+    pXMLConfigDOMRoot = pChildItem;
+    pXFAConfigDOMRoot = ParseAsXDPPacket_Config(pXMLConfigDOMRoot);
+    if (pXFAConfigDOMRoot)
+      pXFARootNode->InsertChildAndNotify(pXFAConfigDOMRoot, nullptr);
+  }
+
+  CFX_XMLNode* pXMLDatasetsDOMRoot = nullptr;
+  CFX_XMLNode* pXMLFormDOMRoot = nullptr;
+  CFX_XMLNode* pXMLTemplateDOMRoot = nullptr;
+  for (CFX_XMLNode* pChildItem = pXMLDocumentNode->GetFirstChild(); pChildItem;
+       pChildItem = pChildItem->GetNextSibling()) {
+    CFX_XMLElement* pElement = ToXMLElement(pChildItem);
+    if (!pElement || pElement == pXMLConfigDOMRoot)
+      continue;
+
+    WideString wsPacketName = pElement->GetLocalTagName();
+    Optional<XFA_PACKETINFO> packet_info =
+        XFA_GetPacketByName(wsPacketName.AsStringView());
+    if (packet_info.has_value() && packet_info.value().uri &&
+        !MatchNodeName(pElement, packet_info.value().name,
+                       packet_info.value().uri, packet_info.value().flags)) {
+      packet_info = {};
+    }
+    XFA_PacketType ePacket = XFA_PacketType::User;
+    if (packet_info.has_value())
+      ePacket = packet_info.value().packet_type;
+    if (ePacket == XFA_PacketType::Xdp)
+      continue;
+    if (ePacket == XFA_PacketType::Datasets) {
+      if (pXMLDatasetsDOMRoot)
+        return nullptr;
+
+      pXMLDatasetsDOMRoot = pElement;
+    } else if (ePacket == XFA_PacketType::Form) {
+      if (pXMLFormDOMRoot)
+        return nullptr;
+
+      pXMLFormDOMRoot = pElement;
+    } else if (ePacket == XFA_PacketType::Template) {
+      // Found a duplicate template packet.
+      if (pXMLTemplateDOMRoot)
+        return nullptr;
+
+      CXFA_Node* pPacketNode = ParseAsXDPPacket_Template(pElement);
+      if (pPacketNode) {
+        pXMLTemplateDOMRoot = pElement;
+        pXFARootNode->InsertChildAndNotify(pPacketNode, nullptr);
+      }
+    } else {
+      CXFA_Node* pPacketNode = ParseAsXDPPacket(pElement, ePacket);
+      if (pPacketNode) {
+        if (packet_info.has_value() &&
+            (packet_info.value().flags & XFA_XDPPACKET_FLAGS_SUPPORTONE) &&
+            pXFARootNode->GetFirstChildByName(
+                FX_HashCode_GetW(packet_info.value().name, false))) {
+          return nullptr;
+        }
+        pXFARootNode->InsertChildAndNotify(pPacketNode, nullptr);
+      }
+    }
+  }
+
+  // No template is found.
+  if (!pXMLTemplateDOMRoot)
+    return nullptr;
+
+  if (pXMLDatasetsDOMRoot) {
+    CXFA_Node* pPacketNode =
+        ParseAsXDPPacket(pXMLDatasetsDOMRoot, XFA_PacketType::Datasets);
+    if (pPacketNode)
+      pXFARootNode->InsertChildAndNotify(pPacketNode, nullptr);
+  }
+  if (pXMLFormDOMRoot) {
+    CXFA_Node* pPacketNode =
+        ParseAsXDPPacket(pXMLFormDOMRoot, XFA_PacketType::Form);
+    if (pPacketNode)
+      pXFARootNode->InsertChildAndNotify(pPacketNode, nullptr);
+  }
+
+  pXFARootNode->SetXMLMappingNode(pXMLDocumentNode);
+  return pXFARootNode;
+}
+
+CXFA_Node* CXFA_DocumentParser::ParseAsXDPPacket_Config(
+    CFX_XMLNode* pXMLDocumentNode) {
+  XFA_PACKETINFO packet = XFA_GetPacketByIndex(XFA_PacketType::Config);
+  if (!MatchNodeName(pXMLDocumentNode, packet.name, packet.uri, packet.flags))
+    return nullptr;
+
+  CXFA_Node* pNode =
+      m_pFactory->CreateNode(XFA_PacketType::Config, XFA_Element::Config);
+  if (!pNode)
+    return nullptr;
+
+  pNode->JSObject()->SetCData(XFA_Attribute::Name, packet.name, false, false);
+  if (!NormalLoader(pNode, pXMLDocumentNode, XFA_PacketType::Config, true))
+    return nullptr;
+
+  pNode->SetXMLMappingNode(pXMLDocumentNode);
+  return pNode;
+}
+
+CXFA_Node* CXFA_DocumentParser::ParseAsXDPPacket_Template(
+    CFX_XMLNode* pXMLDocumentNode) {
+  XFA_PACKETINFO packet = XFA_GetPacketByIndex(XFA_PacketType::Template);
+  if (!MatchNodeName(pXMLDocumentNode, packet.name, packet.uri, packet.flags))
+    return nullptr;
+
+  CXFA_Node* pNode =
+      m_pFactory->CreateNode(XFA_PacketType::Template, XFA_Element::Template);
+  if (!pNode)
+    return nullptr;
+
+  pNode->JSObject()->SetCData(XFA_Attribute::Name, packet.name, false, false);
+
+  CFX_XMLElement* pXMLDocumentElement = ToXMLElement(pXMLDocumentNode);
+  WideString wsNamespaceURI = pXMLDocumentElement->GetNamespaceURI();
+  if (wsNamespaceURI.IsEmpty())
+    wsNamespaceURI = pXMLDocumentElement->GetAttribute(L"xmlns:xfa");
+
+  pNode->GetDocument()->RecognizeXFAVersionNumber(wsNamespaceURI);
+
+  if (!NormalLoader(pNode, pXMLDocumentNode, XFA_PacketType::Template, true))
+    return nullptr;
+
+  pNode->SetXMLMappingNode(pXMLDocumentNode);
+  return pNode;
+}
+
+CXFA_Node* CXFA_DocumentParser::ParseAsXDPPacket_Form(
+    CFX_XMLNode* pXMLDocumentNode) {
+  XFA_PACKETINFO packet = XFA_GetPacketByIndex(XFA_PacketType::Form);
+  if (!MatchNodeName(pXMLDocumentNode, packet.name, packet.uri, packet.flags))
+    return nullptr;
+
+  CXFA_Node* pNode =
+      m_pFactory->CreateNode(XFA_PacketType::Form, XFA_Element::Form);
+  if (!pNode)
+    return nullptr;
+
+  pNode->JSObject()->SetCData(XFA_Attribute::Name, packet.name, false, false);
+  CXFA_Template* pTemplateRoot =
+      m_pRootNode->GetFirstChildByClass<CXFA_Template>(XFA_Element::Template);
+  CXFA_Subform* pTemplateChosen =
+      pTemplateRoot ? pTemplateRoot->GetFirstChildByClass<CXFA_Subform>(
+                          XFA_Element::Subform)
+                    : nullptr;
+  bool bUseAttribute = true;
+  if (pTemplateChosen &&
+      pTemplateChosen->JSObject()->GetEnum(XFA_Attribute::RestoreState) !=
+          XFA_AttributeValue::Auto) {
+    bUseAttribute = false;
+  }
+  if (!NormalLoader(pNode, pXMLDocumentNode, XFA_PacketType::Form,
+                    bUseAttribute))
+    return nullptr;
+
+  pNode->SetXMLMappingNode(pXMLDocumentNode);
+  return pNode;
+}
+
+CXFA_Node* CXFA_DocumentParser::ParseAsXDPPacket_Data(
+    CFX_XMLNode* pXMLDocumentNode) {
+  XFA_PACKETINFO packet = XFA_GetPacketByIndex(XFA_PacketType::Datasets);
+  CFX_XMLNode* pDatasetsXMLNode = GetDataSetsFromXDP(pXMLDocumentNode);
+  if (pDatasetsXMLNode) {
+    CXFA_Node* pNode = m_pFactory->CreateNode(XFA_PacketType::Datasets,
+                                              XFA_Element::DataModel);
+    if (!pNode)
+      return nullptr;
+
+    pNode->JSObject()->SetCData(XFA_Attribute::Name, packet.name, false, false);
+    if (!DataLoader(pNode, pDatasetsXMLNode, false))
+      return nullptr;
+
+    pNode->SetXMLMappingNode(pDatasetsXMLNode);
+    return pNode;
+  }
+
+  CFX_XMLNode* pDataXMLNode = nullptr;
+  if (MatchNodeName(pXMLDocumentNode, L"data", packet.uri, packet.flags)) {
+    ToXMLElement(pXMLDocumentNode)->RemoveAttribute(L"xmlns:xfa");
+    pDataXMLNode = pXMLDocumentNode;
+  } else {
+    auto* pDataElement = xml_doc_->CreateNode<CFX_XMLElement>(L"xfa:data");
+    pXMLDocumentNode->RemoveSelfIfParented();
+
+    CFX_XMLElement* pElement = ToXMLElement(pXMLDocumentNode);
+    pElement->RemoveAttribute(L"xmlns:xfa");
+
+    // The node was either removed from the parent above, or already has no
+    // parent so we can take ownership.
+    pDataElement->AppendLastChild(pXMLDocumentNode);
+    pDataXMLNode = pDataElement;
+  }
+  if (!pDataXMLNode)
+    return nullptr;
+
+  CXFA_Node* pNode =
+      m_pFactory->CreateNode(XFA_PacketType::Datasets, XFA_Element::DataGroup);
+  if (!pNode)
+    return nullptr;
+
+  WideString wsLocalName = ToXMLElement(pDataXMLNode)->GetLocalTagName();
+  pNode->JSObject()->SetCData(XFA_Attribute::Name, wsLocalName, false, false);
+  if (!DataLoader(pNode, pDataXMLNode, true))
+    return nullptr;
+
+  pNode->SetXMLMappingNode(pDataXMLNode);
+  return pNode;
+}
+
+CXFA_Node* CXFA_DocumentParser::ParseAsXDPPacket_LocaleConnectionSourceSet(
+    CFX_XMLNode* pXMLDocumentNode,
+    XFA_PacketType packet_type,
+    XFA_Element element) {
+  XFA_PACKETINFO packet = XFA_GetPacketByIndex(packet_type);
+  if (!MatchNodeName(pXMLDocumentNode, packet.name, packet.uri, packet.flags))
+    return nullptr;
+
+  CXFA_Node* pNode = m_pFactory->CreateNode(packet_type, element);
+  if (!pNode)
+    return nullptr;
+
+  pNode->JSObject()->SetCData(XFA_Attribute::Name, packet.name, false, false);
+  if (!NormalLoader(pNode, pXMLDocumentNode, packet_type, true))
+    return nullptr;
+
+  pNode->SetXMLMappingNode(pXMLDocumentNode);
+  return pNode;
+}
+
+CXFA_Node* CXFA_DocumentParser::ParseAsXDPPacket_Xdc(
+    CFX_XMLNode* pXMLDocumentNode) {
+  XFA_PACKETINFO packet = XFA_GetPacketByIndex(XFA_PacketType::Xdc);
+  if (!MatchNodeName(pXMLDocumentNode, packet.name, packet.uri, packet.flags))
+    return nullptr;
+
+  CXFA_Node* pNode =
+      m_pFactory->CreateNode(XFA_PacketType::Xdc, XFA_Element::Xdc);
+  if (!pNode)
+    return nullptr;
+
+  pNode->JSObject()->SetCData(XFA_Attribute::Name, packet.name, false, false);
+  pNode->SetXMLMappingNode(pXMLDocumentNode);
+  return pNode;
+}
+
+CXFA_Node* CXFA_DocumentParser::ParseAsXDPPacket_User(
+    CFX_XMLNode* pXMLDocumentNode) {
+  CXFA_Node* pNode =
+      m_pFactory->CreateNode(XFA_PacketType::Xdp, XFA_Element::Packet);
+  if (!pNode)
+    return nullptr;
+
+  WideString wsName = ToXMLElement(pXMLDocumentNode)->GetLocalTagName();
+  pNode->JSObject()->SetCData(XFA_Attribute::Name, wsName, false, false);
+  pNode->SetXMLMappingNode(pXMLDocumentNode);
+  return pNode;
+}
+
+CXFA_Node* CXFA_DocumentParser::DataLoader(CXFA_Node* pXFANode,
+                                           CFX_XMLNode* pXMLDoc,
+                                           bool bDoTransform) {
+  ParseDataGroup(pXFANode, pXMLDoc, XFA_PacketType::Datasets);
+  return pXFANode;
+}
+
+CXFA_Node* CXFA_DocumentParser::NormalLoader(CXFA_Node* pXFANode,
+                                             CFX_XMLNode* pXMLDoc,
+                                             XFA_PacketType ePacketID,
+                                             bool bUseAttribute) {
+  constexpr size_t kMaxExecuteRecursion = 1000;
+  if (m_ExecuteRecursionDepth > kMaxExecuteRecursion)
+    return nullptr;
+  AutoRestorer<size_t> restorer(&m_ExecuteRecursionDepth);
+  ++m_ExecuteRecursionDepth;
+
+  bool bOneOfPropertyFound = false;
+  for (CFX_XMLNode* pXMLChild = pXMLDoc->GetFirstChild(); pXMLChild;
+       pXMLChild = pXMLChild->GetNextSibling()) {
+    switch (pXMLChild->GetType()) {
+      case CFX_XMLNode::Type::kElement: {
+        CFX_XMLElement* pXMLElement = static_cast<CFX_XMLElement*>(pXMLChild);
+        WideString wsTagName = pXMLElement->GetLocalTagName();
+        XFA_Element eType = XFA_GetElementByName(wsTagName.AsStringView());
+        if (eType == XFA_Element::Unknown)
+          continue;
+
+        if (pXFANode->HasPropertyFlags(
+                eType,
+                XFA_PROPERTYFLAG_OneOf | XFA_PROPERTYFLAG_DefaultOneOf)) {
+          if (bOneOfPropertyFound)
+            break;
+          bOneOfPropertyFound = true;
+        }
+
+        CXFA_Node* pXFAChild = m_pFactory->CreateNode(ePacketID, eType);
+        if (!pXFAChild)
+          return nullptr;
+        if (ePacketID == XFA_PacketType::Config) {
+          pXFAChild->JSObject()->SetAttribute(XFA_Attribute::Name,
+                                              wsTagName.AsStringView(), false);
+        }
+
+        bool IsNeedValue = true;
+        for (auto it : pXMLElement->GetAttributes()) {
+          WideString wsAttrName;
+          GetAttributeLocalName(it.first.AsStringView(), wsAttrName);
+          if (wsAttrName.EqualsASCII("nil") && it.second.EqualsASCII("true"))
+            IsNeedValue = false;
+
+          Optional<XFA_ATTRIBUTEINFO> attr =
+              XFA_GetAttributeByName(wsAttrName.AsStringView());
+          if (!attr.has_value())
+            continue;
+
+          if (!bUseAttribute && attr.value().attribute != XFA_Attribute::Name &&
+              attr.value().attribute != XFA_Attribute::Save) {
+            continue;
+          }
+          pXFAChild->JSObject()->SetAttribute(attr.value().attribute,
+                                              it.second.AsStringView(), false);
+        }
+        pXFANode->InsertChildAndNotify(pXFAChild, nullptr);
+        if (eType == XFA_Element::Validate || eType == XFA_Element::Locale) {
+          if (ePacketID == XFA_PacketType::Config)
+            ParseContentNode(pXFAChild, pXMLElement, ePacketID);
+          else
+            NormalLoader(pXFAChild, pXMLElement, ePacketID, bUseAttribute);
+
+          break;
+        }
+        switch (pXFAChild->GetObjectType()) {
+          case XFA_ObjectType::ContentNode:
+          case XFA_ObjectType::TextNode:
+          case XFA_ObjectType::NodeC:
+          case XFA_ObjectType::NodeV:
+            if (IsNeedValue)
+              ParseContentNode(pXFAChild, pXMLElement, ePacketID);
+            break;
+          default:
+            NormalLoader(pXFAChild, pXMLElement, ePacketID, bUseAttribute);
+            break;
+        }
+      } break;
+      case CFX_XMLNode::Type::kInstruction:
+        ParseInstruction(pXFANode, ToXMLInstruction(pXMLChild), ePacketID);
+        break;
+      default:
+        break;
+    }
+  }
+  return pXFANode;
+}
+
+void CXFA_DocumentParser::ParseContentNode(CXFA_Node* pXFANode,
+                                           CFX_XMLNode* pXMLNode,
+                                           XFA_PacketType ePacketID) {
+  XFA_Element element = XFA_Element::Sharptext;
+  if (pXFANode->GetElementType() == XFA_Element::ExData) {
+    WideString wsContentType =
+        pXFANode->JSObject()->GetCData(XFA_Attribute::ContentType);
+    if (wsContentType.EqualsASCII("text/html"))
+      element = XFA_Element::SharpxHTML;
+    else if (wsContentType.EqualsASCII("text/xml"))
+      element = XFA_Element::Sharpxml;
+  }
+  if (element == XFA_Element::SharpxHTML)
+    pXFANode->SetXMLMappingNode(pXMLNode);
+
+  WideString wsValue;
+  for (CFX_XMLNode* pXMLChild = pXMLNode->GetFirstChild(); pXMLChild;
+       pXMLChild = pXMLChild->GetNextSibling()) {
+    CFX_XMLNode::Type eNodeType = pXMLChild->GetType();
+    if (eNodeType == CFX_XMLNode::Type::kInstruction)
+      continue;
+
+    CFX_XMLElement* pElement = ToXMLElement(pXMLChild);
+    if (element == XFA_Element::SharpxHTML) {
+      if (!pElement)
+        break;
+      if (XFA_RecognizeRichText(pElement))
+        wsValue += GetPlainTextFromRichText(pElement);
+    } else if (element == XFA_Element::Sharpxml) {
+      if (!pElement)
+        break;
+      ConvertXMLToPlainText(pElement, wsValue);
+    } else {
+      if (pElement)
+        break;
+      CFX_XMLText* pText = ToXMLText(pXMLChild);
+      if (pText)
+        wsValue = pText->GetText();
+    }
+    break;
+  }
+  if (!wsValue.IsEmpty()) {
+    if (pXFANode->IsContentNode()) {
+      CXFA_Node* pContentRawDataNode =
+          m_pFactory->CreateNode(ePacketID, element);
+      ASSERT(pContentRawDataNode);
+      pContentRawDataNode->JSObject()->SetCData(XFA_Attribute::Value, wsValue,
+                                                false, false);
+      pXFANode->InsertChildAndNotify(pContentRawDataNode, nullptr);
+    } else {
+      pXFANode->JSObject()->SetCData(XFA_Attribute::Value, wsValue, false,
+                                     false);
+    }
+  }
+}
+
+void CXFA_DocumentParser::ParseDataGroup(CXFA_Node* pXFANode,
+                                         CFX_XMLNode* pXMLNode,
+                                         XFA_PacketType ePacketID) {
+  for (CFX_XMLNode* pXMLChild = pXMLNode->GetFirstChild(); pXMLChild;
+       pXMLChild = pXMLChild->GetNextSibling()) {
+    switch (pXMLChild->GetType()) {
+      case CFX_XMLNode::Type::kElement: {
+        CFX_XMLElement* pXMLElement = static_cast<CFX_XMLElement*>(pXMLChild);
+        WideString wsNamespaceURI = pXMLElement->GetNamespaceURI();
+        if (wsNamespaceURI.EqualsASCII(
+                "http://www.xfa.com/schema/xfa-package/") ||
+            wsNamespaceURI.EqualsASCII(
+                "http://www.xfa.org/schema/xfa-package/") ||
+            wsNamespaceURI.EqualsASCII(
+                "http://www.w3.org/2001/XMLSchema-instance")) {
+          continue;
+        }
+
+        XFA_Element eNodeType = XFA_Element::DataModel;
+        if (eNodeType == XFA_Element::DataModel) {
+          Optional<WideString> wsDataNodeAttr =
+              FindAttributeWithNS(pXMLElement, L"dataNode",
+                                  L"http://www.xfa.org/schema/xfa-data/1.0/");
+          if (wsDataNodeAttr.has_value()) {
+            if (wsDataNodeAttr.value().EqualsASCII("dataGroup"))
+              eNodeType = XFA_Element::DataGroup;
+            else if (wsDataNodeAttr.value().EqualsASCII("dataValue"))
+              eNodeType = XFA_Element::DataValue;
+          }
+        }
+        if (eNodeType == XFA_Element::DataModel) {
+          Optional<WideString> wsContentType =
+              FindAttributeWithNS(pXMLElement, L"contentType",
+                                  L"http://www.xfa.org/schema/xfa-data/1.0/");
+          if (wsContentType.has_value() && !wsContentType.value().IsEmpty())
+            eNodeType = XFA_Element::DataValue;
+        }
+        if (eNodeType == XFA_Element::DataModel) {
+          for (CFX_XMLNode* pXMLDataChild = pXMLElement->GetFirstChild();
+               pXMLDataChild; pXMLDataChild = pXMLDataChild->GetNextSibling()) {
+            CFX_XMLElement* pElement = ToXMLElement(pXMLDataChild);
+            if (pElement && !XFA_RecognizeRichText(pElement)) {
+              eNodeType = XFA_Element::DataGroup;
+              break;
+            }
+          }
+        }
+        if (eNodeType == XFA_Element::DataModel)
+          eNodeType = XFA_Element::DataValue;
+
+        CXFA_Node* pXFAChild =
+            m_pFactory->CreateNode(XFA_PacketType::Datasets, eNodeType);
+        if (!pXFAChild)
+          return;
+
+        pXFAChild->JSObject()->SetCData(
+            XFA_Attribute::Name, pXMLElement->GetLocalTagName(), false, false);
+        bool bNeedValue = true;
+
+        for (auto it : pXMLElement->GetAttributes()) {
+          WideString wsName;
+          WideString wsNS;
+          if (!ResolveAttribute(pXMLElement, it.first, wsName, wsNS)) {
+            continue;
+          }
+          if (wsName.EqualsASCII("nil") && it.second.EqualsASCII("true")) {
+            bNeedValue = false;
+            continue;
+          }
+          if (wsNS.EqualsASCII("http://www.xfa.com/schema/xfa-package/") ||
+              wsNS.EqualsASCII("http://www.xfa.org/schema/xfa-package/") ||
+              wsNS.EqualsASCII("http://www.w3.org/2001/XMLSchema-instance") ||
+              wsNS.EqualsASCII("http://www.xfa.org/schema/xfa-data/1.0/")) {
+            continue;
+          }
+          CXFA_Node* pXFAMetaData = m_pFactory->CreateNode(
+              XFA_PacketType::Datasets, XFA_Element::DataValue);
+          if (!pXFAMetaData)
+            return;
+
+          pXFAMetaData->JSObject()->SetCData(XFA_Attribute::Name, wsName, false,
+                                             false);
+          pXFAMetaData->JSObject()->SetCData(XFA_Attribute::QualifiedName,
+                                             it.first, false, false);
+          pXFAMetaData->JSObject()->SetCData(XFA_Attribute::Value, it.second,
+                                             false, false);
+          pXFAMetaData->JSObject()->SetEnum(
+              XFA_Attribute::Contains, XFA_AttributeValue::MetaData, false);
+          pXFAChild->InsertChildAndNotify(pXFAMetaData, nullptr);
+          pXFAMetaData->SetXMLMappingNode(pXMLElement);
+          pXFAMetaData->SetFlag(XFA_NodeFlag_Initialized);
+        }
+
+        if (!bNeedValue)
+          pXMLElement->RemoveAttribute(L"xsi:nil");
+
+        pXFANode->InsertChildAndNotify(pXFAChild, nullptr);
+        if (eNodeType == XFA_Element::DataGroup)
+          ParseDataGroup(pXFAChild, pXMLElement, ePacketID);
+        else if (bNeedValue)
+          ParseDataValue(pXFAChild, pXMLChild, XFA_PacketType::Datasets);
+
+        pXFAChild->SetXMLMappingNode(pXMLElement);
+        pXFAChild->SetFlag(XFA_NodeFlag_Initialized);
+        continue;
+      }
+      case CFX_XMLNode::Type::kCharData:
+      case CFX_XMLNode::Type::kText: {
+        CFX_XMLText* pXMLText = ToXMLText(pXMLChild);
+        WideString wsText = pXMLText->GetText();
+        if (IsStringAllWhitespace(wsText))
+          continue;
+
+        CXFA_Node* pXFAChild = m_pFactory->CreateNode(XFA_PacketType::Datasets,
+                                                      XFA_Element::DataValue);
+        if (!pXFAChild)
+          return;
+
+        pXFAChild->JSObject()->SetCData(XFA_Attribute::Value, wsText, false,
+                                        false);
+        pXFANode->InsertChildAndNotify(pXFAChild, nullptr);
+        pXFAChild->SetXMLMappingNode(pXMLText);
+        pXFAChild->SetFlag(XFA_NodeFlag_Initialized);
+        continue;
+      }
+      default:
+        continue;
+    }
+  }
+}
+
+void CXFA_DocumentParser::ParseDataValue(CXFA_Node* pXFANode,
+                                         CFX_XMLNode* pXMLNode,
+                                         XFA_PacketType ePacketID) {
+  CFX_WideTextBuf wsValueTextBuf;
+  CFX_WideTextBuf wsCurValueTextBuf;
+  bool bMarkAsCompound = false;
+  CFX_XMLNode* pXMLCurValueNode = nullptr;
+  for (CFX_XMLNode* pXMLChild = pXMLNode->GetFirstChild(); pXMLChild;
+       pXMLChild = pXMLChild->GetNextSibling()) {
+    CFX_XMLNode::Type eNodeType = pXMLChild->GetType();
+    if (eNodeType == CFX_XMLNode::Type::kInstruction)
+      continue;
+
+    CFX_XMLText* pText = ToXMLText(pXMLChild);
+    if (pText) {
+      WideString wsText = pText->GetText();
+      if (!pXMLCurValueNode)
+        pXMLCurValueNode = pXMLChild;
+      wsCurValueTextBuf << wsText;
+      continue;
+    }
+    if (XFA_RecognizeRichText(ToXMLElement(pXMLChild))) {
+      WideString wsText = GetPlainTextFromRichText(ToXMLElement(pXMLChild));
+      if (!pXMLCurValueNode)
+        pXMLCurValueNode = pXMLChild;
+      wsCurValueTextBuf << wsText;
+      continue;
+    }
+    bMarkAsCompound = true;
+    if (pXMLCurValueNode) {
+      WideString wsCurValue = wsCurValueTextBuf.MakeString();
+      if (!wsCurValue.IsEmpty()) {
+        CXFA_Node* pXFAChild =
+            m_pFactory->CreateNode(ePacketID, XFA_Element::DataValue);
+        if (!pXFAChild)
+          return;
+
+        pXFAChild->JSObject()->SetCData(XFA_Attribute::Name, WideString(),
+                                        false, false);
+        pXFAChild->JSObject()->SetCData(XFA_Attribute::Value, wsCurValue, false,
+                                        false);
+        pXFANode->InsertChildAndNotify(pXFAChild, nullptr);
+        pXFAChild->SetXMLMappingNode(pXMLCurValueNode);
+        pXFAChild->SetFlag(XFA_NodeFlag_Initialized);
+        wsValueTextBuf << wsCurValue;
+        wsCurValueTextBuf.Clear();
+      }
+      pXMLCurValueNode = nullptr;
+    }
+    CXFA_Node* pXFAChild =
+        m_pFactory->CreateNode(ePacketID, XFA_Element::DataValue);
+    if (!pXFAChild)
+      return;
+
+    WideString wsNodeStr = ToXMLElement(pXMLChild)->GetLocalTagName();
+    pXFAChild->JSObject()->SetCData(XFA_Attribute::Name, wsNodeStr, false,
+                                    false);
+    ParseDataValue(pXFAChild, pXMLChild, ePacketID);
+    pXFANode->InsertChildAndNotify(pXFAChild, nullptr);
+    pXFAChild->SetXMLMappingNode(pXMLChild);
+    pXFAChild->SetFlag(XFA_NodeFlag_Initialized);
+    WideString wsCurValue =
+        pXFAChild->JSObject()->GetCData(XFA_Attribute::Value);
+    wsValueTextBuf << wsCurValue;
+  }
+
+  if (pXMLCurValueNode) {
+    WideString wsCurValue = wsCurValueTextBuf.MakeString();
+    if (!wsCurValue.IsEmpty()) {
+      if (bMarkAsCompound) {
+        CXFA_Node* pXFAChild =
+            m_pFactory->CreateNode(ePacketID, XFA_Element::DataValue);
+        if (!pXFAChild)
+          return;
+
+        pXFAChild->JSObject()->SetCData(XFA_Attribute::Name, WideString(),
+                                        false, false);
+        pXFAChild->JSObject()->SetCData(XFA_Attribute::Value, wsCurValue, false,
+                                        false);
+        pXFANode->InsertChildAndNotify(pXFAChild, nullptr);
+        pXFAChild->SetXMLMappingNode(pXMLCurValueNode);
+        pXFAChild->SetFlag(XFA_NodeFlag_Initialized);
+      }
+      wsValueTextBuf << wsCurValue;
+      wsCurValueTextBuf.Clear();
+    }
+    pXMLCurValueNode = nullptr;
+  }
+  WideString wsNodeValue = wsValueTextBuf.MakeString();
+  pXFANode->JSObject()->SetCData(XFA_Attribute::Value, wsNodeValue, false,
+                                 false);
+}
+
+void CXFA_DocumentParser::ParseInstruction(CXFA_Node* pXFANode,
+                                           CFX_XMLInstruction* pXMLInstruction,
+                                           XFA_PacketType ePacketID) {
+  const std::vector<WideString>& target_data = pXMLInstruction->GetTargetData();
+  if (pXMLInstruction->IsOriginalXFAVersion()) {
+    if (target_data.size() > 1 &&
+        (pXFANode->GetDocument()->RecognizeXFAVersionNumber(target_data[0]) !=
+         XFA_VERSION_UNKNOWN) &&
+        target_data[1].EqualsASCII("v2.7-scripting:1")) {
+      pXFANode->GetDocument()->set_is_scripting();
+    }
+    return;
+  }
+  if (pXMLInstruction->IsAcrobat()) {
+    if (target_data.size() > 1 && target_data[0].EqualsASCII("JavaScript") &&
+        target_data[1].EqualsASCII("strictScoping")) {
+      pXFANode->GetDocument()->set_is_strict_scoping();
+    }
+  }
 }
diff --git a/xfa/fxfa/parser/cxfa_document_parser.h b/xfa/fxfa/parser/cxfa_document_parser.h
index 35d7160..a494b4f 100644
--- a/xfa/fxfa/parser/cxfa_document_parser.h
+++ b/xfa/fxfa/parser/cxfa_document_parser.h
@@ -1,4 +1,4 @@
-// Copyright 2016 PDFium Authors. All rights reserved.
+// Copyright 2014 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.
 
@@ -8,32 +8,75 @@
 #define XFA_FXFA_PARSER_CXFA_DOCUMENT_PARSER_H_
 
 #include <memory>
+#include <utility>
 
-#include "xfa/fxfa/parser/cxfa_simple_parser.h"
+#include "core/fxcrt/fx_string.h"
+#include "core/fxcrt/retain_ptr.h"
+#include "xfa/fxfa/fxfa_basic.h"
 
-class CFX_XMLDoc;
+class CFX_XMLDocument;
+class CFX_XMLNode;
 class CXFA_Document;
-class CXFA_FFNotify;
-class CXFA_Notify;
-class IFX_SeekableStream;
+class CXFA_Node;
+class CFX_XMLInstruction;
+class IFX_SeekableReadStream;
 
 class CXFA_DocumentParser {
  public:
-  explicit CXFA_DocumentParser(CXFA_FFNotify* pNotify);
+  explicit CXFA_DocumentParser(CXFA_Document* pFactory);
   ~CXFA_DocumentParser();
 
-  int32_t StartParse(const RetainPtr<IFX_SeekableStream>& pStream,
-                     XFA_PacketType ePacketID);
-  int32_t DoParse();
+  bool Parse(const RetainPtr<IFX_SeekableReadStream>& pStream,
+             XFA_PacketType ePacketID);
 
-  CFX_XMLDoc* GetXMLDoc() const;
-  CXFA_FFNotify* GetNotify() const;
-  CXFA_Document* GetDocument() const;
+  CFX_XMLNode* ParseXMLData(const ByteString& wsXML);
+  void ConstructXFANode(CXFA_Node* pXFANode, CFX_XMLNode* pXMLNode);
+
+  std::unique_ptr<CFX_XMLDocument> GetXMLDoc() { return std::move(xml_doc_); }
+  CXFA_Node* GetRootNode() const;
 
  private:
-  UnownedPtr<CXFA_FFNotify> const m_pNotify;
-  std::unique_ptr<CXFA_Document> m_pDocument;
-  CXFA_SimpleParser m_nodeParser;
+  std::unique_ptr<CFX_XMLDocument> LoadXML(
+      const RetainPtr<IFX_SeekableReadStream>& pStream);
+
+  CXFA_Node* ParseAsXDPPacket(CFX_XMLNode* pXMLDocumentNode,
+                              XFA_PacketType ePacketID);
+  CXFA_Node* ParseAsXDPPacket_XDP(CFX_XMLNode* pXMLDocumentNode);
+  CXFA_Node* ParseAsXDPPacket_Config(CFX_XMLNode* pXMLDocumentNode);
+  CXFA_Node* ParseAsXDPPacket_Template(CFX_XMLNode* pXMLDocumentNode);
+  CXFA_Node* ParseAsXDPPacket_Form(CFX_XMLNode* pXMLDocumentNode);
+  CXFA_Node* ParseAsXDPPacket_Data(CFX_XMLNode* pXMLDocumentNode);
+  CXFA_Node* ParseAsXDPPacket_LocaleConnectionSourceSet(
+      CFX_XMLNode* pXMLDocumentNode,
+      XFA_PacketType packet_type,
+      XFA_Element element);
+  CXFA_Node* ParseAsXDPPacket_Xdc(CFX_XMLNode* pXMLDocumentNode);
+  CXFA_Node* ParseAsXDPPacket_User(CFX_XMLNode* pXMLDocumentNode);
+  CXFA_Node* NormalLoader(CXFA_Node* pXFANode,
+                          CFX_XMLNode* pXMLDoc,
+                          XFA_PacketType ePacketID,
+                          bool bUseAttribute);
+  CXFA_Node* DataLoader(CXFA_Node* pXFANode,
+                        CFX_XMLNode* pXMLDoc,
+                        bool bDoTransform);
+  void ParseContentNode(CXFA_Node* pXFANode,
+                        CFX_XMLNode* pXMLNode,
+                        XFA_PacketType ePacketID);
+  void ParseDataValue(CXFA_Node* pXFANode,
+                      CFX_XMLNode* pXMLNode,
+                      XFA_PacketType ePacketID);
+  void ParseDataGroup(CXFA_Node* pXFANode,
+                      CFX_XMLNode* pXMLNode,
+                      XFA_PacketType ePacketID);
+  void ParseInstruction(CXFA_Node* pXFANode,
+                        CFX_XMLInstruction* pXMLInstruction,
+                        XFA_PacketType ePacketID);
+
+  UnownedPtr<CXFA_Document> m_pFactory;
+  std::unique_ptr<CFX_XMLDocument> xml_doc_;
+  // TODO(dsinclair): Figure out who owns this.
+  CXFA_Node* m_pRootNode = nullptr;
+  size_t m_ExecuteRecursionDepth = 0;
 };
 
 #endif  // XFA_FXFA_PARSER_CXFA_DOCUMENT_PARSER_H_
diff --git a/xfa/fxfa/parser/cxfa_simple_parser_embeddertest.cpp b/xfa/fxfa/parser/cxfa_document_parser_embeddertest.cpp
similarity index 75%
rename from xfa/fxfa/parser/cxfa_simple_parser_embeddertest.cpp
rename to xfa/fxfa/parser/cxfa_document_parser_embeddertest.cpp
index 174febf..129c8bc 100644
--- a/xfa/fxfa/parser/cxfa_simple_parser_embeddertest.cpp
+++ b/xfa/fxfa/parser/cxfa_document_parser_embeddertest.cpp
@@ -5,16 +5,16 @@
 #include "testing/embedder_test.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-class CXFASimpleParserEmbeddertest : public EmbedderTest {};
+class CXFASimpleParserEmbedderTest : public EmbedderTest {};
 
-TEST_F(CXFASimpleParserEmbeddertest, Bug_216) {
+TEST_F(CXFASimpleParserEmbedderTest, Bug_216) {
   EXPECT_TRUE(OpenDocument("bug_216.pdf"));
   FPDF_PAGE page = LoadPage(0);
   EXPECT_NE(nullptr, page);
   UnloadPage(page);
 }
 
-TEST_F(CXFASimpleParserEmbeddertest, Bug_709793) {
+TEST_F(CXFASimpleParserEmbedderTest, Bug_709793) {
   EXPECT_TRUE(OpenDocument("bug_709793.pdf"));
   FPDF_PAGE page = LoadPage(0);
   EXPECT_NE(nullptr, page);
diff --git a/xfa/fxfa/parser/cxfa_document_parser_unittest.cpp b/xfa/fxfa/parser/cxfa_document_parser_unittest.cpp
new file mode 100644
index 0000000..625473a
--- /dev/null
+++ b/xfa/fxfa/parser/cxfa_document_parser_unittest.cpp
@@ -0,0 +1,124 @@
+// Copyright 2018 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_document_parser.h"
+
+#include "core/fxcrt/cfx_readonlymemorystream.h"
+#include "core/fxcrt/xml/cfx_xmldocument.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/base/ptr_util.h"
+#include "xfa/fxfa/parser/cxfa_document.h"
+
+class CXFA_DocumentParserTest : public testing::Test {
+ public:
+  void SetUp() override {
+    doc_ = pdfium::MakeUnique<CXFA_Document>(nullptr, nullptr);
+    parser_ = pdfium::MakeUnique<CXFA_DocumentParser>(doc_.get());
+  }
+
+  void TearDown() override {
+    // Hold the XML tree until we cleanup the document.
+    std::unique_ptr<CFX_XMLDocument> doc = parser_->GetXMLDoc();
+    parser_ = nullptr;
+    doc_ = nullptr;
+  }
+
+  CXFA_Document* GetDoc() const { return doc_.get(); }
+  CXFA_DocumentParser* GetParser() const { return parser_.get(); }
+
+ private:
+  std::unique_ptr<CXFA_Document> doc_;
+  std::unique_ptr<CXFA_DocumentParser> parser_;
+};
+
+TEST_F(CXFA_DocumentParserTest, XMLInstructionsScriptOff) {
+  static const char kInput[] =
+      "<config>\n"
+      "<?originalXFAVersion http://www.xfa.org/schema/xfa-template/2.7 "
+      "v2.7-scripting:0 ?>\n"
+      "</config>";
+  EXPECT_FALSE(GetDoc()->is_scripting());
+
+  auto stream = pdfium::MakeRetain<CFX_ReadOnlyMemoryStream>(
+      pdfium::as_bytes(pdfium::make_span(kInput)));
+  ASSERT_TRUE(GetParser()->Parse(stream, XFA_PacketType::Config));
+
+  CXFA_Node* root = GetParser()->GetRootNode();
+  ASSERT_TRUE(root);
+  EXPECT_FALSE(GetDoc()->is_scripting());
+}
+
+TEST_F(CXFA_DocumentParserTest, XMLInstructionsScriptOn) {
+  static const char kInput[] =
+      "<config>\n"
+      "<?originalXFAVersion http://www.xfa.org/schema/xfa-template/2.7 "
+      "v2.7-scripting:1 ?>\n"
+      "</config>";
+
+  EXPECT_FALSE(GetDoc()->is_scripting());
+
+  auto stream = pdfium::MakeRetain<CFX_ReadOnlyMemoryStream>(
+      pdfium::as_bytes(pdfium::make_span(kInput)));
+  ASSERT_TRUE(GetParser()->Parse(stream, XFA_PacketType::Config));
+
+  CXFA_Node* root = GetParser()->GetRootNode();
+  ASSERT_TRUE(root);
+  EXPECT_TRUE(GetDoc()->is_scripting());
+}
+
+TEST_F(CXFA_DocumentParserTest, XMLInstructionsStrictScope) {
+  static const char kInput[] =
+      "<config>"
+      "<?acrobat JavaScript strictScoping ?>\n"
+      "</config>";
+
+  EXPECT_FALSE(GetDoc()->is_strict_scoping());
+
+  auto stream = pdfium::MakeRetain<CFX_ReadOnlyMemoryStream>(
+      pdfium::as_bytes(pdfium::make_span(kInput)));
+  ASSERT_TRUE(GetParser()->Parse(stream, XFA_PacketType::Config));
+
+  CXFA_Node* root = GetParser()->GetRootNode();
+  ASSERT_TRUE(root);
+  EXPECT_TRUE(GetDoc()->is_strict_scoping());
+}
+
+TEST_F(CXFA_DocumentParserTest, XMLInstructionsStrictScopeBad) {
+  static const char kInput[] =
+      "<config>"
+      "<?acrobat JavaScript otherScoping ?>\n"
+      "</config>";
+
+  EXPECT_FALSE(GetDoc()->is_strict_scoping());
+
+  auto stream = pdfium::MakeRetain<CFX_ReadOnlyMemoryStream>(
+      pdfium::as_bytes(pdfium::make_span(kInput)));
+  ASSERT_TRUE(GetParser()->Parse(stream, XFA_PacketType::Config));
+
+  CXFA_Node* root = GetParser()->GetRootNode();
+  ASSERT_TRUE(root);
+  EXPECT_FALSE(GetDoc()->is_strict_scoping());
+}
+
+TEST_F(CXFA_DocumentParserTest, MultipleXMLInstructions) {
+  static const char kInput[] =
+      "<config>"
+      "<?originalXFAVersion http://www.xfa.org/schema/xfa-template/2.7 "
+      "v2.7-scripting:1 ?>\n"
+      "<?acrobat JavaScript strictScoping ?>\n"
+      "</config>";
+
+  EXPECT_FALSE(GetDoc()->is_scripting());
+  EXPECT_FALSE(GetDoc()->is_strict_scoping());
+
+  auto stream = pdfium::MakeRetain<CFX_ReadOnlyMemoryStream>(
+      pdfium::as_bytes(pdfium::make_span(kInput)));
+  ASSERT_TRUE(GetParser()->Parse(stream, XFA_PacketType::Config));
+
+  CXFA_Node* root = GetParser()->GetRootNode();
+  ASSERT_TRUE(root);
+
+  EXPECT_TRUE(GetDoc()->is_scripting());
+  EXPECT_TRUE(GetDoc()->is_strict_scoping());
+}
diff --git a/xfa/fxfa/parser/cxfa_documentassembly.cpp b/xfa/fxfa/parser/cxfa_documentassembly.cpp
index 146071d..c6582e8 100644
--- a/xfa/fxfa/parser/cxfa_documentassembly.cpp
+++ b/xfa/fxfa/parser/cxfa_documentassembly.cpp
@@ -6,14 +6,15 @@
 
 #include "xfa/fxfa/parser/cxfa_documentassembly.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kDocumentAssemblyAttributeData[] = {
     {XFA_Attribute::Desc, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Lock, XFA_AttributeType::Integer, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"documentAssembly";
+};
 
 }  // namespace
 
@@ -24,8 +25,8 @@
                 XFA_XDPPACKET_Config,
                 XFA_ObjectType::ContentNode,
                 XFA_Element::DocumentAssembly,
-                nullptr,
-                kAttributeData,
-                kName) {}
+                {},
+                kDocumentAssemblyAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_DocumentAssembly::~CXFA_DocumentAssembly() {}
+CXFA_DocumentAssembly::~CXFA_DocumentAssembly() = default;
diff --git a/xfa/fxfa/parser/cxfa_documentassembly.h b/xfa/fxfa/parser/cxfa_documentassembly.h
index c22d4a9..92cde65 100644
--- a/xfa/fxfa/parser/cxfa_documentassembly.h
+++ b/xfa/fxfa/parser/cxfa_documentassembly.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_DocumentAssembly : public CXFA_Node {
+class CXFA_DocumentAssembly final : public CXFA_Node {
  public:
   CXFA_DocumentAssembly(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_DocumentAssembly() override;
diff --git a/xfa/fxfa/parser/cxfa_draw.cpp b/xfa/fxfa/parser/cxfa_draw.cpp
index 8d0dd37..02387d7 100644
--- a/xfa/fxfa/parser/cxfa_draw.cpp
+++ b/xfa/fxfa/parser/cxfa_draw.cpp
@@ -11,29 +11,30 @@
 
 namespace {
 
-const CXFA_Node::PropertyData kPropertyData[] = {
+const CXFA_Node::PropertyData kDrawPropertyData[] = {
     {XFA_Element::Ui, 1, 0},     {XFA_Element::Margin, 1, 0},
     {XFA_Element::Para, 1, 0},   {XFA_Element::Border, 1, 0},
     {XFA_Element::Assist, 1, 0}, {XFA_Element::Traversal, 1, 0},
     {XFA_Element::Keep, 1, 0},   {XFA_Element::Caption, 1, 0},
     {XFA_Element::Desc, 1, 0},   {XFA_Element::Font, 1, 0},
     {XFA_Element::Value, 1, 0},  {XFA_Element::Extras, 1, 0},
-    {XFA_Element::Unknown, 0, 0}};
-const CXFA_Node::AttributeData kAttributeData[] = {
+};
+
+const CXFA_Node::AttributeData kDrawAttributeData[] = {
     {XFA_Attribute::H, XFA_AttributeType::Measure, (void*)L"0in"},
     {XFA_Attribute::W, XFA_AttributeType::Measure, (void*)L"0in"},
     {XFA_Attribute::X, XFA_AttributeType::Measure, (void*)L"0in"},
     {XFA_Attribute::Y, XFA_AttributeType::Measure, (void*)L"0in"},
     {XFA_Attribute::Id, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::HAlign, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::Left},
+     (void*)XFA_AttributeValue::Left},
     {XFA_Attribute::Name, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Use, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Rotate, XFA_AttributeType::Integer, (void*)0},
     {XFA_Attribute::Presence, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::Visible},
+     (void*)XFA_AttributeValue::Visible},
     {XFA_Attribute::VAlign, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::Top},
+     (void*)XFA_AttributeValue::Top},
     {XFA_Attribute::MaxH, XFA_AttributeType::Measure, (void*)L"0in"},
     {XFA_Attribute::MaxW, XFA_AttributeType::Measure, (void*)L"0in"},
     {XFA_Attribute::MinH, XFA_AttributeType::Measure, (void*)L"0in"},
@@ -43,10 +44,8 @@
     {XFA_Attribute::Usehref, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Locale, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::AnchorType, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::TopLeft},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"draw";
+     (void*)XFA_AttributeValue::TopLeft},
+};
 
 }  // namespace
 
@@ -56,9 +55,8 @@
                 (XFA_XDPPACKET_Template | XFA_XDPPACKET_Form),
                 XFA_ObjectType::ContainerNode,
                 XFA_Element::Draw,
-                kPropertyData,
-                kAttributeData,
-                kName,
+                kDrawPropertyData,
+                kDrawAttributeData,
                 pdfium::MakeUnique<CJX_Draw>(this)) {}
 
-CXFA_Draw::~CXFA_Draw() {}
+CXFA_Draw::~CXFA_Draw() = default;
diff --git a/xfa/fxfa/parser/cxfa_draw.h b/xfa/fxfa/parser/cxfa_draw.h
index 603103b..c1b9006 100644
--- a/xfa/fxfa/parser/cxfa_draw.h
+++ b/xfa/fxfa/parser/cxfa_draw.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Draw : public CXFA_Node {
+class CXFA_Draw final : public CXFA_Node {
  public:
   CXFA_Draw(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Draw() override;
diff --git a/xfa/fxfa/parser/cxfa_driver.cpp b/xfa/fxfa/parser/cxfa_driver.cpp
index 883cbf6..215601c 100644
--- a/xfa/fxfa/parser/cxfa_driver.cpp
+++ b/xfa/fxfa/parser/cxfa_driver.cpp
@@ -6,18 +6,21 @@
 
 #include "xfa/fxfa/parser/cxfa_driver.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::PropertyData kPropertyData[] = {{XFA_Element::FontInfo, 1, 0},
-                                                 {XFA_Element::Xdc, 1, 0},
-                                                 {XFA_Element::Unknown, 0, 0}};
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::PropertyData kDriverPropertyData[] = {
+    {XFA_Element::FontInfo, 1, 0},
+    {XFA_Element::Xdc, 1, 0},
+};
+
+const CXFA_Node::AttributeData kDriverAttributeData[] = {
     {XFA_Attribute::Name, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Desc, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Lock, XFA_AttributeType::Integer, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"driver";
+};
 
 }  // namespace
 
@@ -27,8 +30,8 @@
                 XFA_XDPPACKET_Config,
                 XFA_ObjectType::Node,
                 XFA_Element::Driver,
-                kPropertyData,
-                kAttributeData,
-                kName) {}
+                kDriverPropertyData,
+                kDriverAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_Driver::~CXFA_Driver() {}
+CXFA_Driver::~CXFA_Driver() = default;
diff --git a/xfa/fxfa/parser/cxfa_driver.h b/xfa/fxfa/parser/cxfa_driver.h
index aee732e..f58e153 100644
--- a/xfa/fxfa/parser/cxfa_driver.h
+++ b/xfa/fxfa/parser/cxfa_driver.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Driver : public CXFA_Node {
+class CXFA_Driver final : public CXFA_Node {
  public:
   CXFA_Driver(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Driver() override;
diff --git a/xfa/fxfa/parser/cxfa_dsigdata.cpp b/xfa/fxfa/parser/cxfa_dsigdata.cpp
index 88d3e8e..19788db 100644
--- a/xfa/fxfa/parser/cxfa_dsigdata.cpp
+++ b/xfa/fxfa/parser/cxfa_dsigdata.cpp
@@ -6,13 +6,14 @@
 
 #include "xfa/fxfa/parser/cxfa_dsigdata.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kDSigDataAttributeData[] = {
     {XFA_Attribute::Value, XFA_AttributeType::CData, nullptr},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"dSigData";
+};
 
 }  // namespace
 
@@ -22,8 +23,8 @@
                 (XFA_XDPPACKET_Template | XFA_XDPPACKET_Form),
                 XFA_ObjectType::Node,
                 XFA_Element::DSigData,
-                nullptr,
-                kAttributeData,
-                kName) {}
+                {},
+                kDSigDataAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_DSigData::~CXFA_DSigData() {}
+CXFA_DSigData::~CXFA_DSigData() = default;
diff --git a/xfa/fxfa/parser/cxfa_dsigdata.h b/xfa/fxfa/parser/cxfa_dsigdata.h
index 0cbaeb4..06e691c 100644
--- a/xfa/fxfa/parser/cxfa_dsigdata.h
+++ b/xfa/fxfa/parser/cxfa_dsigdata.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_DSigData : public CXFA_Node {
+class CXFA_DSigData final : public CXFA_Node {
  public:
   CXFA_DSigData(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_DSigData() override;
diff --git a/xfa/fxfa/parser/cxfa_duplexoption.cpp b/xfa/fxfa/parser/cxfa_duplexoption.cpp
index f8d4170..36feccd 100644
--- a/xfa/fxfa/parser/cxfa_duplexoption.cpp
+++ b/xfa/fxfa/parser/cxfa_duplexoption.cpp
@@ -6,14 +6,15 @@
 
 #include "xfa/fxfa/parser/cxfa_duplexoption.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kDuplexOptionAttributeData[] = {
     {XFA_Attribute::Desc, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Lock, XFA_AttributeType::Integer, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"duplexOption";
+};
 
 }  // namespace
 
@@ -23,8 +24,8 @@
                 XFA_XDPPACKET_Config,
                 XFA_ObjectType::ContentNode,
                 XFA_Element::DuplexOption,
-                nullptr,
-                kAttributeData,
-                kName) {}
+                {},
+                kDuplexOptionAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_DuplexOption::~CXFA_DuplexOption() {}
+CXFA_DuplexOption::~CXFA_DuplexOption() = default;
diff --git a/xfa/fxfa/parser/cxfa_duplexoption.h b/xfa/fxfa/parser/cxfa_duplexoption.h
index 69034ce..5bf8e50 100644
--- a/xfa/fxfa/parser/cxfa_duplexoption.h
+++ b/xfa/fxfa/parser/cxfa_duplexoption.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_DuplexOption : public CXFA_Node {
+class CXFA_DuplexOption final : public CXFA_Node {
  public:
   CXFA_DuplexOption(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_DuplexOption() override;
diff --git a/xfa/fxfa/parser/cxfa_dynamicrender.cpp b/xfa/fxfa/parser/cxfa_dynamicrender.cpp
index a60e192..5326cec 100644
--- a/xfa/fxfa/parser/cxfa_dynamicrender.cpp
+++ b/xfa/fxfa/parser/cxfa_dynamicrender.cpp
@@ -6,14 +6,15 @@
 
 #include "xfa/fxfa/parser/cxfa_dynamicrender.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kDynamicRenderAttributeData[] = {
     {XFA_Attribute::Desc, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Lock, XFA_AttributeType::Integer, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"dynamicRender";
+};
 
 }  // namespace
 
@@ -24,8 +25,8 @@
                 XFA_XDPPACKET_Config,
                 XFA_ObjectType::ContentNode,
                 XFA_Element::DynamicRender,
-                nullptr,
-                kAttributeData,
-                kName) {}
+                {},
+                kDynamicRenderAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_DynamicRender::~CXFA_DynamicRender() {}
+CXFA_DynamicRender::~CXFA_DynamicRender() = default;
diff --git a/xfa/fxfa/parser/cxfa_dynamicrender.h b/xfa/fxfa/parser/cxfa_dynamicrender.h
index f7c54fa..78b75a7 100644
--- a/xfa/fxfa/parser/cxfa_dynamicrender.h
+++ b/xfa/fxfa/parser/cxfa_dynamicrender.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_DynamicRender : public CXFA_Node {
+class CXFA_DynamicRender final : public CXFA_Node {
  public:
   CXFA_DynamicRender(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_DynamicRender() override;
diff --git a/xfa/fxfa/parser/cxfa_edge.cpp b/xfa/fxfa/parser/cxfa_edge.cpp
index 65e599c..36ca7b9 100644
--- a/xfa/fxfa/parser/cxfa_edge.cpp
+++ b/xfa/fxfa/parser/cxfa_edge.cpp
@@ -6,28 +6,28 @@
 
 #include "xfa/fxfa/parser/cxfa_edge.h"
 
-#include "fxjs/xfa/cjx_edge.h"
+#include "fxjs/xfa/cjx_node.h"
 #include "third_party/base/ptr_util.h"
 
 namespace {
 
-const CXFA_Node::PropertyData kPropertyData[] = {{XFA_Element::Color, 1, 0},
-                                                 {XFA_Element::Extras, 1, 0},
-                                                 {XFA_Element::Unknown, 0, 0}};
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::PropertyData kEdgePropertyData[] = {
+    {XFA_Element::Color, 1, 0},
+    {XFA_Element::Extras, 1, 0},
+};
+
+const CXFA_Node::AttributeData kEdgeAttributeData[] = {
     {XFA_Attribute::Id, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Cap, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::Square},
+     (void*)XFA_AttributeValue::Square},
     {XFA_Attribute::Use, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Stroke, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::Solid},
+     (void*)XFA_AttributeValue::Solid},
     {XFA_Attribute::Presence, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::Visible},
+     (void*)XFA_AttributeValue::Visible},
     {XFA_Attribute::Thickness, XFA_AttributeType::Measure, (void*)L"0.5pt"},
     {XFA_Attribute::Usehref, XFA_AttributeType::CData, nullptr},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"edge";
+};
 
 }  // namespace
 
@@ -37,9 +37,8 @@
                   (XFA_XDPPACKET_Template | XFA_XDPPACKET_Form),
                   XFA_ObjectType::Node,
                   XFA_Element::Edge,
-                  kPropertyData,
-                  kAttributeData,
-                  kName,
-                  pdfium::MakeUnique<CJX_Edge>(this)) {}
+                  kEdgePropertyData,
+                  kEdgeAttributeData,
+                  pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_Edge::~CXFA_Edge() {}
+CXFA_Edge::~CXFA_Edge() = default;
diff --git a/xfa/fxfa/parser/cxfa_edge.h b/xfa/fxfa/parser/cxfa_edge.h
index 36fee55..79c7f14 100644
--- a/xfa/fxfa/parser/cxfa_edge.h
+++ b/xfa/fxfa/parser/cxfa_edge.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_stroke.h"
 
-class CXFA_Edge : public CXFA_Stroke {
+class CXFA_Edge final : public CXFA_Stroke {
  public:
   static constexpr FX_ARGB kDefaultColor = 0xFF000000;
 
diff --git a/xfa/fxfa/parser/cxfa_effectiveinputpolicy.cpp b/xfa/fxfa/parser/cxfa_effectiveinputpolicy.cpp
index a2c5d0f..f2f210d 100644
--- a/xfa/fxfa/parser/cxfa_effectiveinputpolicy.cpp
+++ b/xfa/fxfa/parser/cxfa_effectiveinputpolicy.cpp
@@ -6,16 +6,17 @@
 
 #include "xfa/fxfa/parser/cxfa_effectiveinputpolicy.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kEffectiveInputPolicyAttributeData[] = {
     {XFA_Attribute::Id, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Name, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Use, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Usehref, XFA_AttributeType::CData, nullptr},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"effectiveInputPolicy";
+};
 
 }  // namespace
 
@@ -26,8 +27,8 @@
                 XFA_XDPPACKET_ConnectionSet,
                 XFA_ObjectType::Node,
                 XFA_Element::EffectiveInputPolicy,
-                nullptr,
-                kAttributeData,
-                kName) {}
+                {},
+                kEffectiveInputPolicyAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_EffectiveInputPolicy::~CXFA_EffectiveInputPolicy() {}
+CXFA_EffectiveInputPolicy::~CXFA_EffectiveInputPolicy() = default;
diff --git a/xfa/fxfa/parser/cxfa_effectiveinputpolicy.h b/xfa/fxfa/parser/cxfa_effectiveinputpolicy.h
index 52a60a4..4f4fb8e 100644
--- a/xfa/fxfa/parser/cxfa_effectiveinputpolicy.h
+++ b/xfa/fxfa/parser/cxfa_effectiveinputpolicy.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_EffectiveInputPolicy : public CXFA_Node {
+class CXFA_EffectiveInputPolicy final : public CXFA_Node {
  public:
   CXFA_EffectiveInputPolicy(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_EffectiveInputPolicy() override;
diff --git a/xfa/fxfa/parser/cxfa_effectiveoutputpolicy.cpp b/xfa/fxfa/parser/cxfa_effectiveoutputpolicy.cpp
index e1ab370..43e07ff 100644
--- a/xfa/fxfa/parser/cxfa_effectiveoutputpolicy.cpp
+++ b/xfa/fxfa/parser/cxfa_effectiveoutputpolicy.cpp
@@ -6,16 +6,17 @@
 
 #include "xfa/fxfa/parser/cxfa_effectiveoutputpolicy.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kEffectiveOutputPolicyAttributeData[] = {
     {XFA_Attribute::Id, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Name, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Use, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Usehref, XFA_AttributeType::CData, nullptr},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"effectiveOutputPolicy";
+};
 
 }  // namespace
 
@@ -26,8 +27,8 @@
                 XFA_XDPPACKET_ConnectionSet,
                 XFA_ObjectType::Node,
                 XFA_Element::EffectiveOutputPolicy,
-                nullptr,
-                kAttributeData,
-                kName) {}
+                {},
+                kEffectiveOutputPolicyAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_EffectiveOutputPolicy::~CXFA_EffectiveOutputPolicy() {}
+CXFA_EffectiveOutputPolicy::~CXFA_EffectiveOutputPolicy() = default;
diff --git a/xfa/fxfa/parser/cxfa_effectiveoutputpolicy.h b/xfa/fxfa/parser/cxfa_effectiveoutputpolicy.h
index b2317d5..9b15a47 100644
--- a/xfa/fxfa/parser/cxfa_effectiveoutputpolicy.h
+++ b/xfa/fxfa/parser/cxfa_effectiveoutputpolicy.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_EffectiveOutputPolicy : public CXFA_Node {
+class CXFA_EffectiveOutputPolicy final : public CXFA_Node {
  public:
   CXFA_EffectiveOutputPolicy(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_EffectiveOutputPolicy() override;
diff --git a/xfa/fxfa/parser/cxfa_embed.cpp b/xfa/fxfa/parser/cxfa_embed.cpp
index f65fea4..0941b19 100644
--- a/xfa/fxfa/parser/cxfa_embed.cpp
+++ b/xfa/fxfa/parser/cxfa_embed.cpp
@@ -6,14 +6,15 @@
 
 #include "xfa/fxfa/parser/cxfa_embed.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kEmbedAttributeData[] = {
     {XFA_Attribute::Desc, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Lock, XFA_AttributeType::Integer, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"embed";
+};
 
 }  // namespace
 
@@ -23,8 +24,8 @@
                 XFA_XDPPACKET_Config,
                 XFA_ObjectType::ContentNode,
                 XFA_Element::Embed,
-                nullptr,
-                kAttributeData,
-                kName) {}
+                {},
+                kEmbedAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_Embed::~CXFA_Embed() {}
+CXFA_Embed::~CXFA_Embed() = default;
diff --git a/xfa/fxfa/parser/cxfa_embed.h b/xfa/fxfa/parser/cxfa_embed.h
index d130840..8772b30 100644
--- a/xfa/fxfa/parser/cxfa_embed.h
+++ b/xfa/fxfa/parser/cxfa_embed.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Embed : public CXFA_Node {
+class CXFA_Embed final : public CXFA_Node {
  public:
   CXFA_Embed(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Embed() override;
diff --git a/xfa/fxfa/parser/cxfa_encoding.cpp b/xfa/fxfa/parser/cxfa_encoding.cpp
index 303221a..a9330d6 100644
--- a/xfa/fxfa/parser/cxfa_encoding.cpp
+++ b/xfa/fxfa/parser/cxfa_encoding.cpp
@@ -6,18 +6,16 @@
 
 #include "xfa/fxfa/parser/cxfa_encoding.h"
 
-#include "fxjs/xfa/cjx_encoding.h"
+#include "fxjs/xfa/cjx_node.h"
 #include "third_party/base/ptr_util.h"
 
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kEncodingAttributeData[] = {
     {XFA_Attribute::Id, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Use, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Usehref, XFA_AttributeType::CData, nullptr},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"encoding";
+};
 
 }  // namespace
 
@@ -27,9 +25,8 @@
                 (XFA_XDPPACKET_Template | XFA_XDPPACKET_Form),
                 XFA_ObjectType::NodeC,
                 XFA_Element::Encoding,
-                nullptr,
-                kAttributeData,
-                kName,
-                pdfium::MakeUnique<CJX_Encoding>(this)) {}
+                {},
+                kEncodingAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_Encoding::~CXFA_Encoding() {}
+CXFA_Encoding::~CXFA_Encoding() = default;
diff --git a/xfa/fxfa/parser/cxfa_encoding.h b/xfa/fxfa/parser/cxfa_encoding.h
index ad41b01..b98ea21 100644
--- a/xfa/fxfa/parser/cxfa_encoding.h
+++ b/xfa/fxfa/parser/cxfa_encoding.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Encoding : public CXFA_Node {
+class CXFA_Encoding final : public CXFA_Node {
  public:
   CXFA_Encoding(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Encoding() override;
diff --git a/xfa/fxfa/parser/cxfa_encodings.cpp b/xfa/fxfa/parser/cxfa_encodings.cpp
index c0df2d6..939cb53 100644
--- a/xfa/fxfa/parser/cxfa_encodings.cpp
+++ b/xfa/fxfa/parser/cxfa_encodings.cpp
@@ -6,20 +6,18 @@
 
 #include "xfa/fxfa/parser/cxfa_encodings.h"
 
-#include "fxjs/xfa/cjx_encodings.h"
+#include "fxjs/xfa/cjx_node.h"
 #include "third_party/base/ptr_util.h"
 
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kEncodingsAttributeData[] = {
     {XFA_Attribute::Id, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Use, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Type, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::Optional},
+     (void*)XFA_AttributeValue::Optional},
     {XFA_Attribute::Usehref, XFA_AttributeType::CData, nullptr},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"encodings";
+};
 
 }  // namespace
 
@@ -29,9 +27,8 @@
                 (XFA_XDPPACKET_Template | XFA_XDPPACKET_Form),
                 XFA_ObjectType::Node,
                 XFA_Element::Encodings,
-                nullptr,
-                kAttributeData,
-                kName,
-                pdfium::MakeUnique<CJX_Encodings>(this)) {}
+                {},
+                kEncodingsAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_Encodings::~CXFA_Encodings() {}
+CXFA_Encodings::~CXFA_Encodings() = default;
diff --git a/xfa/fxfa/parser/cxfa_encodings.h b/xfa/fxfa/parser/cxfa_encodings.h
index d3876de..3e8de09 100644
--- a/xfa/fxfa/parser/cxfa_encodings.h
+++ b/xfa/fxfa/parser/cxfa_encodings.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Encodings : public CXFA_Node {
+class CXFA_Encodings final : public CXFA_Node {
  public:
   CXFA_Encodings(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Encodings() override;
diff --git a/xfa/fxfa/parser/cxfa_encrypt.cpp b/xfa/fxfa/parser/cxfa_encrypt.cpp
index 6ddf941..baef9ad 100644
--- a/xfa/fxfa/parser/cxfa_encrypt.cpp
+++ b/xfa/fxfa/parser/cxfa_encrypt.cpp
@@ -11,18 +11,17 @@
 
 namespace {
 
-const CXFA_Node::PropertyData kPropertyData[] = {
+const CXFA_Node::PropertyData kEncryptPropertyData[] = {
     {XFA_Element::Certificate, 1, 0},
-    {XFA_Element::Unknown, 0, 0}};
-const CXFA_Node::AttributeData kAttributeData[] = {
+};
+
+const CXFA_Node::AttributeData kEncryptAttributeData[] = {
     {XFA_Attribute::Id, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Use, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Usehref, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Desc, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Lock, XFA_AttributeType::Integer, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"encrypt";
+};
 
 }  // namespace
 
@@ -33,9 +32,8 @@
           (XFA_XDPPACKET_Template | XFA_XDPPACKET_Config | XFA_XDPPACKET_Form),
           XFA_ObjectType::ContentNode,
           XFA_Element::Encrypt,
-          kPropertyData,
-          kAttributeData,
-          kName,
+          kEncryptPropertyData,
+          kEncryptAttributeData,
           pdfium::MakeUnique<CJX_Encrypt>(this)) {}
 
-CXFA_Encrypt::~CXFA_Encrypt() {}
+CXFA_Encrypt::~CXFA_Encrypt() = default;
diff --git a/xfa/fxfa/parser/cxfa_encrypt.h b/xfa/fxfa/parser/cxfa_encrypt.h
index 4968db6..afb74b4 100644
--- a/xfa/fxfa/parser/cxfa_encrypt.h
+++ b/xfa/fxfa/parser/cxfa_encrypt.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Encrypt : public CXFA_Node {
+class CXFA_Encrypt final : public CXFA_Node {
  public:
   CXFA_Encrypt(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Encrypt() override;
diff --git a/xfa/fxfa/parser/cxfa_encryption.cpp b/xfa/fxfa/parser/cxfa_encryption.cpp
index 2a876fe..e730770 100644
--- a/xfa/fxfa/parser/cxfa_encryption.cpp
+++ b/xfa/fxfa/parser/cxfa_encryption.cpp
@@ -6,19 +6,21 @@
 
 #include "xfa/fxfa/parser/cxfa_encryption.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::PropertyData kPropertyData[] = {
+const CXFA_Node::PropertyData kEncryptionPropertyData[] = {
     {XFA_Element::EncryptionLevel, 1, 0},
     {XFA_Element::Encrypt, 1, 0},
     {XFA_Element::Permissions, 1, 0},
-    {XFA_Element::Unknown, 0, 0}};
-const CXFA_Node::AttributeData kAttributeData[] = {
+};
+
+const CXFA_Node::AttributeData kEncryptionAttributeData[] = {
     {XFA_Attribute::Desc, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Lock, XFA_AttributeType::Integer, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"encryption";
+};
 
 }  // namespace
 
@@ -28,8 +30,8 @@
                 XFA_XDPPACKET_Config,
                 XFA_ObjectType::Node,
                 XFA_Element::Encryption,
-                kPropertyData,
-                kAttributeData,
-                kName) {}
+                kEncryptionPropertyData,
+                kEncryptionAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_Encryption::~CXFA_Encryption() {}
+CXFA_Encryption::~CXFA_Encryption() = default;
diff --git a/xfa/fxfa/parser/cxfa_encryption.h b/xfa/fxfa/parser/cxfa_encryption.h
index f2028ee..1bcf48f 100644
--- a/xfa/fxfa/parser/cxfa_encryption.h
+++ b/xfa/fxfa/parser/cxfa_encryption.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Encryption : public CXFA_Node {
+class CXFA_Encryption final : public CXFA_Node {
  public:
   CXFA_Encryption(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Encryption() override;
diff --git a/xfa/fxfa/parser/cxfa_encryptionlevel.cpp b/xfa/fxfa/parser/cxfa_encryptionlevel.cpp
index 099b035..b9a182f 100644
--- a/xfa/fxfa/parser/cxfa_encryptionlevel.cpp
+++ b/xfa/fxfa/parser/cxfa_encryptionlevel.cpp
@@ -6,14 +6,15 @@
 
 #include "xfa/fxfa/parser/cxfa_encryptionlevel.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kEncryptionLevelAttributeData[] = {
     {XFA_Attribute::Desc, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Lock, XFA_AttributeType::Integer, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"encryptionLevel";
+};
 
 }  // namespace
 
@@ -24,8 +25,8 @@
                 XFA_XDPPACKET_Config,
                 XFA_ObjectType::ContentNode,
                 XFA_Element::EncryptionLevel,
-                nullptr,
-                kAttributeData,
-                kName) {}
+                {},
+                kEncryptionLevelAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_EncryptionLevel::~CXFA_EncryptionLevel() {}
+CXFA_EncryptionLevel::~CXFA_EncryptionLevel() = default;
diff --git a/xfa/fxfa/parser/cxfa_encryptionlevel.h b/xfa/fxfa/parser/cxfa_encryptionlevel.h
index 1bb80ce..faf300b 100644
--- a/xfa/fxfa/parser/cxfa_encryptionlevel.h
+++ b/xfa/fxfa/parser/cxfa_encryptionlevel.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_EncryptionLevel : public CXFA_Node {
+class CXFA_EncryptionLevel final : public CXFA_Node {
  public:
   CXFA_EncryptionLevel(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_EncryptionLevel() override;
diff --git a/xfa/fxfa/parser/cxfa_encryptionmethod.cpp b/xfa/fxfa/parser/cxfa_encryptionmethod.cpp
index e3402e2..4cad94c 100644
--- a/xfa/fxfa/parser/cxfa_encryptionmethod.cpp
+++ b/xfa/fxfa/parser/cxfa_encryptionmethod.cpp
@@ -6,15 +6,16 @@
 
 #include "xfa/fxfa/parser/cxfa_encryptionmethod.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kEncryptionMethodAttributeData[] = {
     {XFA_Attribute::Id, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Use, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Usehref, XFA_AttributeType::CData, nullptr},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"encryptionMethod";
+};
 
 }  // namespace
 
@@ -25,8 +26,8 @@
                 (XFA_XDPPACKET_Template | XFA_XDPPACKET_Form),
                 XFA_ObjectType::NodeC,
                 XFA_Element::EncryptionMethod,
-                nullptr,
-                kAttributeData,
-                kName) {}
+                {},
+                kEncryptionMethodAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_EncryptionMethod::~CXFA_EncryptionMethod() {}
+CXFA_EncryptionMethod::~CXFA_EncryptionMethod() = default;
diff --git a/xfa/fxfa/parser/cxfa_encryptionmethod.h b/xfa/fxfa/parser/cxfa_encryptionmethod.h
index 2c86001..cae708f 100644
--- a/xfa/fxfa/parser/cxfa_encryptionmethod.h
+++ b/xfa/fxfa/parser/cxfa_encryptionmethod.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_EncryptionMethod : public CXFA_Node {
+class CXFA_EncryptionMethod final : public CXFA_Node {
  public:
   CXFA_EncryptionMethod(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_EncryptionMethod() override;
diff --git a/xfa/fxfa/parser/cxfa_encryptionmethods.cpp b/xfa/fxfa/parser/cxfa_encryptionmethods.cpp
index e412031..806cd75 100644
--- a/xfa/fxfa/parser/cxfa_encryptionmethods.cpp
+++ b/xfa/fxfa/parser/cxfa_encryptionmethods.cpp
@@ -6,17 +6,18 @@
 
 #include "xfa/fxfa/parser/cxfa_encryptionmethods.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kEncryptionMethodsAttributeData[] = {
     {XFA_Attribute::Id, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Use, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Type, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::Optional},
+     (void*)XFA_AttributeValue::Optional},
     {XFA_Attribute::Usehref, XFA_AttributeType::CData, nullptr},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"encryptionMethods";
+};
 
 }  // namespace
 
@@ -27,8 +28,8 @@
                 (XFA_XDPPACKET_Template | XFA_XDPPACKET_Form),
                 XFA_ObjectType::Node,
                 XFA_Element::EncryptionMethods,
-                nullptr,
-                kAttributeData,
-                kName) {}
+                {},
+                kEncryptionMethodsAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_EncryptionMethods::~CXFA_EncryptionMethods() {}
+CXFA_EncryptionMethods::~CXFA_EncryptionMethods() = default;
diff --git a/xfa/fxfa/parser/cxfa_encryptionmethods.h b/xfa/fxfa/parser/cxfa_encryptionmethods.h
index 9fcc0b5..825ee9f 100644
--- a/xfa/fxfa/parser/cxfa_encryptionmethods.h
+++ b/xfa/fxfa/parser/cxfa_encryptionmethods.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_EncryptionMethods : public CXFA_Node {
+class CXFA_EncryptionMethods final : public CXFA_Node {
  public:
   CXFA_EncryptionMethods(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_EncryptionMethods() override;
diff --git a/xfa/fxfa/parser/cxfa_enforce.cpp b/xfa/fxfa/parser/cxfa_enforce.cpp
index 59b6426..f8ce4a0 100644
--- a/xfa/fxfa/parser/cxfa_enforce.cpp
+++ b/xfa/fxfa/parser/cxfa_enforce.cpp
@@ -6,14 +6,15 @@
 
 #include "xfa/fxfa/parser/cxfa_enforce.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kEnforceAttributeData[] = {
     {XFA_Attribute::Desc, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Lock, XFA_AttributeType::Integer, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"enforce";
+};
 
 }  // namespace
 
@@ -23,8 +24,8 @@
                 XFA_XDPPACKET_Config,
                 XFA_ObjectType::ContentNode,
                 XFA_Element::Enforce,
-                nullptr,
-                kAttributeData,
-                kName) {}
+                {},
+                kEnforceAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_Enforce::~CXFA_Enforce() {}
+CXFA_Enforce::~CXFA_Enforce() = default;
diff --git a/xfa/fxfa/parser/cxfa_enforce.h b/xfa/fxfa/parser/cxfa_enforce.h
index 3ccd8b8..ec7d745 100644
--- a/xfa/fxfa/parser/cxfa_enforce.h
+++ b/xfa/fxfa/parser/cxfa_enforce.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Enforce : public CXFA_Node {
+class CXFA_Enforce final : public CXFA_Node {
  public:
   CXFA_Enforce(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Enforce() override;
diff --git a/xfa/fxfa/parser/cxfa_equate.cpp b/xfa/fxfa/parser/cxfa_equate.cpp
index e927fbc..52a4108 100644
--- a/xfa/fxfa/parser/cxfa_equate.cpp
+++ b/xfa/fxfa/parser/cxfa_equate.cpp
@@ -6,17 +6,18 @@
 
 #include "xfa/fxfa/parser/cxfa_equate.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kEquateAttributeData[] = {
     {XFA_Attribute::To, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Force, XFA_AttributeType::Boolean, nullptr},
     {XFA_Attribute::Desc, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::From, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Lock, XFA_AttributeType::Integer, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"equate";
+};
 
 }  // namespace
 
@@ -26,8 +27,8 @@
                 XFA_XDPPACKET_Config,
                 XFA_ObjectType::NodeV,
                 XFA_Element::Equate,
-                nullptr,
-                kAttributeData,
-                kName) {}
+                {},
+                kEquateAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_Equate::~CXFA_Equate() {}
+CXFA_Equate::~CXFA_Equate() = default;
diff --git a/xfa/fxfa/parser/cxfa_equate.h b/xfa/fxfa/parser/cxfa_equate.h
index 0a28182..fc1f8d6 100644
--- a/xfa/fxfa/parser/cxfa_equate.h
+++ b/xfa/fxfa/parser/cxfa_equate.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Equate : public CXFA_Node {
+class CXFA_Equate final : public CXFA_Node {
  public:
   CXFA_Equate(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Equate() override;
diff --git a/xfa/fxfa/parser/cxfa_equaterange.cpp b/xfa/fxfa/parser/cxfa_equaterange.cpp
index 6f46a1f..4398c24 100644
--- a/xfa/fxfa/parser/cxfa_equaterange.cpp
+++ b/xfa/fxfa/parser/cxfa_equaterange.cpp
@@ -6,17 +6,18 @@
 
 #include "xfa/fxfa/parser/cxfa_equaterange.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kEquateRangeAttributeData[] = {
     {XFA_Attribute::To, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::UnicodeRange, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Desc, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::From, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Lock, XFA_AttributeType::Integer, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"equateRange";
+};
 
 }  // namespace
 
@@ -26,8 +27,8 @@
                 XFA_XDPPACKET_Config,
                 XFA_ObjectType::NodeV,
                 XFA_Element::EquateRange,
-                nullptr,
-                kAttributeData,
-                kName) {}
+                {},
+                kEquateRangeAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_EquateRange::~CXFA_EquateRange() {}
+CXFA_EquateRange::~CXFA_EquateRange() = default;
diff --git a/xfa/fxfa/parser/cxfa_equaterange.h b/xfa/fxfa/parser/cxfa_equaterange.h
index 86c86b1..56f05e1 100644
--- a/xfa/fxfa/parser/cxfa_equaterange.h
+++ b/xfa/fxfa/parser/cxfa_equaterange.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_EquateRange : public CXFA_Node {
+class CXFA_EquateRange final : public CXFA_Node {
  public:
   CXFA_EquateRange(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_EquateRange() override;
diff --git a/xfa/fxfa/parser/cxfa_era.cpp b/xfa/fxfa/parser/cxfa_era.cpp
index 6051676..1cb8df2 100644
--- a/xfa/fxfa/parser/cxfa_era.cpp
+++ b/xfa/fxfa/parser/cxfa_era.cpp
@@ -6,11 +6,8 @@
 
 #include "xfa/fxfa/parser/cxfa_era.h"
 
-namespace {
-
-constexpr wchar_t kName[] = L"era";
-
-}  // namespace
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
 
 CXFA_Era::CXFA_Era(CXFA_Document* doc, XFA_PacketType packet)
     : CXFA_Node(doc,
@@ -18,8 +15,8 @@
                 XFA_XDPPACKET_LocaleSet,
                 XFA_ObjectType::ContentNode,
                 XFA_Element::Era,
-                nullptr,
-                nullptr,
-                kName) {}
+                {},
+                {},
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_Era::~CXFA_Era() {}
+CXFA_Era::~CXFA_Era() = default;
diff --git a/xfa/fxfa/parser/cxfa_era.h b/xfa/fxfa/parser/cxfa_era.h
index a46a574..e0ecdf7 100644
--- a/xfa/fxfa/parser/cxfa_era.h
+++ b/xfa/fxfa/parser/cxfa_era.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Era : public CXFA_Node {
+class CXFA_Era final : public CXFA_Node {
  public:
   CXFA_Era(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Era() override;
diff --git a/xfa/fxfa/parser/cxfa_eranames.cpp b/xfa/fxfa/parser/cxfa_eranames.cpp
index 06bd2ca..391c5fa 100644
--- a/xfa/fxfa/parser/cxfa_eranames.cpp
+++ b/xfa/fxfa/parser/cxfa_eranames.cpp
@@ -6,12 +6,14 @@
 
 #include "xfa/fxfa/parser/cxfa_eranames.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::PropertyData kPropertyData[] = {{XFA_Element::Era, 2, 0},
-                                                 {XFA_Element::Unknown, 0, 0}};
-
-constexpr wchar_t kName[] = L"eraNames";
+const CXFA_Node::PropertyData kEraNamesPropertyData[] = {
+    {XFA_Element::Era, 2, 0},
+};
 
 }  // namespace
 
@@ -21,8 +23,8 @@
                 XFA_XDPPACKET_LocaleSet,
                 XFA_ObjectType::Node,
                 XFA_Element::EraNames,
-                kPropertyData,
-                nullptr,
-                kName) {}
+                kEraNamesPropertyData,
+                {},
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_EraNames::~CXFA_EraNames() {}
+CXFA_EraNames::~CXFA_EraNames() = default;
diff --git a/xfa/fxfa/parser/cxfa_eranames.h b/xfa/fxfa/parser/cxfa_eranames.h
index 4c8f788..468b658 100644
--- a/xfa/fxfa/parser/cxfa_eranames.h
+++ b/xfa/fxfa/parser/cxfa_eranames.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_EraNames : public CXFA_Node {
+class CXFA_EraNames final : public CXFA_Node {
  public:
   CXFA_EraNames(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_EraNames() override;
diff --git a/xfa/fxfa/parser/cxfa_event.cpp b/xfa/fxfa/parser/cxfa_event.cpp
index d4af2ff..0b109c1 100644
--- a/xfa/fxfa/parser/cxfa_event.cpp
+++ b/xfa/fxfa/parser/cxfa_event.cpp
@@ -6,33 +6,32 @@
 
 #include "xfa/fxfa/parser/cxfa_event.h"
 
-#include "fxjs/xfa/cjx_event.h"
+#include "fxjs/xfa/cjx_node.h"
 #include "third_party/base/ptr_util.h"
 #include "xfa/fxfa/parser/cxfa_script.h"
 #include "xfa/fxfa/parser/cxfa_submit.h"
 
 namespace {
 
-const CXFA_Node::PropertyData kPropertyData[] = {
+const CXFA_Node::PropertyData kEventPropertyData[] = {
     {XFA_Element::Execute, 1, XFA_PROPERTYFLAG_OneOf},
     {XFA_Element::Script, 1, XFA_PROPERTYFLAG_OneOf},
     {XFA_Element::SignData, 1, XFA_PROPERTYFLAG_OneOf},
     {XFA_Element::Extras, 1, 0},
     {XFA_Element::Submit, 1, XFA_PROPERTYFLAG_OneOf},
-    {XFA_Element::Unknown, 0, 0}};
-const CXFA_Node::AttributeData kAttributeData[] = {
+};
+
+const CXFA_Node::AttributeData kEventAttributeData[] = {
     {XFA_Attribute::Id, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Name, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Ref, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Use, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Listen, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::RefOnly},
+     (void*)XFA_AttributeValue::RefOnly},
     {XFA_Attribute::Usehref, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Activity, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::Click},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"event";
+     (void*)XFA_AttributeValue::Click},
+};
 
 }  // namespace
 
@@ -42,14 +41,13 @@
                 (XFA_XDPPACKET_Template | XFA_XDPPACKET_Form),
                 XFA_ObjectType::Node,
                 XFA_Element::Event,
-                kPropertyData,
-                kAttributeData,
-                kName,
-                pdfium::MakeUnique<CJX_Event>(this)) {}
+                kEventPropertyData,
+                kEventAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_Event::~CXFA_Event() {}
+CXFA_Event::~CXFA_Event() = default;
 
-XFA_AttributeEnum CXFA_Event::GetActivity() {
+XFA_AttributeValue CXFA_Event::GetActivity() {
   return JSObject()->GetEnum(XFA_Attribute::Activity);
 }
 
@@ -73,6 +71,8 @@
   return GetChild<CXFA_Script>(0, XFA_Element::Script, false);
 }
 
+#ifdef PDF_XFA_ELEMENT_SUBMIT_ENABLED
 CXFA_Submit* CXFA_Event::GetSubmitIfExists() {
   return GetChild<CXFA_Submit>(0, XFA_Element::Submit, false);
 }
+#endif  // PDF_XFA_ELEMENT_SUBMIT_ENABLED
diff --git a/xfa/fxfa/parser/cxfa_event.h b/xfa/fxfa/parser/cxfa_event.h
index a410805..73da7c2 100644
--- a/xfa/fxfa/parser/cxfa_event.h
+++ b/xfa/fxfa/parser/cxfa_event.h
@@ -12,15 +12,19 @@
 class CXFA_Script;
 class CXFA_Submit;
 
-class CXFA_Event : public CXFA_Node {
+class CXFA_Event final : public CXFA_Node {
  public:
   CXFA_Event(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Event() override;
 
-  XFA_AttributeEnum GetActivity();
+  XFA_AttributeValue GetActivity();
   XFA_Element GetEventType() const;
   CXFA_Script* GetScriptIfExists();
+
+#ifdef PDF_XFA_ELEMENT_SUBMIT_ENABLED
   CXFA_Submit* GetSubmitIfExists();
+#endif  // PDF_XFA_ELEMENT_SUBMIT_ENABLED
+
   WideString GetRef();
 };
 
diff --git a/xfa/fxfa/parser/cxfa_exclgroup.cpp b/xfa/fxfa/parser/cxfa_exclgroup.cpp
index a24dc36..f662224 100644
--- a/xfa/fxfa/parser/cxfa_exclgroup.cpp
+++ b/xfa/fxfa/parser/cxfa_exclgroup.cpp
@@ -11,44 +11,44 @@
 
 namespace {
 
-const CXFA_Node::PropertyData kPropertyData[] = {
+const CXFA_Node::PropertyData kExclGroupPropertyData[] = {
     {XFA_Element::Margin, 1, 0},    {XFA_Element::Para, 1, 0},
     {XFA_Element::Border, 1, 0},    {XFA_Element::Assist, 1, 0},
     {XFA_Element::Traversal, 1, 0}, {XFA_Element::Validate, 1, 0},
     {XFA_Element::Caption, 1, 0},   {XFA_Element::Bind, 1, 0},
     {XFA_Element::Desc, 1, 0},      {XFA_Element::Calculate, 1, 0},
-    {XFA_Element::Extras, 1, 0},    {XFA_Element::Unknown, 0, 0}};
-const CXFA_Node::AttributeData kAttributeData[] = {
+    {XFA_Element::Extras, 1, 0},
+};
+
+const CXFA_Node::AttributeData kExclGroupAttributeData[] = {
     {XFA_Attribute::H, XFA_AttributeType::Measure, (void*)L"0in"},
     {XFA_Attribute::W, XFA_AttributeType::Measure, (void*)L"0in"},
     {XFA_Attribute::X, XFA_AttributeType::Measure, (void*)L"0in"},
     {XFA_Attribute::Y, XFA_AttributeType::Measure, (void*)L"0in"},
     {XFA_Attribute::Id, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::HAlign, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::Left},
+     (void*)XFA_AttributeValue::Left},
     {XFA_Attribute::Name, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Use, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Access, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::Open},
+     (void*)XFA_AttributeValue::Open},
     {XFA_Attribute::Presence, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::Visible},
+     (void*)XFA_AttributeValue::Visible},
     {XFA_Attribute::VAlign, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::Top},
+     (void*)XFA_AttributeValue::Top},
     {XFA_Attribute::MaxH, XFA_AttributeType::Measure, (void*)L"0in"},
     {XFA_Attribute::MaxW, XFA_AttributeType::Measure, (void*)L"0in"},
     {XFA_Attribute::MinH, XFA_AttributeType::Measure, (void*)L"0in"},
     {XFA_Attribute::MinW, XFA_AttributeType::Measure, (void*)L"0in"},
     {XFA_Attribute::Layout, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::Position},
+     (void*)XFA_AttributeValue::Position},
     {XFA_Attribute::Relevant, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::ColSpan, XFA_AttributeType::Integer, (void*)1},
     {XFA_Attribute::Usehref, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::AnchorType, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::TopLeft},
+     (void*)XFA_AttributeValue::TopLeft},
     {XFA_Attribute::AccessKey, XFA_AttributeType::CData, nullptr},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"exclGroup";
+};
 
 }  // namespace
 
@@ -58,9 +58,8 @@
                 (XFA_XDPPACKET_Template | XFA_XDPPACKET_Form),
                 XFA_ObjectType::ContainerNode,
                 XFA_Element::ExclGroup,
-                kPropertyData,
-                kAttributeData,
-                kName,
+                kExclGroupPropertyData,
+                kExclGroupAttributeData,
                 pdfium::MakeUnique<CJX_ExclGroup>(this)) {}
 
-CXFA_ExclGroup::~CXFA_ExclGroup() {}
+CXFA_ExclGroup::~CXFA_ExclGroup() = default;
diff --git a/xfa/fxfa/parser/cxfa_exclgroup.h b/xfa/fxfa/parser/cxfa_exclgroup.h
index 5a3c8a3..390bb4a 100644
--- a/xfa/fxfa/parser/cxfa_exclgroup.h
+++ b/xfa/fxfa/parser/cxfa_exclgroup.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_ExclGroup : public CXFA_Node {
+class CXFA_ExclGroup final : public CXFA_Node {
  public:
   CXFA_ExclGroup(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_ExclGroup() override;
diff --git a/xfa/fxfa/parser/cxfa_exclude.cpp b/xfa/fxfa/parser/cxfa_exclude.cpp
index e07d92a..006831e 100644
--- a/xfa/fxfa/parser/cxfa_exclude.cpp
+++ b/xfa/fxfa/parser/cxfa_exclude.cpp
@@ -6,14 +6,15 @@
 
 #include "xfa/fxfa/parser/cxfa_exclude.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kExcludeAttributeData[] = {
     {XFA_Attribute::Desc, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Lock, XFA_AttributeType::Integer, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"exclude";
+};
 
 }  // namespace
 
@@ -23,8 +24,8 @@
                 XFA_XDPPACKET_Config,
                 XFA_ObjectType::ContentNode,
                 XFA_Element::Exclude,
-                nullptr,
-                kAttributeData,
-                kName) {}
+                {},
+                kExcludeAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_Exclude::~CXFA_Exclude() {}
+CXFA_Exclude::~CXFA_Exclude() = default;
diff --git a/xfa/fxfa/parser/cxfa_exclude.h b/xfa/fxfa/parser/cxfa_exclude.h
index 0f78707..71f08fd 100644
--- a/xfa/fxfa/parser/cxfa_exclude.h
+++ b/xfa/fxfa/parser/cxfa_exclude.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Exclude : public CXFA_Node {
+class CXFA_Exclude final : public CXFA_Node {
  public:
   CXFA_Exclude(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Exclude() override;
diff --git a/xfa/fxfa/parser/cxfa_excludens.cpp b/xfa/fxfa/parser/cxfa_excludens.cpp
index b149e86..0d47359 100644
--- a/xfa/fxfa/parser/cxfa_excludens.cpp
+++ b/xfa/fxfa/parser/cxfa_excludens.cpp
@@ -6,14 +6,15 @@
 
 #include "xfa/fxfa/parser/cxfa_excludens.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kExcludeNSAttributeData[] = {
     {XFA_Attribute::Desc, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Lock, XFA_AttributeType::Integer, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"excludeNS";
+};
 
 }  // namespace
 
@@ -23,8 +24,8 @@
                 XFA_XDPPACKET_Config,
                 XFA_ObjectType::NodeV,
                 XFA_Element::ExcludeNS,
-                nullptr,
-                kAttributeData,
-                kName) {}
+                {},
+                kExcludeNSAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_ExcludeNS::~CXFA_ExcludeNS() {}
+CXFA_ExcludeNS::~CXFA_ExcludeNS() = default;
diff --git a/xfa/fxfa/parser/cxfa_excludens.h b/xfa/fxfa/parser/cxfa_excludens.h
index c5cb548..9ce2e69 100644
--- a/xfa/fxfa/parser/cxfa_excludens.h
+++ b/xfa/fxfa/parser/cxfa_excludens.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_ExcludeNS : public CXFA_Node {
+class CXFA_ExcludeNS final : public CXFA_Node {
  public:
   CXFA_ExcludeNS(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_ExcludeNS() override;
diff --git a/xfa/fxfa/parser/cxfa_exdata.cpp b/xfa/fxfa/parser/cxfa_exdata.cpp
index cf57796..1c2e856 100644
--- a/xfa/fxfa/parser/cxfa_exdata.cpp
+++ b/xfa/fxfa/parser/cxfa_exdata.cpp
@@ -6,25 +6,23 @@
 
 #include "xfa/fxfa/parser/cxfa_exdata.h"
 
-#include "fxjs/xfa/cjx_exdata.h"
+#include "fxjs/xfa/cjx_object.h"
 #include "third_party/base/ptr_util.h"
 
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kExDataAttributeData[] = {
     {XFA_Attribute::Id, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Name, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Rid, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Use, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::ContentType, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::TransferEncoding, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::None},
+     (void*)XFA_AttributeValue::None},
     {XFA_Attribute::Usehref, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::MaxLength, XFA_AttributeType::Integer, (void*)-1},
     {XFA_Attribute::Href, XFA_AttributeType::CData, nullptr},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"exData";
+};
 
 }  // namespace
 
@@ -34,12 +32,11 @@
                 (XFA_XDPPACKET_Template | XFA_XDPPACKET_Form),
                 XFA_ObjectType::ContentNode,
                 XFA_Element::ExData,
-                nullptr,
-                kAttributeData,
-                kName,
-                pdfium::MakeUnique<CJX_ExData>(this)) {}
+                {},
+                kExDataAttributeData,
+                pdfium::MakeUnique<CJX_Object>(this)) {}
 
-CXFA_ExData::~CXFA_ExData() {}
+CXFA_ExData::~CXFA_ExData() = default;
 
 void CXFA_ExData::SetContentType(const WideString& wsContentType) {
   JSObject()->SetCData(XFA_Attribute::ContentType, wsContentType, false, false);
diff --git a/xfa/fxfa/parser/cxfa_exdata.h b/xfa/fxfa/parser/cxfa_exdata.h
index 8eb3caf..8adf028 100644
--- a/xfa/fxfa/parser/cxfa_exdata.h
+++ b/xfa/fxfa/parser/cxfa_exdata.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_ExData : public CXFA_Node {
+class CXFA_ExData final : public CXFA_Node {
  public:
   CXFA_ExData(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_ExData() override;
diff --git a/xfa/fxfa/parser/cxfa_execute.cpp b/xfa/fxfa/parser/cxfa_execute.cpp
index 4196e8f..c89bd70 100644
--- a/xfa/fxfa/parser/cxfa_execute.cpp
+++ b/xfa/fxfa/parser/cxfa_execute.cpp
@@ -6,23 +6,21 @@
 
 #include "xfa/fxfa/parser/cxfa_execute.h"
 
-#include "fxjs/xfa/cjx_execute.h"
+#include "fxjs/xfa/cjx_node.h"
 #include "third_party/base/ptr_util.h"
 
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kExecuteAttributeData[] = {
     {XFA_Attribute::Id, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Use, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Connection, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::RunAt, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::Client},
+     (void*)XFA_AttributeValue::Client},
     {XFA_Attribute::ExecuteType, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::Import},
+     (void*)XFA_AttributeValue::Import},
     {XFA_Attribute::Usehref, XFA_AttributeType::CData, nullptr},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"execute";
+};
 
 }  // namespace
 
@@ -32,9 +30,8 @@
                 (XFA_XDPPACKET_Template | XFA_XDPPACKET_Form),
                 XFA_ObjectType::Node,
                 XFA_Element::Execute,
-                nullptr,
-                kAttributeData,
-                kName,
-                pdfium::MakeUnique<CJX_Execute>(this)) {}
+                {},
+                kExecuteAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_Execute::~CXFA_Execute() {}
+CXFA_Execute::~CXFA_Execute() = default;
diff --git a/xfa/fxfa/parser/cxfa_execute.h b/xfa/fxfa/parser/cxfa_execute.h
index 2d9f158..63fd18b 100644
--- a/xfa/fxfa/parser/cxfa_execute.h
+++ b/xfa/fxfa/parser/cxfa_execute.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Execute : public CXFA_Node {
+class CXFA_Execute final : public CXFA_Node {
  public:
   CXFA_Execute(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Execute() override;
diff --git a/xfa/fxfa/parser/cxfa_exobject.cpp b/xfa/fxfa/parser/cxfa_exobject.cpp
index fff1d2e..86a7409 100644
--- a/xfa/fxfa/parser/cxfa_exobject.cpp
+++ b/xfa/fxfa/parser/cxfa_exobject.cpp
@@ -6,14 +6,16 @@
 
 #include "xfa/fxfa/parser/cxfa_exobject.h"
 
-#include "fxjs/xfa/cjx_exobject.h"
+#include "fxjs/xfa/cjx_node.h"
 #include "third_party/base/ptr_util.h"
 
 namespace {
 
-const CXFA_Node::PropertyData kPropertyData[] = {{XFA_Element::Extras, 1, 0},
-                                                 {XFA_Element::Unknown, 0, 0}};
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::PropertyData kExObjectPropertyData[] = {
+    {XFA_Element::Extras, 1, 0},
+};
+
+const CXFA_Node::AttributeData kExObjectAttributeData[] = {
     {XFA_Attribute::Id, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Name, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Use, XFA_AttributeType::CData, nullptr},
@@ -22,9 +24,7 @@
     {XFA_Attribute::Usehref, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::CodeBase, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::ClassId, XFA_AttributeType::CData, nullptr},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"exObject";
+};
 
 }  // namespace
 
@@ -34,9 +34,8 @@
                 (XFA_XDPPACKET_Template | XFA_XDPPACKET_Form),
                 XFA_ObjectType::Node,
                 XFA_Element::ExObject,
-                kPropertyData,
-                kAttributeData,
-                kName,
-                pdfium::MakeUnique<CJX_ExObject>(this)) {}
+                kExObjectPropertyData,
+                kExObjectAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_ExObject::~CXFA_ExObject() {}
+CXFA_ExObject::~CXFA_ExObject() = default;
diff --git a/xfa/fxfa/parser/cxfa_exobject.h b/xfa/fxfa/parser/cxfa_exobject.h
index b4d7de9..79ffdb9 100644
--- a/xfa/fxfa/parser/cxfa_exobject.h
+++ b/xfa/fxfa/parser/cxfa_exobject.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_ExObject : public CXFA_Node {
+class CXFA_ExObject final : public CXFA_Node {
  public:
   CXFA_ExObject(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_ExObject() override;
diff --git a/xfa/fxfa/parser/cxfa_extras.cpp b/xfa/fxfa/parser/cxfa_extras.cpp
index 4609e6f..b23a689 100644
--- a/xfa/fxfa/parser/cxfa_extras.cpp
+++ b/xfa/fxfa/parser/cxfa_extras.cpp
@@ -11,14 +11,12 @@
 
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kExtrasAttributeData[] = {
     {XFA_Attribute::Id, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Name, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Use, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Usehref, XFA_AttributeType::CData, nullptr},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"extras";
+};
 
 }  // namespace
 
@@ -29,9 +27,8 @@
                  XFA_XDPPACKET_Form),
                 XFA_ObjectType::Node,
                 XFA_Element::Extras,
-                nullptr,
-                kAttributeData,
-                kName,
+                {},
+                kExtrasAttributeData,
                 pdfium::MakeUnique<CJX_Extras>(this)) {}
 
-CXFA_Extras::~CXFA_Extras() {}
+CXFA_Extras::~CXFA_Extras() = default;
diff --git a/xfa/fxfa/parser/cxfa_extras.h b/xfa/fxfa/parser/cxfa_extras.h
index 3b3c6b4..82108d0 100644
--- a/xfa/fxfa/parser/cxfa_extras.h
+++ b/xfa/fxfa/parser/cxfa_extras.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Extras : public CXFA_Node {
+class CXFA_Extras final : public CXFA_Node {
  public:
   CXFA_Extras(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Extras() override;
diff --git a/xfa/fxfa/parser/cxfa_field.cpp b/xfa/fxfa/parser/cxfa_field.cpp
index 56b8d59..e33dfa4 100644
--- a/xfa/fxfa/parser/cxfa_field.cpp
+++ b/xfa/fxfa/parser/cxfa_field.cpp
@@ -11,7 +11,7 @@
 
 namespace {
 
-const CXFA_Node::PropertyData kPropertyData[] = {
+const CXFA_Node::PropertyData kFieldPropertyData[] = {
     {XFA_Element::Ui, 1, 0},        {XFA_Element::Margin, 1, 0},
     {XFA_Element::Para, 1, 0},      {XFA_Element::Format, 1, 0},
     {XFA_Element::Border, 1, 0},    {XFA_Element::Assist, 1, 0},
@@ -20,24 +20,26 @@
     {XFA_Element::Bind, 1, 0},      {XFA_Element::Desc, 1, 0},
     {XFA_Element::Font, 1, 0},      {XFA_Element::Value, 1, 0},
     {XFA_Element::Calculate, 1, 0}, {XFA_Element::Extras, 1, 0},
-    {XFA_Element::Items, 2, 0},     {XFA_Element::Unknown, 0, 0}};
-const CXFA_Node::AttributeData kAttributeData[] = {
+    {XFA_Element::Items, 2, 0},
+};
+
+const CXFA_Node::AttributeData kFieldAttributeData[] = {
     {XFA_Attribute::H, XFA_AttributeType::Measure, (void*)L"0in"},
     {XFA_Attribute::W, XFA_AttributeType::Measure, (void*)L"0in"},
     {XFA_Attribute::X, XFA_AttributeType::Measure, (void*)L"0in"},
     {XFA_Attribute::Y, XFA_AttributeType::Measure, (void*)L"0in"},
     {XFA_Attribute::Id, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::HAlign, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::Left},
+     (void*)XFA_AttributeValue::Left},
     {XFA_Attribute::Name, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Use, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Access, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::Open},
+     (void*)XFA_AttributeValue::Open},
     {XFA_Attribute::Rotate, XFA_AttributeType::Integer, (void*)0},
     {XFA_Attribute::Presence, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::Visible},
+     (void*)XFA_AttributeValue::Visible},
     {XFA_Attribute::VAlign, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::Top},
+     (void*)XFA_AttributeValue::Top},
     {XFA_Attribute::MaxH, XFA_AttributeType::Measure, (void*)L"0in"},
     {XFA_Attribute::MaxW, XFA_AttributeType::Measure, (void*)L"0in"},
     {XFA_Attribute::MinH, XFA_AttributeType::Measure, (void*)L"0in"},
@@ -47,11 +49,9 @@
     {XFA_Attribute::Usehref, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Locale, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::AnchorType, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::TopLeft},
+     (void*)XFA_AttributeValue::TopLeft},
     {XFA_Attribute::AccessKey, XFA_AttributeType::CData, nullptr},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"field";
+};
 
 }  // namespace
 
@@ -61,9 +61,8 @@
                 (XFA_XDPPACKET_Template | XFA_XDPPACKET_Form),
                 XFA_ObjectType::ContainerNode,
                 XFA_Element::Field,
-                kPropertyData,
-                kAttributeData,
-                kName,
+                kFieldPropertyData,
+                kFieldAttributeData,
                 pdfium::MakeUnique<CJX_Field>(this)) {}
 
-CXFA_Field::~CXFA_Field() {}
+CXFA_Field::~CXFA_Field() = default;
diff --git a/xfa/fxfa/parser/cxfa_field.h b/xfa/fxfa/parser/cxfa_field.h
index b2f7a05..e29cdd7 100644
--- a/xfa/fxfa/parser/cxfa_field.h
+++ b/xfa/fxfa/parser/cxfa_field.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Field : public CXFA_Node {
+class CXFA_Field final : public CXFA_Node {
  public:
   CXFA_Field(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Field() override;
diff --git a/xfa/fxfa/parser/cxfa_fill.cpp b/xfa/fxfa/parser/cxfa_fill.cpp
index 4cbd8f8..5bc8b02 100644
--- a/xfa/fxfa/parser/cxfa_fill.cpp
+++ b/xfa/fxfa/parser/cxfa_fill.cpp
@@ -6,7 +6,8 @@
 
 #include "xfa/fxfa/parser/cxfa_fill.h"
 
-#include "fxjs/xfa/cjx_fill.h"
+#include "core/fxge/render_defines.h"
+#include "fxjs/xfa/cjx_node.h"
 #include "third_party/base/ptr_util.h"
 #include "xfa/fxfa/parser/cxfa_color.h"
 #include "xfa/fxfa/parser/cxfa_linear.h"
@@ -17,7 +18,7 @@
 
 namespace {
 
-const CXFA_Node::PropertyData kPropertyData[] = {
+const CXFA_Node::PropertyData kFillPropertyData[] = {
     {XFA_Element::Pattern, 1, XFA_PROPERTYFLAG_OneOf},
     {XFA_Element::Solid, 1,
      XFA_PROPERTYFLAG_OneOf | XFA_PROPERTYFLAG_DefaultOneOf},
@@ -26,16 +27,15 @@
     {XFA_Element::Linear, 1, XFA_PROPERTYFLAG_OneOf},
     {XFA_Element::Extras, 1, 0},
     {XFA_Element::Radial, 1, XFA_PROPERTYFLAG_OneOf},
-    {XFA_Element::Unknown, 0, 0}};
-const CXFA_Node::AttributeData kAttributeData[] = {
+};
+
+const CXFA_Node::AttributeData kFillAttributeData[] = {
     {XFA_Attribute::Id, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Use, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Presence, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::Visible},
+     (void*)XFA_AttributeValue::Visible},
     {XFA_Attribute::Usehref, XFA_AttributeType::CData, nullptr},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"fill";
+};
 
 }  // namespace
 
@@ -45,18 +45,17 @@
                 (XFA_XDPPACKET_Template | XFA_XDPPACKET_Form),
                 XFA_ObjectType::Node,
                 XFA_Element::Fill,
-                kPropertyData,
-                kAttributeData,
-                kName,
-                pdfium::MakeUnique<CJX_Fill>(this)) {}
+                kFillPropertyData,
+                kFillAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_Fill::~CXFA_Fill() {}
+CXFA_Fill::~CXFA_Fill() = default;
 
 bool CXFA_Fill::IsVisible() {
   return JSObject()
              ->TryEnum(XFA_Attribute::Presence, true)
-             .value_or(XFA_AttributeEnum::Visible) ==
-         XFA_AttributeEnum::Visible;
+             .value_or(XFA_AttributeValue::Visible) ==
+         XFA_AttributeValue::Visible;
 }
 
 void CXFA_Fill::SetColor(FX_ARGB color) {
diff --git a/xfa/fxfa/parser/cxfa_fill.h b/xfa/fxfa/parser/cxfa_fill.h
index 1ffdcdf..05fede9 100644
--- a/xfa/fxfa/parser/cxfa_fill.h
+++ b/xfa/fxfa/parser/cxfa_fill.h
@@ -18,7 +18,7 @@
 class CXFA_Radial;
 class CXFA_Stipple;
 
-class CXFA_Fill : public CXFA_Node {
+class CXFA_Fill final : public CXFA_Node {
  public:
   CXFA_Fill(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Fill() override;
diff --git a/xfa/fxfa/parser/cxfa_filter.cpp b/xfa/fxfa/parser/cxfa_filter.cpp
index ec6522d..fdd2960 100644
--- a/xfa/fxfa/parser/cxfa_filter.cpp
+++ b/xfa/fxfa/parser/cxfa_filter.cpp
@@ -6,27 +6,27 @@
 
 #include "xfa/fxfa/parser/cxfa_filter.h"
 
-#include "fxjs/xfa/cjx_filter.h"
+#include "fxjs/xfa/cjx_node.h"
 #include "third_party/base/ptr_util.h"
 
 namespace {
 
-const CXFA_Node::PropertyData kPropertyData[] = {
+const CXFA_Node::PropertyData kFilterPropertyData[] = {
     {XFA_Element::Mdp, 1, 0},           {XFA_Element::Certificates, 1, 0},
     {XFA_Element::TimeStamp, 1, 0},     {XFA_Element::Handler, 1, 0},
     {XFA_Element::DigestMethods, 1, 0}, {XFA_Element::Encodings, 1, 0},
     {XFA_Element::Reasons, 1, 0},       {XFA_Element::AppearanceFilter, 1, 0},
-    {XFA_Element::LockDocument, 1, 0},  {XFA_Element::Unknown, 0, 0}};
-const CXFA_Node::AttributeData kAttributeData[] = {
+    {XFA_Element::LockDocument, 1, 0},
+};
+
+const CXFA_Node::AttributeData kFilterAttributeData[] = {
     {XFA_Attribute::Id, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Name, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Use, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Version, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Usehref, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::AddRevocationInfo, XFA_AttributeType::CData, nullptr},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"filter";
+};
 
 }  // namespace
 
@@ -36,9 +36,8 @@
                 (XFA_XDPPACKET_Template | XFA_XDPPACKET_Form),
                 XFA_ObjectType::Node,
                 XFA_Element::Filter,
-                kPropertyData,
-                kAttributeData,
-                kName,
-                pdfium::MakeUnique<CJX_Filter>(this)) {}
+                kFilterPropertyData,
+                kFilterAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_Filter::~CXFA_Filter() {}
+CXFA_Filter::~CXFA_Filter() = default;
diff --git a/xfa/fxfa/parser/cxfa_filter.h b/xfa/fxfa/parser/cxfa_filter.h
index 2ac069a..033d97c 100644
--- a/xfa/fxfa/parser/cxfa_filter.h
+++ b/xfa/fxfa/parser/cxfa_filter.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Filter : public CXFA_Node {
+class CXFA_Filter final : public CXFA_Node {
  public:
   CXFA_Filter(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Filter() override;
diff --git a/xfa/fxfa/parser/cxfa_fliplabel.cpp b/xfa/fxfa/parser/cxfa_fliplabel.cpp
index 2227e8b..8780e87 100644
--- a/xfa/fxfa/parser/cxfa_fliplabel.cpp
+++ b/xfa/fxfa/parser/cxfa_fliplabel.cpp
@@ -6,14 +6,15 @@
 
 #include "xfa/fxfa/parser/cxfa_fliplabel.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kFlipLabelAttributeData[] = {
     {XFA_Attribute::Desc, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Lock, XFA_AttributeType::Integer, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"flipLabel";
+};
 
 }  // namespace
 
@@ -23,8 +24,8 @@
                 XFA_XDPPACKET_Config,
                 XFA_ObjectType::NodeV,
                 XFA_Element::FlipLabel,
-                nullptr,
-                kAttributeData,
-                kName) {}
+                {},
+                kFlipLabelAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_FlipLabel::~CXFA_FlipLabel() {}
+CXFA_FlipLabel::~CXFA_FlipLabel() = default;
diff --git a/xfa/fxfa/parser/cxfa_fliplabel.h b/xfa/fxfa/parser/cxfa_fliplabel.h
index dac0564..e3f8165 100644
--- a/xfa/fxfa/parser/cxfa_fliplabel.h
+++ b/xfa/fxfa/parser/cxfa_fliplabel.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_FlipLabel : public CXFA_Node {
+class CXFA_FlipLabel final : public CXFA_Node {
  public:
   CXFA_FlipLabel(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_FlipLabel() override;
diff --git a/xfa/fxfa/parser/cxfa_float.cpp b/xfa/fxfa/parser/cxfa_float.cpp
index 83e5749..a17341f 100644
--- a/xfa/fxfa/parser/cxfa_float.cpp
+++ b/xfa/fxfa/parser/cxfa_float.cpp
@@ -6,19 +6,17 @@
 
 #include "xfa/fxfa/parser/cxfa_float.h"
 
-#include "fxjs/xfa/cjx_float.h"
+#include "fxjs/xfa/cjx_object.h"
 #include "third_party/base/ptr_util.h"
 
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kFloatAttributeData[] = {
     {XFA_Attribute::Id, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Name, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Use, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Usehref, XFA_AttributeType::CData, nullptr},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"float";
+};
 
 }  // namespace
 
@@ -28,9 +26,8 @@
                 (XFA_XDPPACKET_Template | XFA_XDPPACKET_Form),
                 XFA_ObjectType::ContentNode,
                 XFA_Element::Float,
-                nullptr,
-                kAttributeData,
-                kName,
-                pdfium::MakeUnique<CJX_Float>(this)) {}
+                {},
+                kFloatAttributeData,
+                pdfium::MakeUnique<CJX_Object>(this)) {}
 
-CXFA_Float::~CXFA_Float() {}
+CXFA_Float::~CXFA_Float() = default;
diff --git a/xfa/fxfa/parser/cxfa_float.h b/xfa/fxfa/parser/cxfa_float.h
index f93b3dd..a3fc1ae 100644
--- a/xfa/fxfa/parser/cxfa_float.h
+++ b/xfa/fxfa/parser/cxfa_float.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Float : public CXFA_Node {
+class CXFA_Float final : public CXFA_Node {
  public:
   CXFA_Float(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Float() override;
diff --git a/xfa/fxfa/parser/cxfa_font.cpp b/xfa/fxfa/parser/cxfa_font.cpp
index 694cb26..70e8426 100644
--- a/xfa/fxfa/parser/cxfa_font.cpp
+++ b/xfa/fxfa/parser/cxfa_font.cpp
@@ -6,17 +6,19 @@
 
 #include "xfa/fxfa/parser/cxfa_font.h"
 
-#include "fxjs/xfa/cjx_font.h"
+#include "fxjs/xfa/cjx_node.h"
 #include "third_party/base/ptr_util.h"
 #include "xfa/fxfa/parser/cxfa_fill.h"
 #include "xfa/fxfa/parser/cxfa_measurement.h"
 
 namespace {
 
-const CXFA_Node::PropertyData kPropertyData[] = {{XFA_Element::Fill, 1, 0},
-                                                 {XFA_Element::Extras, 1, 0},
-                                                 {XFA_Element::Unknown, 0, 0}};
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::PropertyData kFontPropertyData[] = {
+    {XFA_Element::Fill, 1, 0},
+    {XFA_Element::Extras, 1, 0},
+};
+
+const CXFA_Node::AttributeData kFontAttributeData[] = {
     {XFA_Attribute::Id, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::LineThrough, XFA_AttributeType::Integer, (void*)0},
     {XFA_Attribute::Typeface, XFA_AttributeType::CData, (void*)L"Courier"},
@@ -24,31 +26,29 @@
      (void*)L"100%"},
     {XFA_Attribute::Use, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::KerningMode, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::None},
+     (void*)XFA_AttributeValue::None},
     {XFA_Attribute::Underline, XFA_AttributeType::Integer, (void*)0},
     {XFA_Attribute::BaselineShift, XFA_AttributeType::Measure, (void*)L"0in"},
     {XFA_Attribute::OverlinePeriod, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::All},
+     (void*)XFA_AttributeValue::All},
     {XFA_Attribute::LetterSpacing, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::LineThroughPeriod, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::All},
+     (void*)XFA_AttributeValue::All},
     {XFA_Attribute::FontVerticalScale, XFA_AttributeType::CData,
      (void*)L"100%"},
     {XFA_Attribute::PsName, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Size, XFA_AttributeType::Measure, (void*)L"10pt"},
     {XFA_Attribute::Posture, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::Normal},
+     (void*)XFA_AttributeValue::Normal},
     {XFA_Attribute::Usehref, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Weight, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::Normal},
+     (void*)XFA_AttributeValue::Normal},
     {XFA_Attribute::UnderlinePeriod, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::All},
+     (void*)XFA_AttributeValue::All},
     {XFA_Attribute::Overline, XFA_AttributeType::Integer, (void*)0},
     {XFA_Attribute::GenericFamily, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::Serif},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"font";
+     (void*)XFA_AttributeValue::Serif},
+};
 
 }  // namespace
 
@@ -59,17 +59,15 @@
           (XFA_XDPPACKET_Template | XFA_XDPPACKET_Config | XFA_XDPPACKET_Form),
           XFA_ObjectType::Node,
           XFA_Element::Font,
-          kPropertyData,
-          kAttributeData,
-          kName,
-          pdfium::MakeUnique<CJX_Font>(this)) {}
+          kFontPropertyData,
+          kFontAttributeData,
+          pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_Font::~CXFA_Font() {}
+CXFA_Font::~CXFA_Font() = default;
 
 float CXFA_Font::GetBaselineShift() const {
-  return JSObject()
-      ->GetMeasure(XFA_Attribute::BaselineShift)
-      .ToUnit(XFA_Unit::Pt);
+  return JSObject()->GetMeasureInUnit(XFA_Attribute::BaselineShift,
+                                      XFA_Unit::Pt);
 }
 
 float CXFA_Font::GetHorizontalScale() {
@@ -100,14 +98,14 @@
   return JSObject()->GetInteger(XFA_Attribute::Underline);
 }
 
-XFA_AttributeEnum CXFA_Font::GetUnderlinePeriod() {
+XFA_AttributeValue CXFA_Font::GetUnderlinePeriod() {
   return JSObject()
       ->TryEnum(XFA_Attribute::UnderlinePeriod, true)
-      .value_or(XFA_AttributeEnum::All);
+      .value_or(XFA_AttributeValue::All);
 }
 
 float CXFA_Font::GetFontSize() const {
-  return JSObject()->GetMeasure(XFA_Attribute::Size).ToUnit(XFA_Unit::Pt);
+  return JSObject()->GetMeasureInUnit(XFA_Attribute::Size, XFA_Unit::Pt);
 }
 
 WideString CXFA_Font::GetTypeface() {
@@ -115,12 +113,12 @@
 }
 
 bool CXFA_Font::IsBold() {
-  return JSObject()->GetEnum(XFA_Attribute::Weight) == XFA_AttributeEnum::Bold;
+  return JSObject()->GetEnum(XFA_Attribute::Weight) == XFA_AttributeValue::Bold;
 }
 
 bool CXFA_Font::IsItalic() {
   return JSObject()->GetEnum(XFA_Attribute::Posture) ==
-         XFA_AttributeEnum::Italic;
+         XFA_AttributeValue::Italic;
 }
 
 void CXFA_Font::SetColor(FX_ARGB color) {
diff --git a/xfa/fxfa/parser/cxfa_font.h b/xfa/fxfa/parser/cxfa_font.h
index 346be76..e292ed5 100644
--- a/xfa/fxfa/parser/cxfa_font.h
+++ b/xfa/fxfa/parser/cxfa_font.h
@@ -10,7 +10,7 @@
 #include "core/fxge/fx_dib.h"
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Font : public CXFA_Node {
+class CXFA_Font final : public CXFA_Node {
  public:
   CXFA_Font(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Font() override;
@@ -21,7 +21,7 @@
   float GetLetterSpacing();
   int32_t GetLineThrough();
   int32_t GetUnderline();
-  XFA_AttributeEnum GetUnderlinePeriod();
+  XFA_AttributeValue GetUnderlinePeriod();
   float GetFontSize() const;
   WideString GetTypeface();
 
diff --git a/xfa/fxfa/parser/cxfa_fontinfo.cpp b/xfa/fxfa/parser/cxfa_fontinfo.cpp
index ee1dc6e..8ec5e93 100644
--- a/xfa/fxfa/parser/cxfa_fontinfo.cpp
+++ b/xfa/fxfa/parser/cxfa_fontinfo.cpp
@@ -6,19 +6,21 @@
 
 #include "xfa/fxfa/parser/cxfa_fontinfo.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::PropertyData kPropertyData[] = {
+const CXFA_Node::PropertyData kFontInfoPropertyData[] = {
     {XFA_Element::SubsetBelow, 1, 0},
     {XFA_Element::Map, 1, 0},
     {XFA_Element::Embed, 1, 0},
-    {XFA_Element::Unknown, 0, 0}};
-const CXFA_Node::AttributeData kAttributeData[] = {
+};
+
+const CXFA_Node::AttributeData kFontInfoAttributeData[] = {
     {XFA_Attribute::Desc, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Lock, XFA_AttributeType::Integer, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"fontInfo";
+};
 
 }  // namespace
 
@@ -28,8 +30,8 @@
                 XFA_XDPPACKET_Config,
                 XFA_ObjectType::Node,
                 XFA_Element::FontInfo,
-                kPropertyData,
-                kAttributeData,
-                kName) {}
+                kFontInfoPropertyData,
+                kFontInfoAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_FontInfo::~CXFA_FontInfo() {}
+CXFA_FontInfo::~CXFA_FontInfo() = default;
diff --git a/xfa/fxfa/parser/cxfa_fontinfo.h b/xfa/fxfa/parser/cxfa_fontinfo.h
index f9facd8..b798c55 100644
--- a/xfa/fxfa/parser/cxfa_fontinfo.h
+++ b/xfa/fxfa/parser/cxfa_fontinfo.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_FontInfo : public CXFA_Node {
+class CXFA_FontInfo final : public CXFA_Node {
  public:
   CXFA_FontInfo(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_FontInfo() override;
diff --git a/xfa/fxfa/parser/cxfa_form.cpp b/xfa/fxfa/parser/cxfa_form.cpp
index 38ce724..4586a29 100644
--- a/xfa/fxfa/parser/cxfa_form.cpp
+++ b/xfa/fxfa/parser/cxfa_form.cpp
@@ -11,11 +11,9 @@
 
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kFormAttributeData[] = {
     {XFA_Attribute::Checksum, XFA_AttributeType::CData, (void*)nullptr},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"form";
+};
 
 }  // namespace
 
@@ -25,9 +23,8 @@
                 XFA_XDPPACKET_Form,
                 XFA_ObjectType::ModelNode,
                 XFA_Element::Form,
-                nullptr,
-                kAttributeData,
-                kName,
+                {},
+                kFormAttributeData,
                 pdfium::MakeUnique<CJX_Form>(this)) {}
 
-CXFA_Form::~CXFA_Form() {}
+CXFA_Form::~CXFA_Form() = default;
diff --git a/xfa/fxfa/parser/cxfa_form.h b/xfa/fxfa/parser/cxfa_form.h
index 39d1d90..a0e2f32 100644
--- a/xfa/fxfa/parser/cxfa_form.h
+++ b/xfa/fxfa/parser/cxfa_form.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Form : public CXFA_Node {
+class CXFA_Form final : public CXFA_Node {
  public:
   CXFA_Form(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Form() override;
diff --git a/xfa/fxfa/parser/cxfa_format.cpp b/xfa/fxfa/parser/cxfa_format.cpp
index ebaaeb0..9e84a6f 100644
--- a/xfa/fxfa/parser/cxfa_format.cpp
+++ b/xfa/fxfa/parser/cxfa_format.cpp
@@ -6,21 +6,21 @@
 
 #include "xfa/fxfa/parser/cxfa_format.h"
 
-#include "fxjs/xfa/cjx_format.h"
+#include "fxjs/xfa/cjx_node.h"
 #include "third_party/base/ptr_util.h"
 
 namespace {
 
-const CXFA_Node::PropertyData kPropertyData[] = {{XFA_Element::Picture, 1, 0},
-                                                 {XFA_Element::Extras, 1, 0},
-                                                 {XFA_Element::Unknown, 0, 0}};
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::PropertyData kFormatPropertyData[] = {
+    {XFA_Element::Picture, 1, 0},
+    {XFA_Element::Extras, 1, 0},
+};
+
+const CXFA_Node::AttributeData kFormatAttributeData[] = {
     {XFA_Attribute::Id, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Use, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Usehref, XFA_AttributeType::CData, nullptr},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"format";
+};
 
 }  // namespace
 
@@ -30,9 +30,8 @@
                 (XFA_XDPPACKET_Template | XFA_XDPPACKET_Form),
                 XFA_ObjectType::Node,
                 XFA_Element::Format,
-                kPropertyData,
-                kAttributeData,
-                kName,
-                pdfium::MakeUnique<CJX_Format>(this)) {}
+                kFormatPropertyData,
+                kFormatAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_Format::~CXFA_Format() {}
+CXFA_Format::~CXFA_Format() = default;
diff --git a/xfa/fxfa/parser/cxfa_format.h b/xfa/fxfa/parser/cxfa_format.h
index 3e31716..7e74a1c 100644
--- a/xfa/fxfa/parser/cxfa_format.h
+++ b/xfa/fxfa/parser/cxfa_format.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Format : public CXFA_Node {
+class CXFA_Format final : public CXFA_Node {
  public:
   CXFA_Format(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Format() override;
diff --git a/xfa/fxfa/parser/cxfa_formfieldfilling.cpp b/xfa/fxfa/parser/cxfa_formfieldfilling.cpp
index 887e5cc..6dc5af4 100644
--- a/xfa/fxfa/parser/cxfa_formfieldfilling.cpp
+++ b/xfa/fxfa/parser/cxfa_formfieldfilling.cpp
@@ -6,14 +6,15 @@
 
 #include "xfa/fxfa/parser/cxfa_formfieldfilling.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kFormFieldFillingAttributeData[] = {
     {XFA_Attribute::Desc, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Lock, XFA_AttributeType::Integer, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"formFieldFilling";
+};
 
 }  // namespace
 
@@ -24,8 +25,8 @@
                 XFA_XDPPACKET_Config,
                 XFA_ObjectType::ContentNode,
                 XFA_Element::FormFieldFilling,
-                nullptr,
-                kAttributeData,
-                kName) {}
+                {},
+                kFormFieldFillingAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_FormFieldFilling::~CXFA_FormFieldFilling() {}
+CXFA_FormFieldFilling::~CXFA_FormFieldFilling() = default;
diff --git a/xfa/fxfa/parser/cxfa_formfieldfilling.h b/xfa/fxfa/parser/cxfa_formfieldfilling.h
index 77f1b8f..f9e7447 100644
--- a/xfa/fxfa/parser/cxfa_formfieldfilling.h
+++ b/xfa/fxfa/parser/cxfa_formfieldfilling.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_FormFieldFilling : public CXFA_Node {
+class CXFA_FormFieldFilling final : public CXFA_Node {
  public:
   CXFA_FormFieldFilling(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_FormFieldFilling() override;
diff --git a/xfa/fxfa/parser/cxfa_groupparent.cpp b/xfa/fxfa/parser/cxfa_groupparent.cpp
index ca92d3e..8dd780c 100644
--- a/xfa/fxfa/parser/cxfa_groupparent.cpp
+++ b/xfa/fxfa/parser/cxfa_groupparent.cpp
@@ -6,14 +6,15 @@
 
 #include "xfa/fxfa/parser/cxfa_groupparent.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kGroupParentAttributeData[] = {
     {XFA_Attribute::Desc, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Lock, XFA_AttributeType::Integer, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"groupParent";
+};
 
 }  // namespace
 
@@ -23,8 +24,8 @@
                 XFA_XDPPACKET_Config,
                 XFA_ObjectType::NodeV,
                 XFA_Element::GroupParent,
-                nullptr,
-                kAttributeData,
-                kName) {}
+                {},
+                kGroupParentAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_GroupParent::~CXFA_GroupParent() {}
+CXFA_GroupParent::~CXFA_GroupParent() = default;
diff --git a/xfa/fxfa/parser/cxfa_groupparent.h b/xfa/fxfa/parser/cxfa_groupparent.h
index 7de296c..eb63a6a 100644
--- a/xfa/fxfa/parser/cxfa_groupparent.h
+++ b/xfa/fxfa/parser/cxfa_groupparent.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_GroupParent : public CXFA_Node {
+class CXFA_GroupParent final : public CXFA_Node {
  public:
   CXFA_GroupParent(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_GroupParent() override;
diff --git a/xfa/fxfa/parser/cxfa_handler.cpp b/xfa/fxfa/parser/cxfa_handler.cpp
index 80f0f81..88c6ac8 100644
--- a/xfa/fxfa/parser/cxfa_handler.cpp
+++ b/xfa/fxfa/parser/cxfa_handler.cpp
@@ -11,15 +11,13 @@
 
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kHandlerAttributeData[] = {
     {XFA_Attribute::Id, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Use, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Type, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::Optional},
+     (void*)XFA_AttributeValue::Optional},
     {XFA_Attribute::Usehref, XFA_AttributeType::CData, nullptr},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"handler";
+};
 
 }  // namespace
 
@@ -29,9 +27,8 @@
                 (XFA_XDPPACKET_Template | XFA_XDPPACKET_Form),
                 XFA_ObjectType::TextNode,
                 XFA_Element::Handler,
-                nullptr,
-                kAttributeData,
-                kName,
+                {},
+                kHandlerAttributeData,
                 pdfium::MakeUnique<CJX_Handler>(this)) {}
 
-CXFA_Handler::~CXFA_Handler() {}
+CXFA_Handler::~CXFA_Handler() = default;
diff --git a/xfa/fxfa/parser/cxfa_handler.h b/xfa/fxfa/parser/cxfa_handler.h
index e575c0b..1ab1c4d 100644
--- a/xfa/fxfa/parser/cxfa_handler.h
+++ b/xfa/fxfa/parser/cxfa_handler.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Handler : public CXFA_Node {
+class CXFA_Handler final : public CXFA_Node {
  public:
   CXFA_Handler(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Handler() override;
diff --git a/xfa/fxfa/parser/cxfa_hyphenation.cpp b/xfa/fxfa/parser/cxfa_hyphenation.cpp
index 0e835ed..41d77f4 100644
--- a/xfa/fxfa/parser/cxfa_hyphenation.cpp
+++ b/xfa/fxfa/parser/cxfa_hyphenation.cpp
@@ -6,9 +6,12 @@
 
 #include "xfa/fxfa/parser/cxfa_hyphenation.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kHyphenationAttributeData[] = {
     {XFA_Attribute::Id, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Use, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::WordCharacterCount, XFA_AttributeType::Integer, (void*)7},
@@ -18,9 +21,7 @@
     {XFA_Attribute::RemainCharacterCount, XFA_AttributeType::Integer, (void*)3},
     {XFA_Attribute::Usehref, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::ExcludeAllCaps, XFA_AttributeType::Boolean, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"hyphenation";
+};
 
 }  // namespace
 
@@ -30,8 +31,8 @@
                 (XFA_XDPPACKET_Template | XFA_XDPPACKET_Form),
                 XFA_ObjectType::Node,
                 XFA_Element::Hyphenation,
-                nullptr,
-                kAttributeData,
-                kName) {}
+                {},
+                kHyphenationAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_Hyphenation::~CXFA_Hyphenation() {}
+CXFA_Hyphenation::~CXFA_Hyphenation() = default;
diff --git a/xfa/fxfa/parser/cxfa_hyphenation.h b/xfa/fxfa/parser/cxfa_hyphenation.h
index 2601c5f..77b49e9 100644
--- a/xfa/fxfa/parser/cxfa_hyphenation.h
+++ b/xfa/fxfa/parser/cxfa_hyphenation.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Hyphenation : public CXFA_Node {
+class CXFA_Hyphenation final : public CXFA_Node {
  public:
   CXFA_Hyphenation(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Hyphenation() override;
diff --git a/xfa/fxfa/parser/cxfa_ifempty.cpp b/xfa/fxfa/parser/cxfa_ifempty.cpp
index ae612ef..dc50a19 100644
--- a/xfa/fxfa/parser/cxfa_ifempty.cpp
+++ b/xfa/fxfa/parser/cxfa_ifempty.cpp
@@ -6,14 +6,15 @@
 
 #include "xfa/fxfa/parser/cxfa_ifempty.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kIfEmptyAttributeData[] = {
     {XFA_Attribute::Desc, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Lock, XFA_AttributeType::Integer, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"ifEmpty";
+};
 
 }  // namespace
 
@@ -23,8 +24,8 @@
                 XFA_XDPPACKET_Config,
                 XFA_ObjectType::NodeV,
                 XFA_Element::IfEmpty,
-                nullptr,
-                kAttributeData,
-                kName) {}
+                {},
+                kIfEmptyAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_IfEmpty::~CXFA_IfEmpty() {}
+CXFA_IfEmpty::~CXFA_IfEmpty() = default;
diff --git a/xfa/fxfa/parser/cxfa_ifempty.h b/xfa/fxfa/parser/cxfa_ifempty.h
index 3c3c1b4..401faa7 100644
--- a/xfa/fxfa/parser/cxfa_ifempty.h
+++ b/xfa/fxfa/parser/cxfa_ifempty.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_IfEmpty : public CXFA_Node {
+class CXFA_IfEmpty final : public CXFA_Node {
  public:
   CXFA_IfEmpty(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_IfEmpty() override;
diff --git a/xfa/fxfa/parser/cxfa_image.cpp b/xfa/fxfa/parser/cxfa_image.cpp
index 88ca977..fe84b11 100644
--- a/xfa/fxfa/parser/cxfa_image.cpp
+++ b/xfa/fxfa/parser/cxfa_image.cpp
@@ -6,25 +6,23 @@
 
 #include "xfa/fxfa/parser/cxfa_image.h"
 
-#include "fxjs/xfa/cjx_image.h"
+#include "fxjs/xfa/cjx_node.h"
 #include "third_party/base/ptr_util.h"
 
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kImageAttributeData[] = {
     {XFA_Attribute::Id, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Name, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Use, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::ContentType, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::TransferEncoding, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::Base64},
+     (void*)XFA_AttributeValue::Base64},
     {XFA_Attribute::Usehref, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Aspect, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::Fit},
+     (void*)XFA_AttributeValue::Fit},
     {XFA_Attribute::Href, XFA_AttributeType::CData, nullptr},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"image";
+};
 
 }  // namespace
 
@@ -34,13 +32,13 @@
                 (XFA_XDPPACKET_Template | XFA_XDPPACKET_Form),
                 XFA_ObjectType::ContentNode,
                 XFA_Element::Image,
-                nullptr,
-                kAttributeData,
-                kName) {}
+                {},
+                kImageAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_Image::~CXFA_Image() {}
+CXFA_Image::~CXFA_Image() = default;
 
-XFA_AttributeEnum CXFA_Image::GetAspect() {
+XFA_AttributeValue CXFA_Image::GetAspect() {
   return JSObject()->GetEnum(XFA_Attribute::Aspect);
 }
 
@@ -52,8 +50,8 @@
   return JSObject()->TryCData(XFA_Attribute::Href, true).value_or(L"");
 }
 
-XFA_AttributeEnum CXFA_Image::GetTransferEncoding() {
-  return static_cast<XFA_AttributeEnum>(
+XFA_AttributeValue CXFA_Image::GetTransferEncoding() {
+  return static_cast<XFA_AttributeValue>(
       JSObject()->GetEnum(XFA_Attribute::TransferEncoding));
 }
 
@@ -69,7 +67,7 @@
   JSObject()->SetCData(XFA_Attribute::Href, wsHref, false, false);
 }
 
-void CXFA_Image::SetTransferEncoding(XFA_AttributeEnum iTransferEncoding) {
+void CXFA_Image::SetTransferEncoding(XFA_AttributeValue iTransferEncoding) {
   JSObject()->SetEnum(XFA_Attribute::TransferEncoding, iTransferEncoding,
                       false);
 }
diff --git a/xfa/fxfa/parser/cxfa_image.h b/xfa/fxfa/parser/cxfa_image.h
index 3670863..62bb93a 100644
--- a/xfa/fxfa/parser/cxfa_image.h
+++ b/xfa/fxfa/parser/cxfa_image.h
@@ -9,19 +9,19 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Image : public CXFA_Node {
+class CXFA_Image final : public CXFA_Node {
  public:
   CXFA_Image(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Image() override;
 
-  XFA_AttributeEnum GetAspect();
+  XFA_AttributeValue GetAspect();
   WideString GetContent();
 
   WideString GetHref();
   void SetHref(const WideString& wsHref);
 
-  XFA_AttributeEnum GetTransferEncoding();
-  void SetTransferEncoding(XFA_AttributeEnum iTransferEncoding);
+  XFA_AttributeValue GetTransferEncoding();
+  void SetTransferEncoding(XFA_AttributeValue iTransferEncoding);
 
   WideString GetContentType();
   void SetContentType(const WideString& wsContentType);
diff --git a/xfa/fxfa/parser/cxfa_imageedit.cpp b/xfa/fxfa/parser/cxfa_imageedit.cpp
index 6f21085..5a6447e 100644
--- a/xfa/fxfa/parser/cxfa_imageedit.cpp
+++ b/xfa/fxfa/parser/cxfa_imageedit.cpp
@@ -6,24 +6,24 @@
 
 #include "xfa/fxfa/parser/cxfa_imageedit.h"
 
-#include "fxjs/xfa/cjx_imageedit.h"
+#include "fxjs/xfa/cjx_node.h"
 #include "third_party/base/ptr_util.h"
 
 namespace {
 
-const CXFA_Node::PropertyData kPropertyData[] = {{XFA_Element::Margin, 1, 0},
-                                                 {XFA_Element::Border, 1, 0},
-                                                 {XFA_Element::Extras, 1, 0},
-                                                 {XFA_Element::Unknown, 0, 0}};
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::PropertyData kImageEditPropertyData[] = {
+    {XFA_Element::Margin, 1, 0},
+    {XFA_Element::Border, 1, 0},
+    {XFA_Element::Extras, 1, 0},
+};
+
+const CXFA_Node::AttributeData kImageEditAttributeData[] = {
     {XFA_Attribute::Id, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Use, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Usehref, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Data, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::Link},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"imageEdit";
+     (void*)XFA_AttributeValue::Link},
+};
 
 }  // namespace
 
@@ -33,9 +33,16 @@
                 (XFA_XDPPACKET_Template | XFA_XDPPACKET_Form),
                 XFA_ObjectType::Node,
                 XFA_Element::ImageEdit,
-                kPropertyData,
-                kAttributeData,
-                kName,
-                pdfium::MakeUnique<CJX_ImageEdit>(this)) {}
+                kImageEditPropertyData,
+                kImageEditAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_ImageEdit::~CXFA_ImageEdit() {}
+CXFA_ImageEdit::~CXFA_ImageEdit() = default;
+
+XFA_Element CXFA_ImageEdit::GetValueNodeType() const {
+  return XFA_Element::Image;
+}
+
+XFA_FFWidgetType CXFA_ImageEdit::GetDefaultFFWidgetType() const {
+  return XFA_FFWidgetType::kImageEdit;
+}
diff --git a/xfa/fxfa/parser/cxfa_imageedit.h b/xfa/fxfa/parser/cxfa_imageedit.h
index 379750c..884c219 100644
--- a/xfa/fxfa/parser/cxfa_imageedit.h
+++ b/xfa/fxfa/parser/cxfa_imageedit.h
@@ -9,10 +9,13 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_ImageEdit : public CXFA_Node {
+class CXFA_ImageEdit final : public CXFA_Node {
  public:
   CXFA_ImageEdit(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_ImageEdit() override;
+
+  XFA_Element GetValueNodeType() const override;
+  XFA_FFWidgetType GetDefaultFFWidgetType() const override;
 };
 
 #endif  // XFA_FXFA_PARSER_CXFA_IMAGEEDIT_H_
diff --git a/xfa/fxfa/parser/cxfa_includexdpcontent.cpp b/xfa/fxfa/parser/cxfa_includexdpcontent.cpp
index dc887d3..fb9f358 100644
--- a/xfa/fxfa/parser/cxfa_includexdpcontent.cpp
+++ b/xfa/fxfa/parser/cxfa_includexdpcontent.cpp
@@ -6,14 +6,15 @@
 
 #include "xfa/fxfa/parser/cxfa_includexdpcontent.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kIncludeXDPContentAttributeData[] = {
     {XFA_Attribute::Desc, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Lock, XFA_AttributeType::Integer, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"includeXDPContent";
+};
 
 }  // namespace
 
@@ -24,8 +25,8 @@
                 XFA_XDPPACKET_Config,
                 XFA_ObjectType::ContentNode,
                 XFA_Element::IncludeXDPContent,
-                nullptr,
-                kAttributeData,
-                kName) {}
+                {},
+                kIncludeXDPContentAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_IncludeXDPContent::~CXFA_IncludeXDPContent() {}
+CXFA_IncludeXDPContent::~CXFA_IncludeXDPContent() = default;
diff --git a/xfa/fxfa/parser/cxfa_includexdpcontent.h b/xfa/fxfa/parser/cxfa_includexdpcontent.h
index 309a7c6..15c5bbe 100644
--- a/xfa/fxfa/parser/cxfa_includexdpcontent.h
+++ b/xfa/fxfa/parser/cxfa_includexdpcontent.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_IncludeXDPContent : public CXFA_Node {
+class CXFA_IncludeXDPContent final : public CXFA_Node {
  public:
   CXFA_IncludeXDPContent(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_IncludeXDPContent() override;
diff --git a/xfa/fxfa/parser/cxfa_incrementalload.cpp b/xfa/fxfa/parser/cxfa_incrementalload.cpp
index 43ba0cb..cedf559 100644
--- a/xfa/fxfa/parser/cxfa_incrementalload.cpp
+++ b/xfa/fxfa/parser/cxfa_incrementalload.cpp
@@ -6,14 +6,15 @@
 
 #include "xfa/fxfa/parser/cxfa_incrementalload.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kIncrementalLoadAttributeData[] = {
     {XFA_Attribute::Desc, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Lock, XFA_AttributeType::Integer, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"incrementalLoad";
+};
 
 }  // namespace
 
@@ -24,8 +25,8 @@
                 XFA_XDPPACKET_Config,
                 XFA_ObjectType::NodeV,
                 XFA_Element::IncrementalLoad,
-                nullptr,
-                kAttributeData,
-                kName) {}
+                {},
+                kIncrementalLoadAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_IncrementalLoad::~CXFA_IncrementalLoad() {}
+CXFA_IncrementalLoad::~CXFA_IncrementalLoad() = default;
diff --git a/xfa/fxfa/parser/cxfa_incrementalload.h b/xfa/fxfa/parser/cxfa_incrementalload.h
index 9ea8f29..253a2ae 100644
--- a/xfa/fxfa/parser/cxfa_incrementalload.h
+++ b/xfa/fxfa/parser/cxfa_incrementalload.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_IncrementalLoad : public CXFA_Node {
+class CXFA_IncrementalLoad final : public CXFA_Node {
  public:
   CXFA_IncrementalLoad(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_IncrementalLoad() override;
diff --git a/xfa/fxfa/parser/cxfa_incrementalmerge.cpp b/xfa/fxfa/parser/cxfa_incrementalmerge.cpp
index 659dd21..faf1148 100644
--- a/xfa/fxfa/parser/cxfa_incrementalmerge.cpp
+++ b/xfa/fxfa/parser/cxfa_incrementalmerge.cpp
@@ -6,14 +6,15 @@
 
 #include "xfa/fxfa/parser/cxfa_incrementalmerge.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kIncrementalMergeAttributeData[] = {
     {XFA_Attribute::Desc, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Lock, XFA_AttributeType::Integer, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"incrementalMerge";
+};
 
 }  // namespace
 
@@ -24,8 +25,8 @@
                 XFA_XDPPACKET_Config,
                 XFA_ObjectType::ContentNode,
                 XFA_Element::IncrementalMerge,
-                nullptr,
-                kAttributeData,
-                kName) {}
+                {},
+                kIncrementalMergeAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_IncrementalMerge::~CXFA_IncrementalMerge() {}
+CXFA_IncrementalMerge::~CXFA_IncrementalMerge() = default;
diff --git a/xfa/fxfa/parser/cxfa_incrementalmerge.h b/xfa/fxfa/parser/cxfa_incrementalmerge.h
index c8e6554..4ec65af 100644
--- a/xfa/fxfa/parser/cxfa_incrementalmerge.h
+++ b/xfa/fxfa/parser/cxfa_incrementalmerge.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_IncrementalMerge : public CXFA_Node {
+class CXFA_IncrementalMerge final : public CXFA_Node {
  public:
   CXFA_IncrementalMerge(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_IncrementalMerge() override;
diff --git a/xfa/fxfa/parser/cxfa_insert.cpp b/xfa/fxfa/parser/cxfa_insert.cpp
index 998a7f8..ff98c51 100644
--- a/xfa/fxfa/parser/cxfa_insert.cpp
+++ b/xfa/fxfa/parser/cxfa_insert.cpp
@@ -6,19 +6,17 @@
 
 #include "xfa/fxfa/parser/cxfa_insert.h"
 
-#include "fxjs/xfa/cjx_insert.h"
+#include "fxjs/xfa/cjx_textnode.h"
 #include "third_party/base/ptr_util.h"
 
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kInsertAttributeData[] = {
     {XFA_Attribute::Id, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Name, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Use, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Usehref, XFA_AttributeType::CData, nullptr},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"insert";
+};
 
 }  // namespace
 
@@ -28,9 +26,8 @@
                 XFA_XDPPACKET_SourceSet,
                 XFA_ObjectType::TextNode,
                 XFA_Element::Insert,
-                nullptr,
-                kAttributeData,
-                kName,
-                pdfium::MakeUnique<CJX_Insert>(this)) {}
+                {},
+                kInsertAttributeData,
+                pdfium::MakeUnique<CJX_TextNode>(this)) {}
 
-CXFA_Insert::~CXFA_Insert() {}
+CXFA_Insert::~CXFA_Insert() = default;
diff --git a/xfa/fxfa/parser/cxfa_insert.h b/xfa/fxfa/parser/cxfa_insert.h
index 92579c3..e157a82 100644
--- a/xfa/fxfa/parser/cxfa_insert.h
+++ b/xfa/fxfa/parser/cxfa_insert.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Insert : public CXFA_Node {
+class CXFA_Insert final : public CXFA_Node {
  public:
   CXFA_Insert(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Insert() override;
diff --git a/xfa/fxfa/parser/cxfa_instancemanager.cpp b/xfa/fxfa/parser/cxfa_instancemanager.cpp
index 1ba5499..e0d2658 100644
--- a/xfa/fxfa/parser/cxfa_instancemanager.cpp
+++ b/xfa/fxfa/parser/cxfa_instancemanager.cpp
@@ -11,13 +11,13 @@
 
 namespace {
 
-const CXFA_Node::PropertyData kPropertyData[] = {{XFA_Element::Occur, 1, 0},
-                                                 {XFA_Element::Unknown, 0, 0}};
-const CXFA_Node::AttributeData kAttributeData[] = {
-    {XFA_Attribute::Name, XFA_AttributeType::CData, nullptr},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
+const CXFA_Node::PropertyData kInstanceManagerPropertyData[] = {
+    {XFA_Element::Occur, 1, 0},
+};
 
-constexpr wchar_t kName[] = L"instanceManager";
+const CXFA_Node::AttributeData kInstanceManagerAttributeData[] = {
+    {XFA_Attribute::Name, XFA_AttributeType::CData, nullptr},
+};
 
 }  // namespace
 
@@ -28,9 +28,8 @@
                 XFA_XDPPACKET_Form,
                 XFA_ObjectType::Node,
                 XFA_Element::InstanceManager,
-                kPropertyData,
-                kAttributeData,
-                kName,
+                kInstanceManagerPropertyData,
+                kInstanceManagerAttributeData,
                 pdfium::MakeUnique<CJX_InstanceManager>(this)) {}
 
-CXFA_InstanceManager::~CXFA_InstanceManager() {}
+CXFA_InstanceManager::~CXFA_InstanceManager() = default;
diff --git a/xfa/fxfa/parser/cxfa_instancemanager.h b/xfa/fxfa/parser/cxfa_instancemanager.h
index 1910b92..3ace0e9 100644
--- a/xfa/fxfa/parser/cxfa_instancemanager.h
+++ b/xfa/fxfa/parser/cxfa_instancemanager.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_InstanceManager : public CXFA_Node {
+class CXFA_InstanceManager final : public CXFA_Node {
  public:
   CXFA_InstanceManager(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_InstanceManager() override;
diff --git a/xfa/fxfa/parser/cxfa_integer.cpp b/xfa/fxfa/parser/cxfa_integer.cpp
index bd263ab..cf48a25 100644
--- a/xfa/fxfa/parser/cxfa_integer.cpp
+++ b/xfa/fxfa/parser/cxfa_integer.cpp
@@ -6,19 +6,17 @@
 
 #include "xfa/fxfa/parser/cxfa_integer.h"
 
-#include "fxjs/xfa/cjx_integer.h"
+#include "fxjs/xfa/cjx_object.h"
 #include "third_party/base/ptr_util.h"
 
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kIntegerAttributeData[] = {
     {XFA_Attribute::Id, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Name, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Use, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Usehref, XFA_AttributeType::CData, nullptr},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"integer";
+};
 
 }  // namespace
 
@@ -29,9 +27,8 @@
                  XFA_XDPPACKET_Form),
                 XFA_ObjectType::ContentNode,
                 XFA_Element::Integer,
-                nullptr,
-                kAttributeData,
-                kName,
-                pdfium::MakeUnique<CJX_Integer>(this)) {}
+                {},
+                kIntegerAttributeData,
+                pdfium::MakeUnique<CJX_Object>(this)) {}
 
-CXFA_Integer::~CXFA_Integer() {}
+CXFA_Integer::~CXFA_Integer() = default;
diff --git a/xfa/fxfa/parser/cxfa_integer.h b/xfa/fxfa/parser/cxfa_integer.h
index 2e5631d..ac94133 100644
--- a/xfa/fxfa/parser/cxfa_integer.h
+++ b/xfa/fxfa/parser/cxfa_integer.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Integer : public CXFA_Node {
+class CXFA_Integer final : public CXFA_Node {
  public:
   CXFA_Integer(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Integer() override;
diff --git a/xfa/fxfa/parser/cxfa_interactive.cpp b/xfa/fxfa/parser/cxfa_interactive.cpp
index e68d957..a489ab3 100644
--- a/xfa/fxfa/parser/cxfa_interactive.cpp
+++ b/xfa/fxfa/parser/cxfa_interactive.cpp
@@ -6,14 +6,15 @@
 
 #include "xfa/fxfa/parser/cxfa_interactive.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kInteractiveAttributeData[] = {
     {XFA_Attribute::Desc, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Lock, XFA_AttributeType::Integer, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"interactive";
+};
 
 }  // namespace
 
@@ -23,8 +24,8 @@
                 XFA_XDPPACKET_Config,
                 XFA_ObjectType::ContentNode,
                 XFA_Element::Interactive,
-                nullptr,
-                kAttributeData,
-                kName) {}
+                {},
+                kInteractiveAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
 CXFA_Interactive::~CXFA_Interactive() {}
diff --git a/xfa/fxfa/parser/cxfa_interactive.h b/xfa/fxfa/parser/cxfa_interactive.h
index 69f2918..12db0bf 100644
--- a/xfa/fxfa/parser/cxfa_interactive.h
+++ b/xfa/fxfa/parser/cxfa_interactive.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Interactive : public CXFA_Node {
+class CXFA_Interactive final : public CXFA_Node {
  public:
   CXFA_Interactive(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Interactive() override;
diff --git a/xfa/fxfa/parser/cxfa_issuers.cpp b/xfa/fxfa/parser/cxfa_issuers.cpp
index 44c70bc..0d9f5f2 100644
--- a/xfa/fxfa/parser/cxfa_issuers.cpp
+++ b/xfa/fxfa/parser/cxfa_issuers.cpp
@@ -6,20 +6,18 @@
 
 #include "xfa/fxfa/parser/cxfa_issuers.h"
 
-#include "fxjs/xfa/cjx_issuers.h"
+#include "fxjs/xfa/cjx_node.h"
 #include "third_party/base/ptr_util.h"
 
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kIssuersAttributeData[] = {
     {XFA_Attribute::Id, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Use, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Type, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::Optional},
+     (void*)XFA_AttributeValue::Optional},
     {XFA_Attribute::Usehref, XFA_AttributeType::CData, nullptr},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"issuers";
+};
 
 }  // namespace
 
@@ -29,9 +27,8 @@
                 (XFA_XDPPACKET_Template | XFA_XDPPACKET_Form),
                 XFA_ObjectType::Node,
                 XFA_Element::Issuers,
-                nullptr,
-                kAttributeData,
-                kName,
-                pdfium::MakeUnique<CJX_Issuers>(this)) {}
+                {},
+                kIssuersAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_Issuers::~CXFA_Issuers() {}
+CXFA_Issuers::~CXFA_Issuers() = default;
diff --git a/xfa/fxfa/parser/cxfa_issuers.h b/xfa/fxfa/parser/cxfa_issuers.h
index 6b94f15..11ba8b4 100644
--- a/xfa/fxfa/parser/cxfa_issuers.h
+++ b/xfa/fxfa/parser/cxfa_issuers.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Issuers : public CXFA_Node {
+class CXFA_Issuers final : public CXFA_Node {
  public:
   CXFA_Issuers(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Issuers() override;
diff --git a/xfa/fxfa/parser/cxfa_itemlayoutprocessor.cpp b/xfa/fxfa/parser/cxfa_itemlayoutprocessor.cpp
deleted file mode 100644
index 434d7ed..0000000
--- a/xfa/fxfa/parser/cxfa_itemlayoutprocessor.cpp
+++ /dev/null
@@ -1,2843 +0,0 @@
-// Copyright 2014 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
-
-#include "xfa/fxfa/parser/cxfa_itemlayoutprocessor.h"
-
-#include <algorithm>
-#include <memory>
-#include <utility>
-#include <vector>
-
-#include "fxjs/xfa/cjx_object.h"
-#include "third_party/base/logging.h"
-#include "third_party/base/ptr_util.h"
-#include "third_party/base/stl_util.h"
-#include "xfa/fxfa/cxfa_ffnotify.h"
-#include "xfa/fxfa/parser/cxfa_containerlayoutitem.h"
-#include "xfa/fxfa/parser/cxfa_contentlayoutitem.h"
-#include "xfa/fxfa/parser/cxfa_document.h"
-#include "xfa/fxfa/parser/cxfa_keep.h"
-#include "xfa/fxfa/parser/cxfa_layoutcontext.h"
-#include "xfa/fxfa/parser/cxfa_layoutpagemgr.h"
-#include "xfa/fxfa/parser/cxfa_localemgr.h"
-#include "xfa/fxfa/parser/cxfa_margin.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_occur.h"
-#include "xfa/fxfa/parser/cxfa_para.h"
-#include "xfa/fxfa/parser/cxfa_traversestrategy_xfanode.h"
-#include "xfa/fxfa/parser/xfa_utils.h"
-
-namespace {
-
-std::vector<WideString> SeparateStringW(const wchar_t* pStr,
-                                        int32_t iStrLen,
-                                        wchar_t delimiter) {
-  std::vector<WideString> ret;
-  if (!pStr)
-    return ret;
-  if (iStrLen < 0)
-    iStrLen = wcslen(pStr);
-
-  const wchar_t* pToken = pStr;
-  const wchar_t* pEnd = pStr + iStrLen;
-  while (true) {
-    if (pStr >= pEnd || delimiter == *pStr) {
-      ret.push_back(WideString(pToken, pStr - pToken));
-      pToken = pStr + 1;
-      if (pStr >= pEnd)
-        break;
-    }
-    pStr++;
-  }
-  return ret;
-}
-
-void UpdateWidgetSize(CXFA_ContentLayoutItem* pLayoutItem,
-                      float* fWidth,
-                      float* fHeight) {
-  CXFA_Node* pNode = pLayoutItem->m_pFormNode;
-  switch (pNode->GetElementType()) {
-    case XFA_Element::Subform:
-    case XFA_Element::Area:
-    case XFA_Element::ExclGroup:
-    case XFA_Element::SubformSet: {
-      if (*fWidth < -XFA_LAYOUT_FLOAT_PERCISION)
-        *fWidth = pLayoutItem->m_sSize.width;
-      if (*fHeight < -XFA_LAYOUT_FLOAT_PERCISION)
-        *fHeight = pLayoutItem->m_sSize.height;
-      break;
-    }
-    case XFA_Element::Draw:
-    case XFA_Element::Field: {
-      pNode->GetDocument()->GetNotify()->StartFieldDrawLayout(pNode, *fWidth,
-                                                              *fHeight);
-      break;
-    }
-    default:
-      NOTREACHED();
-  }
-}
-
-CFX_SizeF CalculateContainerSpecifiedSize(CXFA_Node* pFormNode,
-                                          bool* bContainerWidthAutoSize,
-                                          bool* bContainerHeightAutoSize) {
-  *bContainerWidthAutoSize = true;
-  *bContainerHeightAutoSize = true;
-
-  XFA_Element eType = pFormNode->GetElementType();
-
-  CFX_SizeF containerSize;
-  if (eType == XFA_Element::Subform || eType == XFA_Element::ExclGroup) {
-    Optional<CXFA_Measurement> wValue =
-        pFormNode->JSObject()->TryMeasure(XFA_Attribute::W, false);
-    if (wValue && wValue->GetValue() > XFA_LAYOUT_FLOAT_PERCISION) {
-      containerSize.width = wValue->ToUnit(XFA_Unit::Pt);
-      *bContainerWidthAutoSize = false;
-    }
-
-    Optional<CXFA_Measurement> hValue =
-        pFormNode->JSObject()->TryMeasure(XFA_Attribute::H, false);
-    if (hValue && hValue->GetValue() > XFA_LAYOUT_FLOAT_PERCISION) {
-      containerSize.height = hValue->ToUnit(XFA_Unit::Pt);
-      *bContainerHeightAutoSize = false;
-    }
-  }
-
-  if (*bContainerWidthAutoSize && eType == XFA_Element::Subform) {
-    Optional<CXFA_Measurement> maxW =
-        pFormNode->JSObject()->TryMeasure(XFA_Attribute::MaxW, false);
-    if (maxW && maxW->GetValue() > XFA_LAYOUT_FLOAT_PERCISION) {
-      containerSize.width = maxW->ToUnit(XFA_Unit::Pt);
-      *bContainerWidthAutoSize = false;
-    }
-
-    Optional<CXFA_Measurement> maxH =
-        pFormNode->JSObject()->TryMeasure(XFA_Attribute::MaxH, false);
-    if (maxH && maxH->GetValue() > XFA_LAYOUT_FLOAT_PERCISION) {
-      containerSize.height = maxH->ToUnit(XFA_Unit::Pt);
-      *bContainerHeightAutoSize = false;
-    }
-  }
-  return containerSize;
-}
-
-CFX_SizeF CalculateContainerComponentSizeFromContentSize(
-    CXFA_Node* pFormNode,
-    bool bContainerWidthAutoSize,
-    float fContentCalculatedWidth,
-    bool bContainerHeightAutoSize,
-    float fContentCalculatedHeight,
-    const CFX_SizeF& currentContainerSize) {
-  CFX_SizeF componentSize = currentContainerSize;
-  CXFA_Margin* pMarginNode =
-      pFormNode->GetFirstChildByClass<CXFA_Margin>(XFA_Element::Margin);
-  if (bContainerWidthAutoSize) {
-    componentSize.width = fContentCalculatedWidth;
-    if (pMarginNode) {
-      Optional<CXFA_Measurement> leftInset =
-          pMarginNode->JSObject()->TryMeasure(XFA_Attribute::LeftInset, false);
-      if (leftInset)
-        componentSize.width += leftInset->ToUnit(XFA_Unit::Pt);
-
-      Optional<CXFA_Measurement> rightInset =
-          pMarginNode->JSObject()->TryMeasure(XFA_Attribute::RightInset, false);
-      if (rightInset)
-        componentSize.width += rightInset->ToUnit(XFA_Unit::Pt);
-    }
-  }
-
-  if (bContainerHeightAutoSize) {
-    componentSize.height = fContentCalculatedHeight;
-    if (pMarginNode) {
-      Optional<CXFA_Measurement> topInset =
-          pMarginNode->JSObject()->TryMeasure(XFA_Attribute::TopInset, false);
-      if (topInset)
-        componentSize.height += topInset->ToUnit(XFA_Unit::Pt);
-
-      Optional<CXFA_Measurement> bottomInset =
-          pMarginNode->JSObject()->TryMeasure(XFA_Attribute::BottomInset,
-                                              false);
-      if (bottomInset)
-        componentSize.height += bottomInset->ToUnit(XFA_Unit::Pt);
-    }
-  }
-  return componentSize;
-}
-
-void RelocateTableRowCells(CXFA_ContentLayoutItem* pLayoutRow,
-                           const std::vector<float>& rgSpecifiedColumnWidths,
-                           XFA_AttributeEnum eLayout) {
-  bool bContainerWidthAutoSize = true;
-  bool bContainerHeightAutoSize = true;
-  CFX_SizeF containerSize = CalculateContainerSpecifiedSize(
-      pLayoutRow->m_pFormNode, &bContainerWidthAutoSize,
-      &bContainerHeightAutoSize);
-  CXFA_Margin* pMarginNode =
-      pLayoutRow->m_pFormNode->GetFirstChildByClass<CXFA_Margin>(
-          XFA_Element::Margin);
-  float fLeftInset = 0;
-  float fTopInset = 0;
-  float fRightInset = 0;
-  float fBottomInset = 0;
-  if (pMarginNode) {
-    fLeftInset = pMarginNode->JSObject()
-                     ->GetMeasure(XFA_Attribute::LeftInset)
-                     .ToUnit(XFA_Unit::Pt);
-    fTopInset = pMarginNode->JSObject()
-                    ->GetMeasure(XFA_Attribute::TopInset)
-                    .ToUnit(XFA_Unit::Pt);
-    fRightInset = pMarginNode->JSObject()
-                      ->GetMeasure(XFA_Attribute::RightInset)
-                      .ToUnit(XFA_Unit::Pt);
-    fBottomInset = pMarginNode->JSObject()
-                       ->GetMeasure(XFA_Attribute::BottomInset)
-                       .ToUnit(XFA_Unit::Pt);
-  }
-
-  float fContentWidthLimit =
-      bContainerWidthAutoSize ? FLT_MAX
-                              : containerSize.width - fLeftInset - fRightInset;
-  float fContentCurrentHeight =
-      pLayoutRow->m_sSize.height - fTopInset - fBottomInset;
-  float fContentCalculatedWidth = 0;
-  float fContentCalculatedHeight = 0;
-  float fCurrentColX = 0;
-  int32_t nCurrentColIdx = 0;
-  bool bMetWholeRowCell = false;
-
-  for (auto* pLayoutChild =
-           static_cast<CXFA_ContentLayoutItem*>(pLayoutRow->m_pFirstChild);
-       pLayoutChild; pLayoutChild = static_cast<CXFA_ContentLayoutItem*>(
-                         pLayoutChild->m_pNextSibling)) {
-    int32_t nOriginalColSpan =
-        pLayoutChild->m_pFormNode->JSObject()->GetInteger(
-            XFA_Attribute::ColSpan);
-    int32_t nColSpan = nOriginalColSpan;
-    float fColSpanWidth = 0;
-    if (nColSpan == -1 ||
-        nCurrentColIdx + nColSpan >
-            pdfium::CollectionSize<int32_t>(rgSpecifiedColumnWidths)) {
-      nColSpan = pdfium::CollectionSize<int32_t>(rgSpecifiedColumnWidths) -
-                 nCurrentColIdx;
-    }
-    for (int32_t i = 0; i < nColSpan; i++)
-      fColSpanWidth += rgSpecifiedColumnWidths[nCurrentColIdx + i];
-
-    if (nColSpan != nOriginalColSpan) {
-      fColSpanWidth =
-          bMetWholeRowCell ? 0 : std::max(fColSpanWidth,
-                                          pLayoutChild->m_sSize.height);
-    }
-    if (nOriginalColSpan == -1)
-      bMetWholeRowCell = true;
-
-    pLayoutChild->m_sPos = CFX_PointF(fCurrentColX, 0);
-    pLayoutChild->m_sSize.width = fColSpanWidth;
-    if (!XFA_ItemLayoutProcessor_IsTakingSpace(pLayoutChild->m_pFormNode))
-      continue;
-
-    fCurrentColX += fColSpanWidth;
-    nCurrentColIdx += nColSpan;
-    float fNewHeight = bContainerHeightAutoSize ? -1 : fContentCurrentHeight;
-    UpdateWidgetSize(pLayoutChild, &fColSpanWidth, &fNewHeight);
-    pLayoutChild->m_sSize.height = fNewHeight;
-    if (bContainerHeightAutoSize) {
-      fContentCalculatedHeight =
-          std::max(fContentCalculatedHeight, pLayoutChild->m_sSize.height);
-    }
-  }
-
-  if (bContainerHeightAutoSize) {
-    for (CXFA_ContentLayoutItem* pLayoutChild =
-             (CXFA_ContentLayoutItem*)pLayoutRow->m_pFirstChild;
-         pLayoutChild;
-         pLayoutChild = (CXFA_ContentLayoutItem*)pLayoutChild->m_pNextSibling) {
-      UpdateWidgetSize(pLayoutChild, &pLayoutChild->m_sSize.width,
-                       &fContentCalculatedHeight);
-      float fOldChildHeight = pLayoutChild->m_sSize.height;
-      pLayoutChild->m_sSize.height = fContentCalculatedHeight;
-      CXFA_Para* pParaNode =
-          pLayoutChild->m_pFormNode->GetFirstChildByClass<CXFA_Para>(
-              XFA_Element::Para);
-      if (pParaNode && pLayoutChild->m_pFirstChild) {
-        float fOffHeight = fContentCalculatedHeight - fOldChildHeight;
-        XFA_AttributeEnum eVType =
-            pParaNode->JSObject()->GetEnum(XFA_Attribute::VAlign);
-        switch (eVType) {
-          case XFA_AttributeEnum::Middle:
-            fOffHeight = fOffHeight / 2;
-            break;
-          case XFA_AttributeEnum::Bottom:
-            break;
-          case XFA_AttributeEnum::Top:
-          default:
-            fOffHeight = 0;
-            break;
-        }
-        if (fOffHeight > 0) {
-          for (CXFA_ContentLayoutItem* pInnerLayoutChild =
-                   (CXFA_ContentLayoutItem*)pLayoutChild->m_pFirstChild;
-               pInnerLayoutChild;
-               pInnerLayoutChild =
-                   (CXFA_ContentLayoutItem*)pInnerLayoutChild->m_pNextSibling) {
-            pInnerLayoutChild->m_sPos.y += fOffHeight;
-          }
-        }
-      }
-    }
-  }
-
-  if (bContainerWidthAutoSize) {
-    float fChildSuppliedWidth = fCurrentColX;
-    if (fContentWidthLimit < FLT_MAX &&
-        fContentWidthLimit > fChildSuppliedWidth) {
-      fChildSuppliedWidth = fContentWidthLimit;
-    }
-    fContentCalculatedWidth =
-        std::max(fContentCalculatedWidth, fChildSuppliedWidth);
-  } else {
-    fContentCalculatedWidth = containerSize.width - fLeftInset - fRightInset;
-  }
-
-  if (pLayoutRow->m_pFormNode->JSObject()->GetEnum(XFA_Attribute::Layout) ==
-      XFA_AttributeEnum::Rl_row) {
-    for (CXFA_ContentLayoutItem* pLayoutChild =
-             (CXFA_ContentLayoutItem*)pLayoutRow->m_pFirstChild;
-         pLayoutChild;
-         pLayoutChild = (CXFA_ContentLayoutItem*)pLayoutChild->m_pNextSibling) {
-      pLayoutChild->m_sPos.x = fContentCalculatedWidth -
-                               pLayoutChild->m_sPos.x -
-                               pLayoutChild->m_sSize.width;
-    }
-  }
-  pLayoutRow->m_sSize = CalculateContainerComponentSizeFromContentSize(
-      pLayoutRow->m_pFormNode, bContainerWidthAutoSize, fContentCalculatedWidth,
-      bContainerHeightAutoSize, fContentCalculatedHeight, containerSize);
-}
-
-void UpdatePendingItemLayout(CXFA_ItemLayoutProcessor* pProcessor,
-                             CXFA_ContentLayoutItem* pLayoutItem) {
-  XFA_AttributeEnum eLayout =
-      pLayoutItem->m_pFormNode->JSObject()->GetEnum(XFA_Attribute::Layout);
-  switch (eLayout) {
-    case XFA_AttributeEnum::Row:
-    case XFA_AttributeEnum::Rl_row:
-      RelocateTableRowCells(pLayoutItem, pProcessor->m_rgSpecifiedColumnWidths,
-                            eLayout);
-      break;
-    default:
-      break;
-  }
-}
-
-void AddTrailerBeforeSplit(CXFA_ItemLayoutProcessor* pProcessor,
-                           float fSplitPos,
-                           CXFA_ContentLayoutItem* pTrailerLayoutItem,
-                           bool bUseInherited) {
-  if (!pTrailerLayoutItem)
-    return;
-
-  float fHeight = pTrailerLayoutItem->m_sSize.height;
-  if (bUseInherited) {
-    float fNewSplitPos = 0;
-    if (fSplitPos - fHeight > XFA_LAYOUT_FLOAT_PERCISION)
-      fNewSplitPos = pProcessor->FindSplitPos(fSplitPos - fHeight);
-    if (fNewSplitPos > XFA_LAYOUT_FLOAT_PERCISION)
-      pProcessor->SplitLayoutItem(fNewSplitPos);
-    return;
-  }
-
-  UpdatePendingItemLayout(pProcessor, pTrailerLayoutItem);
-  CXFA_Margin* pMarginNode =
-      pProcessor->m_pFormNode->GetFirstChildByClass<CXFA_Margin>(
-          XFA_Element::Margin);
-  float fLeftInset = 0;
-  float fTopInset = 0;
-  float fRightInset = 0;
-  float fBottomInset = 0;
-  if (pMarginNode) {
-    fLeftInset = pMarginNode->JSObject()
-                     ->GetMeasure(XFA_Attribute::LeftInset)
-                     .ToUnit(XFA_Unit::Pt);
-    fTopInset = pMarginNode->JSObject()
-                    ->GetMeasure(XFA_Attribute::TopInset)
-                    .ToUnit(XFA_Unit::Pt);
-    fRightInset = pMarginNode->JSObject()
-                      ->GetMeasure(XFA_Attribute::RightInset)
-                      .ToUnit(XFA_Unit::Pt);
-    fBottomInset = pMarginNode->JSObject()
-                       ->GetMeasure(XFA_Attribute::BottomInset)
-                       .ToUnit(XFA_Unit::Pt);
-  }
-
-  if (!pProcessor->IsAddNewRowForTrailer(pTrailerLayoutItem)) {
-    pTrailerLayoutItem->m_sPos.y = pProcessor->m_fLastRowY;
-    pTrailerLayoutItem->m_sPos.x = pProcessor->m_fLastRowWidth;
-    pProcessor->m_pLayoutItem->m_sSize.width +=
-        pTrailerLayoutItem->m_sSize.width;
-    pProcessor->m_pLayoutItem->AddChild(pTrailerLayoutItem);
-    return;
-  }
-
-  float fNewSplitPos = 0;
-  if (fSplitPos - fHeight > XFA_LAYOUT_FLOAT_PERCISION)
-    fNewSplitPos = pProcessor->FindSplitPos(fSplitPos - fHeight);
-
-  if (fNewSplitPos > XFA_LAYOUT_FLOAT_PERCISION) {
-    pProcessor->SplitLayoutItem(fNewSplitPos);
-    pTrailerLayoutItem->m_sPos.y = fNewSplitPos - fTopInset - fBottomInset;
-  } else {
-    pTrailerLayoutItem->m_sPos.y = fSplitPos - fTopInset - fBottomInset;
-  }
-
-  switch (pTrailerLayoutItem->m_pFormNode->JSObject()->GetEnum(
-      XFA_Attribute::HAlign)) {
-    case XFA_AttributeEnum::Right:
-      pTrailerLayoutItem->m_sPos.x = pProcessor->m_pLayoutItem->m_sSize.width -
-                                     fRightInset -
-                                     pTrailerLayoutItem->m_sSize.width;
-      break;
-    case XFA_AttributeEnum::Center:
-      pTrailerLayoutItem->m_sPos.x =
-          (pProcessor->m_pLayoutItem->m_sSize.width - fLeftInset - fRightInset -
-           pTrailerLayoutItem->m_sSize.width) /
-          2;
-      break;
-    case XFA_AttributeEnum::Left:
-    default:
-      pTrailerLayoutItem->m_sPos.x = fLeftInset;
-      break;
-  }
-  pProcessor->m_pLayoutItem->m_sSize.height += fHeight;
-  pProcessor->m_pLayoutItem->AddChild(pTrailerLayoutItem);
-}
-
-void AddLeaderAfterSplit(CXFA_ItemLayoutProcessor* pProcessor,
-                         CXFA_ContentLayoutItem* pLeaderLayoutItem) {
-  UpdatePendingItemLayout(pProcessor, pLeaderLayoutItem);
-
-  CXFA_Margin* pMarginNode =
-      pProcessor->m_pFormNode->GetFirstChildByClass<CXFA_Margin>(
-          XFA_Element::Margin);
-  float fLeftInset = 0;
-  float fRightInset = 0;
-  if (pMarginNode) {
-    fLeftInset = pMarginNode->JSObject()
-                     ->GetMeasure(XFA_Attribute::LeftInset)
-                     .ToUnit(XFA_Unit::Pt);
-    fRightInset = pMarginNode->JSObject()
-                      ->GetMeasure(XFA_Attribute::RightInset)
-                      .ToUnit(XFA_Unit::Pt);
-  }
-
-  float fHeight = pLeaderLayoutItem->m_sSize.height;
-  for (CXFA_ContentLayoutItem* pChildItem =
-           (CXFA_ContentLayoutItem*)pProcessor->m_pLayoutItem->m_pFirstChild;
-       pChildItem;
-       pChildItem = (CXFA_ContentLayoutItem*)pChildItem->m_pNextSibling) {
-    pChildItem->m_sPos.y += fHeight;
-  }
-  pLeaderLayoutItem->m_sPos.y = 0;
-
-  switch (pLeaderLayoutItem->m_pFormNode->JSObject()->GetEnum(
-      XFA_Attribute::HAlign)) {
-    case XFA_AttributeEnum::Right:
-      pLeaderLayoutItem->m_sPos.x = pProcessor->m_pLayoutItem->m_sSize.width -
-                                    fRightInset -
-                                    pLeaderLayoutItem->m_sSize.width;
-      break;
-    case XFA_AttributeEnum::Center:
-      pLeaderLayoutItem->m_sPos.x =
-          (pProcessor->m_pLayoutItem->m_sSize.width - fLeftInset - fRightInset -
-           pLeaderLayoutItem->m_sSize.width) /
-          2;
-      break;
-    case XFA_AttributeEnum::Left:
-    default:
-      pLeaderLayoutItem->m_sPos.x = fLeftInset;
-      break;
-  }
-  pProcessor->m_pLayoutItem->m_sSize.height += fHeight;
-  pProcessor->m_pLayoutItem->AddChild(pLeaderLayoutItem);
-}
-
-void AddPendingNode(CXFA_ItemLayoutProcessor* pProcessor,
-                    CXFA_Node* pPendingNode,
-                    bool bBreakPending) {
-  pProcessor->m_PendingNodes.push_back(pPendingNode);
-  pProcessor->m_bBreakPending = bBreakPending;
-}
-
-float InsertPendingItems(CXFA_ItemLayoutProcessor* pProcessor,
-                         CXFA_Node* pCurChildNode) {
-  float fTotalHeight = 0;
-  if (pProcessor->m_PendingNodes.empty())
-    return fTotalHeight;
-
-  if (!pProcessor->m_pLayoutItem) {
-    pProcessor->m_pLayoutItem =
-        pProcessor->CreateContentLayoutItem(pCurChildNode);
-    pProcessor->m_pLayoutItem->m_sSize.clear();
-  }
-
-  while (!pProcessor->m_PendingNodes.empty()) {
-    auto pPendingProcessor = pdfium::MakeUnique<CXFA_ItemLayoutProcessor>(
-        pProcessor->m_PendingNodes.front(), nullptr);
-    pProcessor->m_PendingNodes.pop_front();
-    pPendingProcessor->DoLayout(false, FLT_MAX, FLT_MAX, nullptr);
-    CXFA_ContentLayoutItem* pPendingLayoutItem =
-        pPendingProcessor->HasLayoutItem()
-            ? pPendingProcessor->ExtractLayoutItem()
-            : nullptr;
-    if (pPendingLayoutItem) {
-      AddLeaderAfterSplit(pProcessor, pPendingLayoutItem);
-      if (pProcessor->m_bBreakPending)
-        fTotalHeight += pPendingLayoutItem->m_sSize.height;
-    }
-  }
-  return fTotalHeight;
-}
-
-XFA_AttributeEnum GetLayout(CXFA_Node* pFormNode, bool* bRootForceTb) {
-  *bRootForceTb = false;
-  Optional<XFA_AttributeEnum> layoutMode =
-      pFormNode->JSObject()->TryEnum(XFA_Attribute::Layout, false);
-  if (layoutMode)
-    return *layoutMode;
-
-  CXFA_Node* pParentNode = pFormNode->GetParent();
-  if (pParentNode && pParentNode->GetElementType() == XFA_Element::Form) {
-    *bRootForceTb = true;
-    return XFA_AttributeEnum::Tb;
-  }
-  return XFA_AttributeEnum::Position;
-}
-
-bool ExistContainerKeep(CXFA_Node* pCurNode, bool bPreFind) {
-  if (!pCurNode || !XFA_ItemLayoutProcessor_IsTakingSpace(pCurNode))
-    return false;
-
-  CXFA_Node* pPreContainer = bPreFind ? pCurNode->GetPrevContainerSibling()
-                                      : pCurNode->GetNextContainerSibling();
-  if (!pPreContainer)
-    return false;
-
-  CXFA_Keep* pKeep =
-      pCurNode->GetFirstChildByClass<CXFA_Keep>(XFA_Element::Keep);
-  if (pKeep) {
-    XFA_Attribute eKeepType = XFA_Attribute::Previous;
-    if (!bPreFind)
-      eKeepType = XFA_Attribute::Next;
-
-    Optional<XFA_AttributeEnum> previous =
-        pKeep->JSObject()->TryEnum(eKeepType, false);
-    if (previous) {
-      if (*previous == XFA_AttributeEnum::ContentArea ||
-          *previous == XFA_AttributeEnum::PageArea) {
-        return true;
-      }
-    }
-  }
-
-  pKeep = pPreContainer->GetFirstChildByClass<CXFA_Keep>(XFA_Element::Keep);
-  if (!pKeep)
-    return false;
-
-  XFA_Attribute eKeepType = XFA_Attribute::Next;
-  if (!bPreFind)
-    eKeepType = XFA_Attribute::Previous;
-
-  Optional<XFA_AttributeEnum> next =
-      pKeep->JSObject()->TryEnum(eKeepType, false);
-  if (!next)
-    return false;
-  if (*next == XFA_AttributeEnum::ContentArea ||
-      *next == XFA_AttributeEnum::PageArea) {
-    return true;
-  }
-  return false;
-}
-
-bool FindBreakNode(CXFA_Node* pContainerNode,
-                   CXFA_Node*& pCurActionNode,
-                   XFA_ItemLayoutProcessorStages* nCurStage,
-                   bool bBreakBefore) {
-  bool bFindRs = false;
-  for (CXFA_Node* pBreakNode = pContainerNode; pBreakNode;
-       pBreakNode = pBreakNode->GetNextSibling()) {
-    XFA_Attribute eAttributeType = XFA_Attribute::Before;
-    if (!bBreakBefore)
-      eAttributeType = XFA_Attribute::After;
-
-    switch (pBreakNode->GetElementType()) {
-      case XFA_Element::BreakBefore: {
-        if (bBreakBefore) {
-          pCurActionNode = pBreakNode;
-          *nCurStage = XFA_ItemLayoutProcessorStages::BreakBefore;
-          bFindRs = true;
-        }
-        break;
-      }
-      case XFA_Element::BreakAfter: {
-        if (!bBreakBefore) {
-          pCurActionNode = pBreakNode;
-          *nCurStage = XFA_ItemLayoutProcessorStages::BreakAfter;
-          bFindRs = true;
-        }
-        break;
-      }
-      case XFA_Element::Break:
-        if (pBreakNode->JSObject()->GetEnum(eAttributeType) !=
-            XFA_AttributeEnum::Auto) {
-          pCurActionNode = pBreakNode;
-          *nCurStage = XFA_ItemLayoutProcessorStages::BreakBefore;
-          if (!bBreakBefore)
-            *nCurStage = XFA_ItemLayoutProcessorStages::BreakAfter;
-
-          bFindRs = true;
-        }
-        break;
-      default:
-        break;
-    }
-    if (bFindRs)
-      break;
-  }
-  return bFindRs;
-}
-
-void DeleteLayoutGeneratedNode(CXFA_Node* pGenerateNode) {
-  CXFA_FFNotify* pNotify = pGenerateNode->GetDocument()->GetNotify();
-  CXFA_LayoutProcessor* pDocLayout =
-      pGenerateNode->GetDocument()->GetDocLayout();
-  CXFA_NodeIteratorTemplate<CXFA_Node, CXFA_TraverseStrategy_XFANode> sIterator(
-      pGenerateNode);
-  for (CXFA_Node* pNode = sIterator.GetCurrent(); pNode;
-       pNode = sIterator.MoveToNext()) {
-    CXFA_ContentLayoutItem* pCurLayoutItem =
-        static_cast<CXFA_ContentLayoutItem*>(
-            pNode->JSObject()->GetLayoutItem());
-    CXFA_ContentLayoutItem* pNextLayoutItem = nullptr;
-    while (pCurLayoutItem) {
-      pNextLayoutItem = pCurLayoutItem->m_pNext;
-      pNotify->OnLayoutItemRemoving(pDocLayout, pCurLayoutItem);
-      delete pCurLayoutItem;
-      pCurLayoutItem = pNextLayoutItem;
-    }
-  }
-  pGenerateNode->GetParent()->RemoveChild(pGenerateNode, true);
-}
-
-uint8_t HAlignEnumToInt(XFA_AttributeEnum eHAlign) {
-  switch (eHAlign) {
-    case XFA_AttributeEnum::Center:
-      return 1;
-    case XFA_AttributeEnum::Right:
-      return 2;
-    case XFA_AttributeEnum::Left:
-    default:
-      return 0;
-  }
-}
-
-XFA_ItemLayoutProcessorResult InsertFlowedItem(
-    CXFA_ItemLayoutProcessor* pThis,
-    CXFA_ItemLayoutProcessor* pProcessor,
-    bool bContainerWidthAutoSize,
-    bool bContainerHeightAutoSize,
-    float fContainerHeight,
-    XFA_AttributeEnum eFlowStrategy,
-    uint8_t* uCurHAlignState,
-    std::vector<CXFA_ContentLayoutItem*> (&rgCurLineLayoutItems)[3],
-    bool bUseBreakControl,
-    float fAvailHeight,
-    float fRealHeight,
-    float fContentWidthLimit,
-    float* fContentCurRowY,
-    float* fContentCurRowAvailWidth,
-    float* fContentCurRowHeight,
-    bool* bAddedItemInRow,
-    bool* bForceEndPage,
-    CXFA_LayoutContext* pLayoutContext,
-    bool bNewRow) {
-  bool bTakeSpace =
-      XFA_ItemLayoutProcessor_IsTakingSpace(pProcessor->m_pFormNode);
-  uint8_t uHAlign = HAlignEnumToInt(
-      pThis->m_pCurChildNode->JSObject()->GetEnum(XFA_Attribute::HAlign));
-  if (bContainerWidthAutoSize)
-    uHAlign = 0;
-
-  if ((eFlowStrategy != XFA_AttributeEnum::Rl_tb &&
-       uHAlign < *uCurHAlignState) ||
-      (eFlowStrategy == XFA_AttributeEnum::Rl_tb &&
-       uHAlign > *uCurHAlignState)) {
-    return XFA_ItemLayoutProcessorResult::RowFullBreak;
-  }
-
-  *uCurHAlignState = uHAlign;
-  bool bIsOwnSplit =
-      pProcessor->m_pFormNode->GetIntact() == XFA_AttributeEnum::None;
-  bool bUseRealHeight = bTakeSpace && bContainerHeightAutoSize && bIsOwnSplit &&
-                        pProcessor->m_pFormNode->GetParent()->GetIntact() ==
-                            XFA_AttributeEnum::None;
-  bool bIsTransHeight = bTakeSpace;
-  if (bIsTransHeight && !bIsOwnSplit) {
-    bool bRootForceTb = false;
-    XFA_AttributeEnum eLayoutStrategy =
-        GetLayout(pProcessor->m_pFormNode, &bRootForceTb);
-    if (eLayoutStrategy == XFA_AttributeEnum::Lr_tb ||
-        eLayoutStrategy == XFA_AttributeEnum::Rl_tb) {
-      bIsTransHeight = false;
-    }
-  }
-
-  bool bUseInherited = false;
-  CXFA_LayoutContext layoutContext;
-  if (pThis->m_pPageMgr) {
-    CXFA_Node* pOverflowNode =
-        pThis->m_pPageMgr->QueryOverflow(pThis->m_pFormNode);
-    if (pOverflowNode) {
-      layoutContext.m_pOverflowNode = pOverflowNode;
-      layoutContext.m_pOverflowProcessor = pThis;
-      pLayoutContext = &layoutContext;
-    }
-  }
-
-  XFA_ItemLayoutProcessorResult eRetValue = XFA_ItemLayoutProcessorResult::Done;
-  if (!bNewRow ||
-      pProcessor->m_ePreProcessRs == XFA_ItemLayoutProcessorResult::Done) {
-    eRetValue = pProcessor->DoLayout(
-        bTakeSpace ? bUseBreakControl : false,
-        bUseRealHeight ? fRealHeight - *fContentCurRowY : FLT_MAX,
-        bIsTransHeight ? fRealHeight - *fContentCurRowY : FLT_MAX,
-        pLayoutContext);
-    pProcessor->m_ePreProcessRs = eRetValue;
-  } else {
-    eRetValue = pProcessor->m_ePreProcessRs;
-    pProcessor->m_ePreProcessRs = XFA_ItemLayoutProcessorResult::Done;
-  }
-  if (pProcessor->HasLayoutItem() == false)
-    return eRetValue;
-
-  CFX_SizeF childSize = pProcessor->GetCurrentComponentSize();
-  if (bUseRealHeight && fRealHeight < XFA_LAYOUT_FLOAT_PERCISION) {
-    fRealHeight = FLT_MAX;
-    fAvailHeight = FLT_MAX;
-  }
-  if (bTakeSpace && (childSize.width >
-                     *fContentCurRowAvailWidth + XFA_LAYOUT_FLOAT_PERCISION) &&
-      (fContentWidthLimit - *fContentCurRowAvailWidth >
-       XFA_LAYOUT_FLOAT_PERCISION)) {
-    return XFA_ItemLayoutProcessorResult::RowFullBreak;
-  }
-
-  CXFA_Node* pOverflowLeaderNode = nullptr;
-  CXFA_Node* pOverflowTrailerNode = nullptr;
-  CXFA_Node* pFormNode = nullptr;
-  CXFA_ContentLayoutItem* pTrailerLayoutItem = nullptr;
-  bool bIsAddTrailerHeight = false;
-  if (pThis->m_pPageMgr &&
-      pProcessor->m_pFormNode->GetIntact() == XFA_AttributeEnum::None) {
-    pFormNode = pThis->m_pPageMgr->QueryOverflow(pProcessor->m_pFormNode);
-    if (!pFormNode && pLayoutContext && pLayoutContext->m_pOverflowProcessor) {
-      pFormNode = pLayoutContext->m_pOverflowNode;
-      bUseInherited = true;
-    }
-    if (pThis->m_pPageMgr->ProcessOverflow(pFormNode, pOverflowLeaderNode,
-                                           pOverflowTrailerNode, false,
-                                           false)) {
-      if (pProcessor->JudgeLeaderOrTrailerForOccur(pOverflowTrailerNode)) {
-        if (pOverflowTrailerNode) {
-          auto pOverflowLeaderProcessor =
-              pdfium::MakeUnique<CXFA_ItemLayoutProcessor>(pOverflowTrailerNode,
-                                                           nullptr);
-          pOverflowLeaderProcessor->DoLayout(false, FLT_MAX, FLT_MAX, nullptr);
-          pTrailerLayoutItem =
-              pOverflowLeaderProcessor->HasLayoutItem()
-                  ? pOverflowLeaderProcessor->ExtractLayoutItem()
-                  : nullptr;
-        }
-
-        bIsAddTrailerHeight =
-            bUseInherited
-                ? pThis->IsAddNewRowForTrailer(pTrailerLayoutItem)
-                : pProcessor->IsAddNewRowForTrailer(pTrailerLayoutItem);
-        if (bIsAddTrailerHeight) {
-          childSize.height += pTrailerLayoutItem->m_sSize.height;
-          bIsAddTrailerHeight = true;
-        }
-      }
-    }
-  }
-
-  if (!bTakeSpace ||
-      *fContentCurRowY + childSize.height <=
-          fAvailHeight + XFA_LAYOUT_FLOAT_PERCISION ||
-      (!bContainerHeightAutoSize &&
-       pThis->m_fUsedSize + fAvailHeight + XFA_LAYOUT_FLOAT_PERCISION >=
-           fContainerHeight)) {
-    if (!bTakeSpace || eRetValue == XFA_ItemLayoutProcessorResult::Done) {
-      if (pProcessor->m_bUseInheriated) {
-        if (pTrailerLayoutItem)
-          AddTrailerBeforeSplit(pProcessor, childSize.height,
-                                pTrailerLayoutItem, false);
-        if (pProcessor->JudgeLeaderOrTrailerForOccur(pOverflowLeaderNode))
-          AddPendingNode(pProcessor, pOverflowLeaderNode, false);
-
-        pProcessor->m_bUseInheriated = false;
-      } else {
-        if (bIsAddTrailerHeight)
-          childSize.height -= pTrailerLayoutItem->m_sSize.height;
-
-        pProcessor->ProcessUnUseOverFlow(pOverflowLeaderNode,
-                                         pOverflowTrailerNode,
-                                         pTrailerLayoutItem, pFormNode);
-      }
-
-      CXFA_ContentLayoutItem* pChildLayoutItem =
-          pProcessor->ExtractLayoutItem();
-      if (ExistContainerKeep(pProcessor->m_pFormNode, false) &&
-          pProcessor->m_pFormNode->GetIntact() == XFA_AttributeEnum::None) {
-        pThis->m_arrayKeepItems.push_back(pChildLayoutItem);
-      } else {
-        pThis->m_arrayKeepItems.clear();
-      }
-      rgCurLineLayoutItems[uHAlign].push_back(pChildLayoutItem);
-      *bAddedItemInRow = true;
-      if (bTakeSpace) {
-        *fContentCurRowAvailWidth -= childSize.width;
-        *fContentCurRowHeight =
-            std::max(*fContentCurRowHeight, childSize.height);
-      }
-      return XFA_ItemLayoutProcessorResult::Done;
-    }
-
-    if (eRetValue == XFA_ItemLayoutProcessorResult::PageFullBreak) {
-      if (pProcessor->m_bUseInheriated) {
-        if (pTrailerLayoutItem) {
-          AddTrailerBeforeSplit(pProcessor, childSize.height,
-                                pTrailerLayoutItem, false);
-        }
-        if (pProcessor->JudgeLeaderOrTrailerForOccur(pOverflowLeaderNode))
-          AddPendingNode(pProcessor, pOverflowLeaderNode, false);
-
-        pProcessor->m_bUseInheriated = false;
-      } else {
-        if (bIsAddTrailerHeight)
-          childSize.height -= pTrailerLayoutItem->m_sSize.height;
-
-        pProcessor->ProcessUnUseOverFlow(pOverflowLeaderNode,
-                                         pOverflowTrailerNode,
-                                         pTrailerLayoutItem, pFormNode);
-      }
-    }
-    rgCurLineLayoutItems[uHAlign].push_back(pProcessor->ExtractLayoutItem());
-    *bAddedItemInRow = true;
-    *fContentCurRowAvailWidth -= childSize.width;
-    *fContentCurRowHeight = std::max(*fContentCurRowHeight, childSize.height);
-    return eRetValue;
-  }
-
-  XFA_ItemLayoutProcessorResult eResult;
-  if (pThis->ProcessKeepForSplit(
-          pThis, pProcessor, eRetValue, &rgCurLineLayoutItems[uHAlign],
-          fContentCurRowAvailWidth, fContentCurRowHeight, fContentCurRowY,
-          bAddedItemInRow, bForceEndPage, &eResult)) {
-    return eResult;
-  }
-
-  *bForceEndPage = true;
-  float fSplitPos = pProcessor->FindSplitPos(fAvailHeight - *fContentCurRowY);
-  if (fSplitPos > XFA_LAYOUT_FLOAT_PERCISION) {
-    XFA_AttributeEnum eLayout =
-        pProcessor->m_pFormNode->JSObject()->GetEnum(XFA_Attribute::Layout);
-    if (eLayout == XFA_AttributeEnum::Tb &&
-        eRetValue == XFA_ItemLayoutProcessorResult::Done) {
-      pProcessor->ProcessUnUseOverFlow(pOverflowLeaderNode,
-                                       pOverflowTrailerNode, pTrailerLayoutItem,
-                                       pFormNode);
-      rgCurLineLayoutItems[uHAlign].push_back(pProcessor->ExtractLayoutItem());
-      *bAddedItemInRow = true;
-      if (bTakeSpace) {
-        *fContentCurRowAvailWidth -= childSize.width;
-        *fContentCurRowHeight =
-            std::max(*fContentCurRowHeight, childSize.height);
-      }
-      return XFA_ItemLayoutProcessorResult::PageFullBreak;
-    }
-
-    CXFA_Node* pTempLeaderNode = nullptr;
-    CXFA_Node* pTempTrailerNode = nullptr;
-    if (pThis->m_pPageMgr && !pProcessor->m_bUseInheriated &&
-        eRetValue != XFA_ItemLayoutProcessorResult::PageFullBreak) {
-      pThis->m_pPageMgr->ProcessOverflow(pFormNode, pTempLeaderNode,
-                                         pTempTrailerNode, false, true);
-    }
-    if (pTrailerLayoutItem && bIsAddTrailerHeight) {
-      AddTrailerBeforeSplit(pProcessor, fSplitPos, pTrailerLayoutItem,
-                            bUseInherited);
-    } else {
-      pProcessor->SplitLayoutItem(fSplitPos);
-    }
-
-    if (bUseInherited) {
-      pProcessor->ProcessUnUseOverFlow(pOverflowLeaderNode,
-                                       pOverflowTrailerNode, pTrailerLayoutItem,
-                                       pFormNode);
-      pThis->m_bUseInheriated = true;
-    } else {
-      CXFA_LayoutItem* firstChild = pProcessor->m_pLayoutItem->m_pFirstChild;
-      if (firstChild && !firstChild->m_pNextSibling &&
-          firstChild->m_pFormNode->IsLayoutGeneratedNode()) {
-        pProcessor->ProcessUnUseOverFlow(pOverflowLeaderNode,
-                                         pOverflowTrailerNode,
-                                         pTrailerLayoutItem, pFormNode);
-      } else if (pProcessor->JudgeLeaderOrTrailerForOccur(
-                     pOverflowLeaderNode)) {
-        AddPendingNode(pProcessor, pOverflowLeaderNode, false);
-      }
-    }
-
-    if (pProcessor->m_pLayoutItem->m_pNextSibling) {
-      childSize = pProcessor->GetCurrentComponentSize();
-      rgCurLineLayoutItems[uHAlign].push_back(pProcessor->ExtractLayoutItem());
-      *bAddedItemInRow = true;
-      if (bTakeSpace) {
-        *fContentCurRowAvailWidth -= childSize.width;
-        *fContentCurRowHeight =
-            std::max(*fContentCurRowHeight, childSize.height);
-      }
-    }
-    return XFA_ItemLayoutProcessorResult::PageFullBreak;
-  }
-
-  if (*fContentCurRowY <= XFA_LAYOUT_FLOAT_PERCISION) {
-    childSize = pProcessor->GetCurrentComponentSize();
-    if (pProcessor->m_pPageMgr->GetNextAvailContentHeight(childSize.height)) {
-      CXFA_Node* pTempLeaderNode = nullptr;
-      CXFA_Node* pTempTrailerNode = nullptr;
-      if (pThis->m_pPageMgr) {
-        if (!pFormNode && pLayoutContext)
-          pFormNode = pLayoutContext->m_pOverflowProcessor->m_pFormNode;
-
-        pThis->m_pPageMgr->ProcessOverflow(pFormNode, pTempLeaderNode,
-                                           pTempTrailerNode, false, true);
-      }
-      if (bUseInherited) {
-        pProcessor->ProcessUnUseOverFlow(pOverflowLeaderNode,
-                                         pOverflowTrailerNode,
-                                         pTrailerLayoutItem, pFormNode);
-        pThis->m_bUseInheriated = true;
-      }
-      return XFA_ItemLayoutProcessorResult::PageFullBreak;
-    }
-
-    rgCurLineLayoutItems[uHAlign].push_back(pProcessor->ExtractLayoutItem());
-    *bAddedItemInRow = true;
-    if (bTakeSpace) {
-      *fContentCurRowAvailWidth -= childSize.width;
-      *fContentCurRowHeight = std::max(*fContentCurRowHeight, childSize.height);
-    }
-    if (eRetValue == XFA_ItemLayoutProcessorResult::Done)
-      *bForceEndPage = false;
-
-    return eRetValue;
-  }
-
-  XFA_AttributeEnum eLayout =
-      pProcessor->m_pFormNode->JSObject()->GetEnum(XFA_Attribute::Layout);
-  if (pProcessor->m_pFormNode->GetIntact() == XFA_AttributeEnum::None &&
-      eLayout == XFA_AttributeEnum::Tb) {
-    if (pThis->m_pPageMgr) {
-      pThis->m_pPageMgr->ProcessOverflow(pFormNode, pOverflowLeaderNode,
-                                         pOverflowTrailerNode, false, true);
-    }
-    if (pTrailerLayoutItem)
-      AddTrailerBeforeSplit(pProcessor, fSplitPos, pTrailerLayoutItem, false);
-    if (pProcessor->JudgeLeaderOrTrailerForOccur(pOverflowLeaderNode))
-      AddPendingNode(pProcessor, pOverflowLeaderNode, false);
-
-    return XFA_ItemLayoutProcessorResult::PageFullBreak;
-  }
-
-  if (eRetValue != XFA_ItemLayoutProcessorResult::Done)
-    return XFA_ItemLayoutProcessorResult::PageFullBreak;
-
-  if (!pFormNode && pLayoutContext)
-    pFormNode = pLayoutContext->m_pOverflowProcessor->m_pFormNode;
-  if (pThis->m_pPageMgr) {
-    pThis->m_pPageMgr->ProcessOverflow(pFormNode, pOverflowLeaderNode,
-                                       pOverflowTrailerNode, false, true);
-  }
-  if (bUseInherited) {
-    pProcessor->ProcessUnUseOverFlow(pOverflowLeaderNode, pOverflowTrailerNode,
-                                     pTrailerLayoutItem, pFormNode);
-    pThis->m_bUseInheriated = true;
-  }
-  return XFA_ItemLayoutProcessorResult::PageFullBreak;
-}
-
-bool FindLayoutItemSplitPos(CXFA_ContentLayoutItem* pLayoutItem,
-                            float fCurVerticalOffset,
-                            float* fProposedSplitPos,
-                            bool* bAppChange,
-                            bool bCalculateMargin) {
-  CXFA_Node* pFormNode = pLayoutItem->m_pFormNode;
-  if (*fProposedSplitPos <= fCurVerticalOffset + XFA_LAYOUT_FLOAT_PERCISION ||
-      *fProposedSplitPos > fCurVerticalOffset + pLayoutItem->m_sSize.height -
-                               XFA_LAYOUT_FLOAT_PERCISION) {
-    return false;
-  }
-
-  switch (pFormNode->GetIntact()) {
-    case XFA_AttributeEnum::None: {
-      bool bAnyChanged = false;
-      CXFA_Document* pDocument = pFormNode->GetDocument();
-      CXFA_FFNotify* pNotify = pDocument->GetNotify();
-      float fCurTopMargin = 0, fCurBottomMargin = 0;
-      CXFA_Margin* pMarginNode =
-          pFormNode->GetFirstChildByClass<CXFA_Margin>(XFA_Element::Margin);
-      if (pMarginNode && bCalculateMargin) {
-        fCurTopMargin = pMarginNode->JSObject()
-                            ->GetMeasure(XFA_Attribute::TopInset)
-                            .ToUnit(XFA_Unit::Pt);
-        fCurBottomMargin = pMarginNode->JSObject()
-                               ->GetMeasure(XFA_Attribute::BottomInset)
-                               .ToUnit(XFA_Unit::Pt);
-      }
-      bool bChanged = true;
-      while (bChanged) {
-        bChanged = false;
-        {
-          float fRelSplitPos = *fProposedSplitPos - fCurVerticalOffset;
-          if (pNotify->FindSplitPos(pFormNode, pLayoutItem->GetIndex(),
-                                    fRelSplitPos)) {
-            bAnyChanged = true;
-            bChanged = true;
-            *fProposedSplitPos = fCurVerticalOffset + fRelSplitPos;
-            *bAppChange = true;
-            if (*fProposedSplitPos <=
-                fCurVerticalOffset + XFA_LAYOUT_FLOAT_PERCISION) {
-              return true;
-            }
-          }
-        }
-        float fRelSplitPos = *fProposedSplitPos - fCurBottomMargin;
-        for (CXFA_ContentLayoutItem* pChildItem =
-                 (CXFA_ContentLayoutItem*)pLayoutItem->m_pFirstChild;
-             pChildItem;
-             pChildItem = (CXFA_ContentLayoutItem*)pChildItem->m_pNextSibling) {
-          float fChildOffset =
-              fCurVerticalOffset + fCurTopMargin + pChildItem->m_sPos.y;
-          bool bChange = false;
-          if (FindLayoutItemSplitPos(pChildItem, fChildOffset, &fRelSplitPos,
-                                     &bChange, bCalculateMargin)) {
-            if (fRelSplitPos - fChildOffset < XFA_LAYOUT_FLOAT_PERCISION &&
-                bChange) {
-              *fProposedSplitPos = fRelSplitPos - fCurTopMargin;
-            } else {
-              *fProposedSplitPos = fRelSplitPos + fCurBottomMargin;
-            }
-            bAnyChanged = true;
-            bChanged = true;
-            if (*fProposedSplitPos <=
-                fCurVerticalOffset + XFA_LAYOUT_FLOAT_PERCISION) {
-              return true;
-            }
-            if (bAnyChanged)
-              break;
-          }
-        }
-      }
-      return bAnyChanged;
-    }
-    case XFA_AttributeEnum::ContentArea:
-    case XFA_AttributeEnum::PageArea: {
-      *fProposedSplitPos = fCurVerticalOffset;
-      return true;
-    }
-    default:
-      return false;
-  }
-}
-
-CFX_PointF CalculatePositionedContainerPos(CXFA_Node* pNode,
-                                           const CFX_SizeF& size) {
-  XFA_AttributeEnum eAnchorType =
-      pNode->JSObject()->GetEnum(XFA_Attribute::AnchorType);
-  int32_t nAnchorType = 0;
-  switch (eAnchorType) {
-    case XFA_AttributeEnum::TopLeft:
-      nAnchorType = 0;
-      break;
-    case XFA_AttributeEnum::TopCenter:
-      nAnchorType = 1;
-      break;
-    case XFA_AttributeEnum::TopRight:
-      nAnchorType = 2;
-      break;
-    case XFA_AttributeEnum::MiddleLeft:
-      nAnchorType = 3;
-      break;
-    case XFA_AttributeEnum::MiddleCenter:
-      nAnchorType = 4;
-      break;
-    case XFA_AttributeEnum::MiddleRight:
-      nAnchorType = 5;
-      break;
-    case XFA_AttributeEnum::BottomLeft:
-      nAnchorType = 6;
-      break;
-    case XFA_AttributeEnum::BottomCenter:
-      nAnchorType = 7;
-      break;
-    case XFA_AttributeEnum::BottomRight:
-      nAnchorType = 8;
-      break;
-    default:
-      break;
-  }
-  static const uint8_t nNextPos[4][9] = {{0, 1, 2, 3, 4, 5, 6, 7, 8},
-                                         {6, 3, 0, 7, 4, 1, 8, 5, 2},
-                                         {8, 7, 6, 5, 4, 3, 2, 1, 0},
-                                         {2, 5, 8, 1, 4, 7, 0, 3, 6}};
-
-  CFX_PointF pos(
-      pNode->JSObject()->GetMeasure(XFA_Attribute::X).ToUnit(XFA_Unit::Pt),
-      pNode->JSObject()->GetMeasure(XFA_Attribute::Y).ToUnit(XFA_Unit::Pt));
-  int32_t nRotate =
-      XFA_MapRotation(pNode->JSObject()->GetInteger(XFA_Attribute::Rotate)) /
-      90;
-  int32_t nAbsoluteAnchorType = nNextPos[nRotate][nAnchorType];
-  switch (nAbsoluteAnchorType / 3) {
-    case 1:
-      pos.y -= size.height / 2;
-      break;
-    case 2:
-      pos.y -= size.height;
-      break;
-    default:
-      break;
-  }
-  switch (nAbsoluteAnchorType % 3) {
-    case 1:
-      pos.x -= size.width / 2;
-      break;
-    case 2:
-      pos.x -= size.width;
-      break;
-    default:
-      break;
-  }
-  return pos;
-}
-
-}  // namespace
-
-CXFA_ItemLayoutProcessor::CXFA_ItemLayoutProcessor(CXFA_Node* pNode,
-                                                   CXFA_LayoutPageMgr* pPageMgr)
-    : m_pFormNode(pNode),
-      m_pLayoutItem(nullptr),
-      m_pCurChildNode(XFA_LAYOUT_INVALIDNODE),
-      m_fUsedSize(0),
-      m_pPageMgr(pPageMgr),
-      m_bBreakPending(true),
-      m_fLastRowWidth(0),
-      m_fLastRowY(0),
-      m_bUseInheriated(false),
-      m_ePreProcessRs(XFA_ItemLayoutProcessorResult::Done),
-      m_bKeepBreakFinish(false),
-      m_bIsProcessKeep(false),
-      m_pKeepHeadNode(nullptr),
-      m_pKeepTailNode(nullptr),
-      m_pOldLayoutItem(nullptr),
-      m_pCurChildPreprocessor(nullptr),
-      m_nCurChildNodeStage(XFA_ItemLayoutProcessorStages::None),
-      m_fWidthLimite(0),
-      m_bHasAvailHeight(true) {
-  ASSERT(m_pFormNode && (m_pFormNode->IsContainerNode() ||
-                         m_pFormNode->GetElementType() == XFA_Element::Form));
-  m_pOldLayoutItem = static_cast<CXFA_ContentLayoutItem*>(
-      m_pFormNode->JSObject()->GetLayoutItem());
-}
-
-CXFA_ItemLayoutProcessor::~CXFA_ItemLayoutProcessor() {}
-
-CXFA_ContentLayoutItem* CXFA_ItemLayoutProcessor::CreateContentLayoutItem(
-    CXFA_Node* pFormNode) {
-  if (!pFormNode)
-    return nullptr;
-
-  CXFA_ContentLayoutItem* pLayoutItem = nullptr;
-  if (m_pOldLayoutItem) {
-    pLayoutItem = m_pOldLayoutItem;
-    m_pOldLayoutItem = m_pOldLayoutItem->m_pNext;
-    return pLayoutItem;
-  }
-  pLayoutItem =
-      pFormNode->GetDocument()->GetNotify()->OnCreateContentLayoutItem(
-          pFormNode);
-  CXFA_ContentLayoutItem* pPrevLayoutItem =
-      static_cast<CXFA_ContentLayoutItem*>(
-          pFormNode->JSObject()->GetLayoutItem());
-  if (pPrevLayoutItem) {
-    while (pPrevLayoutItem->m_pNext)
-      pPrevLayoutItem = pPrevLayoutItem->m_pNext;
-
-    pPrevLayoutItem->m_pNext = pLayoutItem;
-    pLayoutItem->m_pPrev = pPrevLayoutItem;
-  } else {
-    pFormNode->JSObject()->SetLayoutItem(pLayoutItem);
-  }
-  return pLayoutItem;
-}
-
-float CXFA_ItemLayoutProcessor::FindSplitPos(float fProposedSplitPos) {
-  ASSERT(m_pLayoutItem);
-  XFA_AttributeEnum eLayout = m_pFormNode->JSObject()
-                                  ->TryEnum(XFA_Attribute::Layout, true)
-                                  .value_or(XFA_AttributeEnum::Position);
-  bool bCalculateMargin = eLayout != XFA_AttributeEnum::Position;
-  while (fProposedSplitPos > XFA_LAYOUT_FLOAT_PERCISION) {
-    bool bAppChange = false;
-    if (!FindLayoutItemSplitPos(m_pLayoutItem, 0, &fProposedSplitPos,
-                                &bAppChange, bCalculateMargin)) {
-      break;
-    }
-  }
-  return fProposedSplitPos;
-}
-
-void CXFA_ItemLayoutProcessor::SplitLayoutItem(
-    CXFA_ContentLayoutItem* pLayoutItem,
-    CXFA_ContentLayoutItem* pSecondParent,
-    float fSplitPos) {
-  float fCurTopMargin = 0, fCurBottomMargin = 0;
-  XFA_AttributeEnum eLayout = m_pFormNode->JSObject()
-                                  ->TryEnum(XFA_Attribute::Layout, true)
-                                  .value_or(XFA_AttributeEnum::Position);
-  bool bCalculateMargin = true;
-  if (eLayout == XFA_AttributeEnum::Position)
-    bCalculateMargin = false;
-
-  CXFA_Margin* pMarginNode =
-      pLayoutItem->m_pFormNode->GetFirstChildByClass<CXFA_Margin>(
-          XFA_Element::Margin);
-  if (pMarginNode && bCalculateMargin) {
-    fCurTopMargin = pMarginNode->JSObject()
-                        ->GetMeasure(XFA_Attribute::TopInset)
-                        .ToUnit(XFA_Unit::Pt);
-    fCurBottomMargin = pMarginNode->JSObject()
-                           ->GetMeasure(XFA_Attribute::BottomInset)
-                           .ToUnit(XFA_Unit::Pt);
-  }
-
-  CXFA_ContentLayoutItem* pSecondLayoutItem = nullptr;
-  if (m_pCurChildPreprocessor &&
-      m_pCurChildPreprocessor->m_pFormNode == pLayoutItem->m_pFormNode) {
-    pSecondLayoutItem = m_pCurChildPreprocessor->CreateContentLayoutItem(
-        pLayoutItem->m_pFormNode);
-  } else {
-    pSecondLayoutItem = CreateContentLayoutItem(pLayoutItem->m_pFormNode);
-  }
-  pSecondLayoutItem->m_sPos.x = pLayoutItem->m_sPos.x;
-  pSecondLayoutItem->m_sSize.width = pLayoutItem->m_sSize.width;
-  pSecondLayoutItem->m_sPos.y = 0;
-  pSecondLayoutItem->m_sSize.height = pLayoutItem->m_sSize.height - fSplitPos;
-  pLayoutItem->m_sSize.height -= pSecondLayoutItem->m_sSize.height;
-  if (pLayoutItem->m_pFirstChild)
-    pSecondLayoutItem->m_sSize.height += fCurTopMargin;
-
-  if (pSecondParent) {
-    pSecondParent->AddChild(pSecondLayoutItem);
-    if (fCurTopMargin > 0 && pLayoutItem->m_pFirstChild) {
-      pSecondParent->m_sSize.height += fCurTopMargin;
-      CXFA_ContentLayoutItem* pParentItem =
-          (CXFA_ContentLayoutItem*)pSecondParent->m_pParent;
-      while (pParentItem) {
-        pParentItem->m_sSize.height += fCurTopMargin;
-        pParentItem = (CXFA_ContentLayoutItem*)pParentItem->m_pParent;
-      }
-    }
-  } else {
-    pSecondLayoutItem->m_pParent = pLayoutItem->m_pParent;
-    pSecondLayoutItem->m_pNextSibling = pLayoutItem->m_pNextSibling;
-    pLayoutItem->m_pNextSibling = pSecondLayoutItem;
-  }
-
-  CXFA_ContentLayoutItem* pChildren =
-      (CXFA_ContentLayoutItem*)pLayoutItem->m_pFirstChild;
-  pLayoutItem->m_pFirstChild = nullptr;
-
-  float lHeightForKeep = 0;
-  float fAddMarginHeight = 0;
-  std::vector<CXFA_ContentLayoutItem*> keepLayoutItems;
-  for (CXFA_ContentLayoutItem *pChildItem = pChildren, *pChildNext = nullptr;
-       pChildItem; pChildItem = pChildNext) {
-    pChildNext = (CXFA_ContentLayoutItem*)pChildItem->m_pNextSibling;
-    pChildItem->m_pNextSibling = nullptr;
-    if (fSplitPos <= fCurTopMargin + pChildItem->m_sPos.y + fCurBottomMargin +
-                         XFA_LAYOUT_FLOAT_PERCISION) {
-      if (!ExistContainerKeep(pChildItem->m_pFormNode, true)) {
-        pChildItem->m_sPos.y -= fSplitPos - fCurBottomMargin;
-        pChildItem->m_sPos.y += lHeightForKeep;
-        pChildItem->m_sPos.y += fAddMarginHeight;
-        pSecondLayoutItem->AddChild(pChildItem);
-        continue;
-      }
-      if (lHeightForKeep < XFA_LAYOUT_FLOAT_PERCISION) {
-        for (auto* pPreItem : keepLayoutItems) {
-          pLayoutItem->RemoveChild(pPreItem);
-          pPreItem->m_sPos.y -= fSplitPos;
-          if (pPreItem->m_sPos.y < 0)
-            pPreItem->m_sPos.y = 0;
-          if (pPreItem->m_sPos.y + pPreItem->m_sSize.height > lHeightForKeep) {
-            pPreItem->m_sPos.y = lHeightForKeep;
-            lHeightForKeep += pPreItem->m_sSize.height;
-            pSecondLayoutItem->m_sSize.height += pPreItem->m_sSize.height;
-            if (pSecondParent)
-              pSecondParent->m_sSize.height += pPreItem->m_sSize.height;
-          }
-          pSecondLayoutItem->AddChild(pPreItem);
-        }
-      }
-      pChildItem->m_sPos.y -= fSplitPos;
-      pChildItem->m_sPos.y += lHeightForKeep;
-      pChildItem->m_sPos.y += fAddMarginHeight;
-      pSecondLayoutItem->AddChild(pChildItem);
-      continue;
-    }
-    if (fSplitPos + XFA_LAYOUT_FLOAT_PERCISION >=
-        fCurTopMargin + fCurBottomMargin + pChildItem->m_sPos.y +
-            pChildItem->m_sSize.height) {
-      pLayoutItem->AddChild(pChildItem);
-      if (ExistContainerKeep(pChildItem->m_pFormNode, false))
-        keepLayoutItems.push_back(pChildItem);
-      else
-        keepLayoutItems.clear();
-      continue;
-    }
-
-    float fOldHeight = pSecondLayoutItem->m_sSize.height;
-    SplitLayoutItem(
-        pChildItem, pSecondLayoutItem,
-        fSplitPos - fCurTopMargin - fCurBottomMargin - pChildItem->m_sPos.y);
-    fAddMarginHeight = pSecondLayoutItem->m_sSize.height - fOldHeight;
-    pLayoutItem->AddChild(pChildItem);
-  }
-}
-
-void CXFA_ItemLayoutProcessor::SplitLayoutItem(float fSplitPos) {
-  ASSERT(m_pLayoutItem);
-  SplitLayoutItem(m_pLayoutItem, nullptr, fSplitPos);
-}
-
-CXFA_ContentLayoutItem* CXFA_ItemLayoutProcessor::ExtractLayoutItem() {
-  CXFA_ContentLayoutItem* pLayoutItem = m_pLayoutItem;
-  if (pLayoutItem) {
-    m_pLayoutItem =
-        static_cast<CXFA_ContentLayoutItem*>(pLayoutItem->m_pNextSibling);
-    pLayoutItem->m_pNextSibling = nullptr;
-  }
-
-  if (m_nCurChildNodeStage != XFA_ItemLayoutProcessorStages::Done ||
-      !ToContentLayoutItem(m_pOldLayoutItem)) {
-    return pLayoutItem;
-  }
-
-  if (m_pOldLayoutItem->m_pPrev)
-    m_pOldLayoutItem->m_pPrev->m_pNext = nullptr;
-
-  CXFA_FFNotify* pNotify =
-      m_pOldLayoutItem->m_pFormNode->GetDocument()->GetNotify();
-  CXFA_LayoutProcessor* pDocLayout =
-      m_pOldLayoutItem->m_pFormNode->GetDocument()->GetDocLayout();
-  CXFA_ContentLayoutItem* pOldLayoutItem = m_pOldLayoutItem;
-  while (pOldLayoutItem) {
-    CXFA_ContentLayoutItem* pNextOldLayoutItem = pOldLayoutItem->m_pNext;
-    pNotify->OnLayoutItemRemoving(pDocLayout, pOldLayoutItem);
-    if (pOldLayoutItem->m_pParent)
-      pOldLayoutItem->m_pParent->RemoveChild(pOldLayoutItem);
-
-    delete pOldLayoutItem;
-    pOldLayoutItem = pNextOldLayoutItem;
-  }
-  m_pOldLayoutItem = nullptr;
-  return pLayoutItem;
-}
-
-void CXFA_ItemLayoutProcessor::GotoNextContainerNode(
-    CXFA_Node*& pCurActionNode,
-    XFA_ItemLayoutProcessorStages& nCurStage,
-    CXFA_Node* pParentContainer,
-    bool bUsePageBreak) {
-  CXFA_Node* pEntireContainer = pParentContainer;
-  CXFA_Node* pChildContainer = XFA_LAYOUT_INVALIDNODE;
-  switch (nCurStage) {
-    case XFA_ItemLayoutProcessorStages::BreakBefore:
-    case XFA_ItemLayoutProcessorStages::BreakAfter: {
-      pChildContainer = pCurActionNode->GetParent();
-      break;
-    }
-    case XFA_ItemLayoutProcessorStages::Keep:
-    case XFA_ItemLayoutProcessorStages::Container:
-      pChildContainer = pCurActionNode;
-      break;
-    default:
-      pChildContainer = XFA_LAYOUT_INVALIDNODE;
-      break;
-  }
-
-  switch (nCurStage) {
-    case XFA_ItemLayoutProcessorStages::Keep: {
-      CXFA_Node* pBreakAfterNode = pChildContainer->GetFirstChild();
-      if (!m_bKeepBreakFinish &&
-          FindBreakNode(pBreakAfterNode, pCurActionNode, &nCurStage, false)) {
-        return;
-      }
-      goto CheckNextChildContainer;
-    }
-    case XFA_ItemLayoutProcessorStages::None: {
-      pCurActionNode = XFA_LAYOUT_INVALIDNODE;
-      case XFA_ItemLayoutProcessorStages::BookendLeader:
-        for (CXFA_Node* pBookendNode = pCurActionNode == XFA_LAYOUT_INVALIDNODE
-                                           ? pEntireContainer->GetFirstChild()
-                                           : pCurActionNode->GetNextSibling();
-             pBookendNode; pBookendNode = pBookendNode->GetNextSibling()) {
-          switch (pBookendNode->GetElementType()) {
-            case XFA_Element::Bookend:
-            case XFA_Element::Break:
-              pCurActionNode = pBookendNode;
-              nCurStage = XFA_ItemLayoutProcessorStages::BookendLeader;
-              return;
-            default:
-              break;
-          }
-        }
-    }
-      {
-        pCurActionNode = XFA_LAYOUT_INVALIDNODE;
-        case XFA_ItemLayoutProcessorStages::BreakBefore:
-          if (pCurActionNode != XFA_LAYOUT_INVALIDNODE) {
-            CXFA_Node* pBreakBeforeNode = pCurActionNode->GetNextSibling();
-            if (!m_bKeepBreakFinish &&
-                FindBreakNode(pBreakBeforeNode, pCurActionNode, &nCurStage,
-                              true)) {
-              return;
-            }
-            if (m_bIsProcessKeep) {
-              if (ProcessKeepNodesForBreakBefore(pCurActionNode, nCurStage,
-                                                 pChildContainer)) {
-                return;
-              }
-              goto CheckNextChildContainer;
-            }
-            pCurActionNode = pChildContainer;
-            nCurStage = XFA_ItemLayoutProcessorStages::Container;
-            return;
-          }
-          goto CheckNextChildContainer;
-      }
-    case XFA_ItemLayoutProcessorStages::Container: {
-      pCurActionNode = XFA_LAYOUT_INVALIDNODE;
-      case XFA_ItemLayoutProcessorStages::BreakAfter: {
-        if (pCurActionNode == XFA_LAYOUT_INVALIDNODE) {
-          CXFA_Node* pBreakAfterNode = pChildContainer->GetFirstChild();
-          if (!m_bKeepBreakFinish &&
-              FindBreakNode(pBreakAfterNode, pCurActionNode, &nCurStage,
-                            false)) {
-            return;
-          }
-        } else {
-          CXFA_Node* pBreakAfterNode = pCurActionNode->GetNextSibling();
-          if (FindBreakNode(pBreakAfterNode, pCurActionNode, &nCurStage,
-                            false)) {
-            return;
-          }
-        }
-        goto CheckNextChildContainer;
-      }
-    }
-
-    CheckNextChildContainer : {
-      CXFA_Node* pNextChildContainer =
-          pChildContainer == XFA_LAYOUT_INVALIDNODE
-              ? pEntireContainer->GetFirstContainerChild()
-              : pChildContainer->GetNextContainerSibling();
-      while (pNextChildContainer &&
-             pNextChildContainer->IsLayoutGeneratedNode()) {
-        CXFA_Node* pSaveNode = pNextChildContainer;
-        pNextChildContainer = pNextChildContainer->GetNextContainerSibling();
-        if (pSaveNode->IsUnusedNode())
-          DeleteLayoutGeneratedNode(pSaveNode);
-      }
-      if (!pNextChildContainer)
-        goto NoMoreChildContainer;
-
-      bool bLastKeep = false;
-      if (ProcessKeepNodesForCheckNext(pCurActionNode, nCurStage,
-                                       pNextChildContainer, bLastKeep)) {
-        return;
-      }
-      if (!m_bKeepBreakFinish && !bLastKeep &&
-          FindBreakNode(pNextChildContainer->GetFirstChild(), pCurActionNode,
-                        &nCurStage, true)) {
-        return;
-      }
-      pCurActionNode = pNextChildContainer;
-      if (m_bIsProcessKeep)
-        nCurStage = XFA_ItemLayoutProcessorStages::Keep;
-      else
-        nCurStage = XFA_ItemLayoutProcessorStages::Container;
-      return;
-    }
-
-    NoMoreChildContainer : {
-      pCurActionNode = XFA_LAYOUT_INVALIDNODE;
-      case XFA_ItemLayoutProcessorStages::BookendTrailer:
-        for (CXFA_Node* pBookendNode = pCurActionNode == XFA_LAYOUT_INVALIDNODE
-                                           ? pEntireContainer->GetFirstChild()
-                                           : pCurActionNode->GetNextSibling();
-             pBookendNode; pBookendNode = pBookendNode->GetNextSibling()) {
-          switch (pBookendNode->GetElementType()) {
-            case XFA_Element::Bookend:
-            case XFA_Element::Break:
-              pCurActionNode = pBookendNode;
-              nCurStage = XFA_ItemLayoutProcessorStages::BookendTrailer;
-              return;
-            default:
-              break;
-          }
-        }
-    }
-    default:
-      pCurActionNode = nullptr;
-      nCurStage = XFA_ItemLayoutProcessorStages::Done;
-  }
-}
-
-bool CXFA_ItemLayoutProcessor::ProcessKeepNodesForCheckNext(
-    CXFA_Node*& pCurActionNode,
-    XFA_ItemLayoutProcessorStages& nCurStage,
-    CXFA_Node*& pNextContainer,
-    bool& bLastKeepNode) {
-  const bool bCanSplit = pNextContainer->GetIntact() == XFA_AttributeEnum::None;
-  bool bNextKeep = false;
-  if (ExistContainerKeep(pNextContainer, false))
-    bNextKeep = true;
-
-  if (bNextKeep && !bCanSplit) {
-    if (!m_bIsProcessKeep && !m_bKeepBreakFinish) {
-      m_pKeepHeadNode = pNextContainer;
-      m_bIsProcessKeep = true;
-    }
-    return false;
-  }
-
-  if (m_bIsProcessKeep && m_pKeepHeadNode) {
-    m_pKeepTailNode = pNextContainer;
-    if (!m_bKeepBreakFinish &&
-        FindBreakNode(pNextContainer->GetFirstChild(), pCurActionNode,
-                      &nCurStage, true)) {
-      return true;
-    }
-
-    pNextContainer = m_pKeepHeadNode;
-    m_bKeepBreakFinish = true;
-    m_pKeepHeadNode = nullptr;
-    m_pKeepTailNode = nullptr;
-    m_bIsProcessKeep = false;
-  } else {
-    if (m_bKeepBreakFinish)
-      bLastKeepNode = true;
-    m_bKeepBreakFinish = false;
-  }
-
-  return false;
-}
-
-bool CXFA_ItemLayoutProcessor::ProcessKeepNodesForBreakBefore(
-    CXFA_Node*& pCurActionNode,
-    XFA_ItemLayoutProcessorStages& nCurStage,
-    CXFA_Node* pContainerNode) {
-  if (m_pKeepTailNode == pContainerNode) {
-    pCurActionNode = m_pKeepHeadNode;
-    m_bKeepBreakFinish = true;
-    m_pKeepHeadNode = nullptr;
-    m_pKeepTailNode = nullptr;
-    m_bIsProcessKeep = false;
-    nCurStage = XFA_ItemLayoutProcessorStages::Container;
-    return true;
-  }
-
-  CXFA_Node* pBreakAfterNode = pContainerNode->GetFirstChild();
-  return FindBreakNode(pBreakAfterNode, pCurActionNode, &nCurStage, false);
-}
-
-bool XFA_ItemLayoutProcessor_IsTakingSpace(CXFA_Node* pNode) {
-  XFA_AttributeEnum ePresence = pNode->JSObject()
-                                    ->TryEnum(XFA_Attribute::Presence, true)
-                                    .value_or(XFA_AttributeEnum::Visible);
-  return ePresence == XFA_AttributeEnum::Visible ||
-         ePresence == XFA_AttributeEnum::Invisible;
-}
-
-bool CXFA_ItemLayoutProcessor::IncrementRelayoutNode(
-    CXFA_LayoutProcessor* pLayoutProcessor,
-    CXFA_Node* pNode,
-    CXFA_Node* pParentNode) {
-  return false;
-}
-
-void CXFA_ItemLayoutProcessor::DoLayoutPageArea(
-    CXFA_ContainerLayoutItem* pPageAreaLayoutItem) {
-  CXFA_Node* pFormNode = pPageAreaLayoutItem->m_pFormNode;
-  CXFA_Node* pCurChildNode = XFA_LAYOUT_INVALIDNODE;
-  XFA_ItemLayoutProcessorStages nCurChildNodeStage =
-      XFA_ItemLayoutProcessorStages::None;
-  CXFA_LayoutItem* pBeforeItem = nullptr;
-  for (GotoNextContainerNode(pCurChildNode, nCurChildNodeStage, pFormNode,
-                             false);
-       pCurChildNode; GotoNextContainerNode(pCurChildNode, nCurChildNodeStage,
-                                            pFormNode, false)) {
-    if (nCurChildNodeStage != XFA_ItemLayoutProcessorStages::Container)
-      continue;
-    if (pCurChildNode->GetElementType() == XFA_Element::Variables)
-      continue;
-
-    auto pProcessor =
-        pdfium::MakeUnique<CXFA_ItemLayoutProcessor>(pCurChildNode, nullptr);
-    pProcessor->DoLayout(false, FLT_MAX, FLT_MAX, nullptr);
-    if (!pProcessor->HasLayoutItem())
-      continue;
-
-    pProcessor->SetCurrentComponentPos(CalculatePositionedContainerPos(
-        pCurChildNode, pProcessor->GetCurrentComponentSize()));
-    CXFA_LayoutItem* pProcessItem = pProcessor->ExtractLayoutItem();
-    if (!pBeforeItem)
-      pPageAreaLayoutItem->AddHeadChild(pProcessItem);
-    else
-      pPageAreaLayoutItem->InsertChild(pBeforeItem, pProcessItem);
-
-    pBeforeItem = pProcessItem;
-  }
-
-  pBeforeItem = nullptr;
-  CXFA_LayoutItem* pLayoutItem = pPageAreaLayoutItem->m_pFirstChild;
-  while (pLayoutItem) {
-    if (!pLayoutItem->IsContentLayoutItem() ||
-        pLayoutItem->m_pFormNode->GetElementType() != XFA_Element::Draw) {
-      pLayoutItem = pLayoutItem->m_pNextSibling;
-      continue;
-    }
-    if (pLayoutItem->m_pFormNode->GetElementType() != XFA_Element::Draw)
-      continue;
-
-    CXFA_LayoutItem* pNextLayoutItem = pLayoutItem->m_pNextSibling;
-    pPageAreaLayoutItem->RemoveChild(pLayoutItem);
-    if (!pBeforeItem)
-      pPageAreaLayoutItem->AddHeadChild(pLayoutItem);
-    else
-      pPageAreaLayoutItem->InsertChild(pBeforeItem, pLayoutItem);
-
-    pBeforeItem = pLayoutItem;
-    pLayoutItem = pNextLayoutItem;
-  }
-}
-
-void CXFA_ItemLayoutProcessor::DoLayoutPositionedContainer(
-    CXFA_LayoutContext* pContext) {
-  if (m_pLayoutItem)
-    return;
-
-  m_pLayoutItem = CreateContentLayoutItem(m_pFormNode);
-  bool bIgnoreXY = (m_pFormNode->JSObject()
-                        ->TryEnum(XFA_Attribute::Layout, true)
-                        .value_or(XFA_AttributeEnum::Position) !=
-                    XFA_AttributeEnum::Position);
-  bool bContainerWidthAutoSize = true;
-  bool bContainerHeightAutoSize = true;
-  CFX_SizeF containerSize = CalculateContainerSpecifiedSize(
-      m_pFormNode, &bContainerWidthAutoSize, &bContainerHeightAutoSize);
-
-  float fContentCalculatedWidth = 0;
-  float fContentCalculatedHeight = 0;
-  float fHiddenContentCalculatedWidth = 0;
-  float fHiddenContentCalculatedHeight = 0;
-  if (m_pCurChildNode == XFA_LAYOUT_INVALIDNODE) {
-    GotoNextContainerNode(m_pCurChildNode, m_nCurChildNodeStage, m_pFormNode,
-                          false);
-  }
-
-  int32_t iColIndex = 0;
-  for (; m_pCurChildNode; GotoNextContainerNode(
-           m_pCurChildNode, m_nCurChildNodeStage, m_pFormNode, false)) {
-    if (m_nCurChildNodeStage != XFA_ItemLayoutProcessorStages::Container)
-      continue;
-    if (m_pCurChildNode->GetElementType() == XFA_Element::Variables)
-      continue;
-
-    auto pProcessor = pdfium::MakeUnique<CXFA_ItemLayoutProcessor>(
-        m_pCurChildNode, m_pPageMgr);
-    if (pContext && pContext->m_prgSpecifiedColumnWidths) {
-      int32_t iColSpan =
-          m_pCurChildNode->JSObject()->GetInteger(XFA_Attribute::ColSpan);
-      if (iColSpan <= pdfium::CollectionSize<int32_t>(
-                          *pContext->m_prgSpecifiedColumnWidths) -
-                          iColIndex) {
-        pContext->m_fCurColumnWidth = 0;
-        pContext->m_bCurColumnWidthAvaiable = true;
-        if (iColSpan == -1) {
-          iColSpan = pdfium::CollectionSize<int32_t>(
-              *pContext->m_prgSpecifiedColumnWidths);
-        }
-        for (int32_t i = 0; iColIndex + i < iColSpan; ++i) {
-          pContext->m_fCurColumnWidth +=
-              (*pContext->m_prgSpecifiedColumnWidths)[iColIndex + i];
-        }
-        if (pContext->m_fCurColumnWidth == 0)
-          pContext->m_bCurColumnWidthAvaiable = false;
-
-        iColIndex += iColSpan >= 0 ? iColSpan : 0;
-      }
-    }
-
-    pProcessor->DoLayout(false, FLT_MAX, FLT_MAX, pContext);
-    if (!pProcessor->HasLayoutItem())
-      continue;
-
-    CFX_SizeF size = pProcessor->GetCurrentComponentSize();
-    bool bChangeParentSize = false;
-    if (XFA_ItemLayoutProcessor_IsTakingSpace(m_pCurChildNode))
-      bChangeParentSize = true;
-
-    CFX_PointF absolutePos;
-    if (!bIgnoreXY)
-      absolutePos = CalculatePositionedContainerPos(m_pCurChildNode, size);
-
-    pProcessor->SetCurrentComponentPos(absolutePos);
-    if (bContainerWidthAutoSize) {
-      float fChildSuppliedWidth = absolutePos.x + size.width;
-      if (bChangeParentSize) {
-        fContentCalculatedWidth =
-            std::max(fContentCalculatedWidth, fChildSuppliedWidth);
-      } else {
-        if (fHiddenContentCalculatedWidth < fChildSuppliedWidth &&
-            m_pCurChildNode->GetElementType() != XFA_Element::Subform) {
-          fHiddenContentCalculatedWidth = fChildSuppliedWidth;
-        }
-      }
-    }
-
-    if (bContainerHeightAutoSize) {
-      float fChildSuppliedHeight = absolutePos.y + size.height;
-      if (bChangeParentSize) {
-        fContentCalculatedHeight =
-            std::max(fContentCalculatedHeight, fChildSuppliedHeight);
-      } else {
-        if (fHiddenContentCalculatedHeight < fChildSuppliedHeight &&
-            m_pCurChildNode->GetElementType() != XFA_Element::Subform) {
-          fHiddenContentCalculatedHeight = fChildSuppliedHeight;
-        }
-      }
-    }
-    m_pLayoutItem->AddChild(pProcessor->ExtractLayoutItem());
-  }
-
-  XFA_VERSION eVersion = m_pFormNode->GetDocument()->GetCurVersionMode();
-  if (fContentCalculatedWidth == 0 && eVersion < XFA_VERSION_207)
-    fContentCalculatedWidth = fHiddenContentCalculatedWidth;
-  if (fContentCalculatedHeight == 0 && eVersion < XFA_VERSION_207)
-    fContentCalculatedHeight = fHiddenContentCalculatedHeight;
-
-  containerSize = CalculateContainerComponentSizeFromContentSize(
-      m_pFormNode, bContainerWidthAutoSize, fContentCalculatedWidth,
-      bContainerHeightAutoSize, fContentCalculatedHeight, containerSize);
-  SetCurrentComponentSize(containerSize);
-}
-
-void CXFA_ItemLayoutProcessor::DoLayoutTableContainer(CXFA_Node* pLayoutNode) {
-  if (m_pLayoutItem)
-    return;
-  if (!pLayoutNode)
-    pLayoutNode = m_pFormNode;
-
-  ASSERT(m_pCurChildNode == XFA_LAYOUT_INVALIDNODE);
-
-  m_pLayoutItem = CreateContentLayoutItem(m_pFormNode);
-  bool bContainerWidthAutoSize = true;
-  bool bContainerHeightAutoSize = true;
-  CFX_SizeF containerSize = CalculateContainerSpecifiedSize(
-      m_pFormNode, &bContainerWidthAutoSize, &bContainerHeightAutoSize);
-  float fContentCalculatedWidth = 0;
-  float fContentCalculatedHeight = 0;
-  CXFA_Margin* pMarginNode =
-      m_pFormNode->GetFirstChildByClass<CXFA_Margin>(XFA_Element::Margin);
-  float fLeftInset = 0;
-  float fRightInset = 0;
-  if (pMarginNode) {
-    fLeftInset = pMarginNode->JSObject()
-                     ->GetMeasure(XFA_Attribute::LeftInset)
-                     .ToUnit(XFA_Unit::Pt);
-    fRightInset = pMarginNode->JSObject()
-                      ->GetMeasure(XFA_Attribute::RightInset)
-                      .ToUnit(XFA_Unit::Pt);
-  }
-
-  float fContentWidthLimit =
-      bContainerWidthAutoSize ? FLT_MAX
-                              : containerSize.width - fLeftInset - fRightInset;
-  WideString wsColumnWidths =
-      pLayoutNode->JSObject()->GetCData(XFA_Attribute::ColumnWidths);
-  if (!wsColumnWidths.IsEmpty()) {
-    auto widths = SeparateStringW(wsColumnWidths.c_str(),
-                                  wsColumnWidths.GetLength(), L' ');
-    for (auto& width : widths) {
-      width.TrimLeft(L' ');
-      if (width.IsEmpty())
-        continue;
-
-      m_rgSpecifiedColumnWidths.push_back(
-          CXFA_Measurement(width.AsStringView()).ToUnit(XFA_Unit::Pt));
-    }
-  }
-
-  int32_t iSpecifiedColumnCount =
-      pdfium::CollectionSize<int32_t>(m_rgSpecifiedColumnWidths);
-  CXFA_LayoutContext layoutContext;
-  layoutContext.m_prgSpecifiedColumnWidths = &m_rgSpecifiedColumnWidths;
-  CXFA_LayoutContext* pLayoutContext =
-      iSpecifiedColumnCount > 0 ? &layoutContext : nullptr;
-  if (m_pCurChildNode == XFA_LAYOUT_INVALIDNODE) {
-    GotoNextContainerNode(m_pCurChildNode, m_nCurChildNodeStage, m_pFormNode,
-                          false);
-  }
-
-  for (; m_pCurChildNode; GotoNextContainerNode(
-           m_pCurChildNode, m_nCurChildNodeStage, m_pFormNode, false)) {
-    layoutContext.m_bCurColumnWidthAvaiable = false;
-    layoutContext.m_fCurColumnWidth = 0;
-    if (m_nCurChildNodeStage != XFA_ItemLayoutProcessorStages::Container)
-      continue;
-
-    auto pProcessor = pdfium::MakeUnique<CXFA_ItemLayoutProcessor>(
-        m_pCurChildNode, m_pPageMgr);
-    pProcessor->DoLayout(false, FLT_MAX, FLT_MAX, pLayoutContext);
-    if (!pProcessor->HasLayoutItem())
-      continue;
-
-    m_pLayoutItem->AddChild(pProcessor->ExtractLayoutItem());
-  }
-
-  int32_t iRowCount = 0;
-  int32_t iColCount = 0;
-  {
-    std::vector<CXFA_ContentLayoutItem*> rgRowItems;
-    std::vector<int32_t> rgRowItemsSpan;
-    std::vector<float> rgRowItemsWidth;
-    for (auto* pLayoutChild =
-             static_cast<CXFA_ContentLayoutItem*>(m_pLayoutItem->m_pFirstChild);
-         pLayoutChild; pLayoutChild = static_cast<CXFA_ContentLayoutItem*>(
-                           pLayoutChild->m_pNextSibling)) {
-      if (pLayoutChild->m_pFormNode->GetElementType() != XFA_Element::Subform)
-        continue;
-      if (!XFA_ItemLayoutProcessor_IsTakingSpace(pLayoutChild->m_pFormNode))
-        continue;
-
-      XFA_AttributeEnum eLayout =
-          pLayoutChild->m_pFormNode->JSObject()->GetEnum(XFA_Attribute::Layout);
-      if (eLayout != XFA_AttributeEnum::Row &&
-          eLayout != XFA_AttributeEnum::Rl_row) {
-        continue;
-      }
-      if (CXFA_ContentLayoutItem* pRowLayoutCell =
-              (CXFA_ContentLayoutItem*)pLayoutChild->m_pFirstChild) {
-        rgRowItems.push_back(pRowLayoutCell);
-        int32_t iColSpan = pRowLayoutCell->m_pFormNode->JSObject()->GetInteger(
-            XFA_Attribute::ColSpan);
-        rgRowItemsSpan.push_back(iColSpan);
-        rgRowItemsWidth.push_back(pRowLayoutCell->m_sSize.width);
-      }
-    }
-
-    iRowCount = pdfium::CollectionSize<int32_t>(rgRowItems);
-    iColCount = 0;
-    bool bMoreColumns = true;
-    while (bMoreColumns) {
-      bMoreColumns = false;
-      bool bAutoCol = false;
-      for (int32_t i = 0; i < iRowCount; i++) {
-        while (rgRowItems[i] && (rgRowItemsSpan[i] <= 0 ||
-                                 !XFA_ItemLayoutProcessor_IsTakingSpace(
-                                     rgRowItems[i]->m_pFormNode))) {
-          CXFA_ContentLayoutItem* pNewCell =
-              (CXFA_ContentLayoutItem*)rgRowItems[i]->m_pNextSibling;
-          if (rgRowItemsSpan[i] < 0 && XFA_ItemLayoutProcessor_IsTakingSpace(
-                                           rgRowItems[i]->m_pFormNode)) {
-            pNewCell = nullptr;
-          }
-          rgRowItems[i] = pNewCell;
-          rgRowItemsSpan[i] =
-              pNewCell ? pNewCell->m_pFormNode->JSObject()->GetInteger(
-                             XFA_Attribute::ColSpan)
-                       : 0;
-          rgRowItemsWidth[i] = pNewCell ? pNewCell->m_sSize.width : 0;
-        }
-        CXFA_ContentLayoutItem* pCell = rgRowItems[i];
-        if (!pCell)
-          continue;
-
-        bMoreColumns = true;
-        if (rgRowItemsSpan[i] != 1)
-          continue;
-
-        if (iColCount >= iSpecifiedColumnCount) {
-          int32_t c = iColCount + 1 - pdfium::CollectionSize<int32_t>(
-                                          m_rgSpecifiedColumnWidths);
-          for (int32_t j = 0; j < c; j++)
-            m_rgSpecifiedColumnWidths.push_back(0);
-        }
-        if (m_rgSpecifiedColumnWidths[iColCount] < XFA_LAYOUT_FLOAT_PERCISION)
-          bAutoCol = true;
-        if (bAutoCol &&
-            m_rgSpecifiedColumnWidths[iColCount] < rgRowItemsWidth[i]) {
-          m_rgSpecifiedColumnWidths[iColCount] = rgRowItemsWidth[i];
-        }
-      }
-
-      if (!bMoreColumns)
-        continue;
-
-      float fFinalColumnWidth = 0.0f;
-      if (pdfium::IndexInBounds(m_rgSpecifiedColumnWidths, iColCount))
-        fFinalColumnWidth = m_rgSpecifiedColumnWidths[iColCount];
-
-      for (int32_t i = 0; i < iRowCount; ++i) {
-        if (!rgRowItems[i])
-          continue;
-        --rgRowItemsSpan[i];
-        rgRowItemsWidth[i] -= fFinalColumnWidth;
-      }
-      ++iColCount;
-    }
-  }
-
-  float fCurrentRowY = 0;
-  for (CXFA_ContentLayoutItem* pLayoutChild =
-           (CXFA_ContentLayoutItem*)m_pLayoutItem->m_pFirstChild;
-       pLayoutChild;
-       pLayoutChild = (CXFA_ContentLayoutItem*)pLayoutChild->m_pNextSibling) {
-    if (!XFA_ItemLayoutProcessor_IsTakingSpace(pLayoutChild->m_pFormNode))
-      continue;
-
-    if (pLayoutChild->m_pFormNode->GetElementType() == XFA_Element::Subform) {
-      XFA_AttributeEnum eSubformLayout =
-          pLayoutChild->m_pFormNode->JSObject()->GetEnum(XFA_Attribute::Layout);
-      if (eSubformLayout == XFA_AttributeEnum::Row ||
-          eSubformLayout == XFA_AttributeEnum::Rl_row) {
-        RelocateTableRowCells(pLayoutChild, m_rgSpecifiedColumnWidths,
-                              eSubformLayout);
-      }
-    }
-
-    pLayoutChild->m_sPos.y = fCurrentRowY;
-    if (bContainerWidthAutoSize) {
-      pLayoutChild->m_sPos.x = 0;
-    } else {
-      switch (pLayoutChild->m_pFormNode->JSObject()->GetEnum(
-          XFA_Attribute::HAlign)) {
-        case XFA_AttributeEnum::Center:
-          pLayoutChild->m_sPos.x =
-              (fContentWidthLimit - pLayoutChild->m_sSize.width) / 2;
-          break;
-        case XFA_AttributeEnum::Right:
-          pLayoutChild->m_sPos.x =
-              fContentWidthLimit - pLayoutChild->m_sSize.width;
-          break;
-        case XFA_AttributeEnum::Left:
-        default:
-          pLayoutChild->m_sPos.x = 0;
-          break;
-      }
-    }
-
-    if (bContainerWidthAutoSize) {
-      float fChildSuppliedWidth =
-          pLayoutChild->m_sPos.x + pLayoutChild->m_sSize.width;
-      if (fContentWidthLimit < FLT_MAX &&
-          fContentWidthLimit > fChildSuppliedWidth) {
-        fChildSuppliedWidth = fContentWidthLimit;
-      }
-      fContentCalculatedWidth =
-          std::max(fContentCalculatedWidth, fChildSuppliedWidth);
-    }
-    fCurrentRowY += pLayoutChild->m_sSize.height;
-  }
-
-  if (bContainerHeightAutoSize)
-    fContentCalculatedHeight = std::max(fContentCalculatedHeight, fCurrentRowY);
-
-  containerSize = CalculateContainerComponentSizeFromContentSize(
-      m_pFormNode, bContainerWidthAutoSize, fContentCalculatedWidth,
-      bContainerHeightAutoSize, fContentCalculatedHeight, containerSize);
-  SetCurrentComponentSize(containerSize);
-}
-
-bool CXFA_ItemLayoutProcessor::IsAddNewRowForTrailer(
-    CXFA_ContentLayoutItem* pTrailerItem) {
-  if (!pTrailerItem)
-    return false;
-
-  float fWidth = pTrailerItem->m_sSize.width;
-  XFA_AttributeEnum eLayout =
-      m_pFormNode->JSObject()->GetEnum(XFA_Attribute::Layout);
-  return eLayout == XFA_AttributeEnum::Tb || m_fWidthLimite <= fWidth;
-}
-
-float CXFA_ItemLayoutProcessor::InsertKeepLayoutItems() {
-  if (m_arrayKeepItems.empty())
-    return 0;
-
-  if (!m_pLayoutItem) {
-    m_pLayoutItem = CreateContentLayoutItem(m_pFormNode);
-    m_pLayoutItem->m_sSize.clear();
-  }
-
-  float fTotalHeight = 0;
-  for (auto iter = m_arrayKeepItems.rbegin(); iter != m_arrayKeepItems.rend();
-       iter++) {
-    AddLeaderAfterSplit(this, *iter);
-    fTotalHeight += (*iter)->m_sSize.height;
-  }
-  m_arrayKeepItems.clear();
-
-  return fTotalHeight;
-}
-
-bool CXFA_ItemLayoutProcessor::ProcessKeepForSplit(
-    CXFA_ItemLayoutProcessor* pParentProcessor,
-    CXFA_ItemLayoutProcessor* pChildProcessor,
-    XFA_ItemLayoutProcessorResult eRetValue,
-    std::vector<CXFA_ContentLayoutItem*>* rgCurLineLayoutItem,
-    float* fContentCurRowAvailWidth,
-    float* fContentCurRowHeight,
-    float* fContentCurRowY,
-    bool* bAddedItemInRow,
-    bool* bForceEndPage,
-    XFA_ItemLayoutProcessorResult* result) {
-  if (!pParentProcessor || !pChildProcessor)
-    return false;
-
-  if (pParentProcessor->m_pCurChildNode->GetIntact() ==
-          XFA_AttributeEnum::None &&
-      pChildProcessor->m_bHasAvailHeight)
-    return false;
-
-  if (!ExistContainerKeep(pParentProcessor->m_pCurChildNode, true))
-    return false;
-
-  CFX_SizeF childSize = pChildProcessor->GetCurrentComponentSize();
-  std::vector<CXFA_ContentLayoutItem*> keepLayoutItems;
-  if (pParentProcessor->JudgePutNextPage(pParentProcessor->m_pLayoutItem,
-                                         childSize.height, &keepLayoutItems)) {
-    m_arrayKeepItems.clear();
-
-    for (auto* item : keepLayoutItems) {
-      pParentProcessor->m_pLayoutItem->RemoveChild(item);
-      *fContentCurRowY -= item->m_sSize.height;
-      m_arrayKeepItems.push_back(item);
-    }
-    *bAddedItemInRow = true;
-    *bForceEndPage = true;
-    *result = XFA_ItemLayoutProcessorResult::PageFullBreak;
-    return true;
-  }
-
-  rgCurLineLayoutItem->push_back(pChildProcessor->ExtractLayoutItem());
-  *bAddedItemInRow = true;
-  *fContentCurRowAvailWidth -= childSize.width;
-  *fContentCurRowHeight = std::max(*fContentCurRowHeight, childSize.height);
-  *result = eRetValue;
-
-  return true;
-}
-
-bool CXFA_ItemLayoutProcessor::JudgePutNextPage(
-    CXFA_ContentLayoutItem* pParentLayoutItem,
-    float fChildHeight,
-    std::vector<CXFA_ContentLayoutItem*>* pKeepItems) {
-  if (!pParentLayoutItem)
-    return false;
-
-  float fItemsHeight = 0;
-  for (CXFA_ContentLayoutItem* pChildLayoutItem =
-           (CXFA_ContentLayoutItem*)pParentLayoutItem->m_pFirstChild;
-       pChildLayoutItem;
-       pChildLayoutItem =
-           (CXFA_ContentLayoutItem*)pChildLayoutItem->m_pNextSibling) {
-    if (ExistContainerKeep(pChildLayoutItem->m_pFormNode, false)) {
-      pKeepItems->push_back(pChildLayoutItem);
-      fItemsHeight += pChildLayoutItem->m_sSize.height;
-    } else {
-      pKeepItems->clear();
-      fItemsHeight = 0;
-    }
-  }
-  fItemsHeight += fChildHeight;
-  return m_pPageMgr->GetNextAvailContentHeight(fItemsHeight);
-}
-
-void CXFA_ItemLayoutProcessor::ProcessUnUseBinds(CXFA_Node* pFormNode) {
-  if (!pFormNode)
-    return;
-
-  CXFA_NodeIteratorTemplate<CXFA_Node, CXFA_TraverseStrategy_XFANode> sIterator(
-      pFormNode);
-  for (CXFA_Node* pNode = sIterator.MoveToNext(); pNode;
-       pNode = sIterator.MoveToNext()) {
-    if (pNode->IsContainerNode()) {
-      CXFA_Node* pBindNode = pNode->GetBindData();
-      if (pBindNode) {
-        pBindNode->RemoveBindItem(pNode);
-        pNode->SetBindingNode(nullptr);
-      }
-    }
-    pNode->SetFlag(XFA_NodeFlag_UnusedNode, true);
-  }
-}
-
-void CXFA_ItemLayoutProcessor::ProcessUnUseOverFlow(
-    CXFA_Node* pLeaderNode,
-    CXFA_Node* pTrailerNode,
-    CXFA_ContentLayoutItem* pTrailerItem,
-    CXFA_Node* pFormNode) {
-  ProcessUnUseBinds(pLeaderNode);
-  ProcessUnUseBinds(pTrailerNode);
-  if (!pFormNode)
-    return;
-
-  if (pFormNode->GetElementType() == XFA_Element::Overflow ||
-      pFormNode->GetElementType() == XFA_Element::Break) {
-    pFormNode = pFormNode->GetParent();
-  }
-  if (pLeaderNode && pFormNode)
-    pFormNode->RemoveChild(pLeaderNode, true);
-  if (pTrailerNode && pFormNode)
-    pFormNode->RemoveChild(pTrailerNode, true);
-  if (pTrailerItem)
-    XFA_ReleaseLayoutItem(pTrailerItem);
-}
-
-XFA_ItemLayoutProcessorResult CXFA_ItemLayoutProcessor::DoLayoutFlowedContainer(
-    bool bUseBreakControl,
-    XFA_AttributeEnum eFlowStrategy,
-    float fHeightLimit,
-    float fRealHeight,
-    CXFA_LayoutContext* pContext,
-    bool bRootForceTb) {
-  m_bHasAvailHeight = true;
-  bool bBreakDone = false;
-  bool bContainerWidthAutoSize = true;
-  bool bContainerHeightAutoSize = true;
-  bool bForceEndPage = false;
-  bool bIsManualBreak = false;
-  if (m_pCurChildPreprocessor) {
-    m_pCurChildPreprocessor->m_ePreProcessRs =
-        XFA_ItemLayoutProcessorResult::Done;
-  }
-
-  CFX_SizeF containerSize = CalculateContainerSpecifiedSize(
-      m_pFormNode, &bContainerWidthAutoSize, &bContainerHeightAutoSize);
-  if (pContext && pContext->m_bCurColumnWidthAvaiable) {
-    bContainerWidthAutoSize = false;
-    containerSize.width = pContext->m_fCurColumnWidth;
-  }
-  if (!bContainerHeightAutoSize)
-    containerSize.height -= m_fUsedSize;
-
-  if (!bContainerHeightAutoSize) {
-    CXFA_Node* pParentNode = m_pFormNode->GetParent();
-    bool bFocrTb = false;
-    if (pParentNode &&
-        GetLayout(pParentNode, &bFocrTb) == XFA_AttributeEnum::Row) {
-      CXFA_Node* pChildContainer = m_pFormNode->GetFirstContainerChild();
-      if (pChildContainer && pChildContainer->GetNextContainerSibling()) {
-        containerSize.height = 0;
-        bContainerHeightAutoSize = true;
-      }
-    }
-  }
-
-  CXFA_Margin* pMarginNode =
-      m_pFormNode->GetFirstChildByClass<CXFA_Margin>(XFA_Element::Margin);
-  float fLeftInset = 0;
-  float fTopInset = 0;
-  float fRightInset = 0;
-  float fBottomInset = 0;
-  if (pMarginNode) {
-    fLeftInset = pMarginNode->JSObject()
-                     ->GetMeasure(XFA_Attribute::LeftInset)
-                     .ToUnit(XFA_Unit::Pt);
-    fTopInset = pMarginNode->JSObject()
-                    ->GetMeasure(XFA_Attribute::TopInset)
-                    .ToUnit(XFA_Unit::Pt);
-    fRightInset = pMarginNode->JSObject()
-                      ->GetMeasure(XFA_Attribute::RightInset)
-                      .ToUnit(XFA_Unit::Pt);
-    fBottomInset = pMarginNode->JSObject()
-                       ->GetMeasure(XFA_Attribute::BottomInset)
-                       .ToUnit(XFA_Unit::Pt);
-  }
-  float fContentWidthLimit =
-      bContainerWidthAutoSize ? FLT_MAX
-                              : containerSize.width - fLeftInset - fRightInset;
-  float fContentCalculatedWidth = 0;
-  float fContentCalculatedHeight = 0;
-  float fAvailHeight = fHeightLimit - fTopInset - fBottomInset;
-  if (fAvailHeight < 0)
-    m_bHasAvailHeight = false;
-
-  fRealHeight = fRealHeight - fTopInset - fBottomInset;
-  float fContentCurRowY = 0;
-  CXFA_ContentLayoutItem* pLayoutChild = nullptr;
-  if (m_pLayoutItem) {
-    if (m_nCurChildNodeStage != XFA_ItemLayoutProcessorStages::Done &&
-        eFlowStrategy != XFA_AttributeEnum::Tb) {
-      pLayoutChild = (CXFA_ContentLayoutItem*)m_pLayoutItem->m_pFirstChild;
-      for (CXFA_ContentLayoutItem* pLayoutNext = pLayoutChild; pLayoutNext;
-           pLayoutNext = (CXFA_ContentLayoutItem*)pLayoutNext->m_pNextSibling) {
-        if (pLayoutNext->m_sPos.y != pLayoutChild->m_sPos.y)
-          pLayoutChild = pLayoutNext;
-      }
-    }
-
-    for (CXFA_ContentLayoutItem* pLayoutTempChild =
-             (CXFA_ContentLayoutItem*)m_pLayoutItem->m_pFirstChild;
-         pLayoutTempChild != pLayoutChild;
-         pLayoutTempChild =
-             (CXFA_ContentLayoutItem*)pLayoutTempChild->m_pNextSibling) {
-      if (!XFA_ItemLayoutProcessor_IsTakingSpace(pLayoutTempChild->m_pFormNode))
-        continue;
-
-      fContentCalculatedWidth = std::max(
-          fContentCalculatedWidth,
-          pLayoutTempChild->m_sPos.x + pLayoutTempChild->m_sSize.width);
-      fContentCalculatedHeight = std::max(
-          fContentCalculatedHeight,
-          pLayoutTempChild->m_sPos.y + pLayoutTempChild->m_sSize.height);
-    }
-
-    if (pLayoutChild)
-      fContentCurRowY = pLayoutChild->m_sPos.y;
-    else
-      fContentCurRowY = fContentCalculatedHeight;
-  }
-
-  fContentCurRowY += InsertKeepLayoutItems();
-  if (m_nCurChildNodeStage == XFA_ItemLayoutProcessorStages::None) {
-    GotoNextContainerNode(m_pCurChildNode, m_nCurChildNodeStage, m_pFormNode,
-                          true);
-  }
-
-  fContentCurRowY += InsertPendingItems(this, m_pFormNode);
-  if (m_pCurChildPreprocessor &&
-      m_nCurChildNodeStage == XFA_ItemLayoutProcessorStages::Container) {
-    if (ExistContainerKeep(m_pCurChildPreprocessor->GetFormNode(), false)) {
-      m_pKeepHeadNode = m_pCurChildNode;
-      m_bIsProcessKeep = true;
-      m_nCurChildNodeStage = XFA_ItemLayoutProcessorStages::Keep;
-    }
-  }
-
-  while (m_nCurChildNodeStage != XFA_ItemLayoutProcessorStages::Done) {
-    float fContentCurRowHeight = 0;
-    float fContentCurRowAvailWidth = fContentWidthLimit;
-    m_fWidthLimite = fContentCurRowAvailWidth;
-    std::vector<CXFA_ContentLayoutItem*> rgCurLineLayoutItems[3];
-    uint8_t uCurHAlignState =
-        (eFlowStrategy != XFA_AttributeEnum::Rl_tb ? 0 : 2);
-    if (pLayoutChild) {
-      for (CXFA_ContentLayoutItem* pLayoutNext = pLayoutChild; pLayoutNext;
-           pLayoutNext = (CXFA_ContentLayoutItem*)pLayoutNext->m_pNextSibling) {
-        if (!pLayoutNext->m_pNextSibling && m_pCurChildPreprocessor &&
-            m_pCurChildPreprocessor->m_pFormNode == pLayoutNext->m_pFormNode) {
-          pLayoutNext->m_pNext = m_pCurChildPreprocessor->m_pLayoutItem;
-          m_pCurChildPreprocessor->m_pLayoutItem = pLayoutNext;
-          break;
-        }
-        uint8_t uHAlign =
-            HAlignEnumToInt(pLayoutNext->m_pFormNode->JSObject()->GetEnum(
-                XFA_Attribute::HAlign));
-        rgCurLineLayoutItems[uHAlign].push_back(pLayoutNext);
-        if (eFlowStrategy == XFA_AttributeEnum::Lr_tb) {
-          if (uHAlign > uCurHAlignState)
-            uCurHAlignState = uHAlign;
-        } else if (uHAlign < uCurHAlignState) {
-          uCurHAlignState = uHAlign;
-        }
-        if (XFA_ItemLayoutProcessor_IsTakingSpace(pLayoutNext->m_pFormNode)) {
-          if (pLayoutNext->m_sSize.height > fContentCurRowHeight)
-            fContentCurRowHeight = pLayoutNext->m_sSize.height;
-          fContentCurRowAvailWidth -= pLayoutNext->m_sSize.width;
-        }
-      }
-
-      if ((CXFA_ContentLayoutItem*)m_pLayoutItem->m_pFirstChild ==
-          pLayoutChild) {
-        m_pLayoutItem->m_pFirstChild = nullptr;
-      } else {
-        CXFA_ContentLayoutItem* pLayoutNext =
-            (CXFA_ContentLayoutItem*)m_pLayoutItem->m_pFirstChild;
-        for (; pLayoutNext;
-             pLayoutNext =
-                 (CXFA_ContentLayoutItem*)pLayoutNext->m_pNextSibling) {
-          if ((CXFA_ContentLayoutItem*)pLayoutNext->m_pNextSibling ==
-              pLayoutChild) {
-            pLayoutNext->m_pNextSibling = nullptr;
-            break;
-          }
-        }
-      }
-
-      CXFA_ContentLayoutItem* pLayoutNextTemp =
-          (CXFA_ContentLayoutItem*)pLayoutChild;
-      while (pLayoutNextTemp) {
-        pLayoutNextTemp->m_pParent = nullptr;
-        CXFA_ContentLayoutItem* pSaveLayoutNext =
-            (CXFA_ContentLayoutItem*)pLayoutNextTemp->m_pNextSibling;
-        pLayoutNextTemp->m_pNextSibling = nullptr;
-        pLayoutNextTemp = pSaveLayoutNext;
-      }
-      pLayoutChild = nullptr;
-    }
-
-    while (m_pCurChildNode) {
-      std::unique_ptr<CXFA_ItemLayoutProcessor> pProcessor;
-      bool bAddedItemInRow = false;
-      fContentCurRowY += InsertPendingItems(this, m_pFormNode);
-      switch (m_nCurChildNodeStage) {
-        case XFA_ItemLayoutProcessorStages::Keep:
-        case XFA_ItemLayoutProcessorStages::None:
-          break;
-        case XFA_ItemLayoutProcessorStages::BreakBefore: {
-          for (auto* item : m_arrayKeepItems) {
-            m_pLayoutItem->RemoveChild(item);
-            fContentCalculatedHeight -= item->m_sSize.height;
-          }
-
-          CXFA_Node* pLeaderNode = nullptr;
-          CXFA_Node* pTrailerNode = nullptr;
-          bool bCreatePage = false;
-          if (!bUseBreakControl || !m_pPageMgr ||
-              !m_pPageMgr->ProcessBreakBeforeOrAfter(m_pCurChildNode, true,
-                                                     pLeaderNode, pTrailerNode,
-                                                     bCreatePage) ||
-              m_pFormNode->GetElementType() == XFA_Element::Form ||
-              !bCreatePage) {
-            break;
-          }
-
-          if (JudgeLeaderOrTrailerForOccur(pLeaderNode))
-            AddPendingNode(this, pLeaderNode, true);
-
-          if (JudgeLeaderOrTrailerForOccur(pTrailerNode)) {
-            if (m_pFormNode->GetParent()->GetElementType() ==
-                    XFA_Element::Form &&
-                !m_pLayoutItem) {
-              AddPendingNode(this, pTrailerNode, true);
-            } else {
-              auto pTempProcessor =
-                  pdfium::MakeUnique<CXFA_ItemLayoutProcessor>(pTrailerNode,
-                                                               nullptr);
-              InsertFlowedItem(
-                  this, pTempProcessor.get(), bContainerWidthAutoSize,
-                  bContainerHeightAutoSize, containerSize.height, eFlowStrategy,
-                  &uCurHAlignState, rgCurLineLayoutItems, false, FLT_MAX,
-                  FLT_MAX, fContentWidthLimit, &fContentCurRowY,
-                  &fContentCurRowAvailWidth, &fContentCurRowHeight,
-                  &bAddedItemInRow, &bForceEndPage, pContext, false);
-            }
-          }
-          GotoNextContainerNode(m_pCurChildNode, m_nCurChildNodeStage,
-                                m_pFormNode, true);
-          bForceEndPage = true;
-          bIsManualBreak = true;
-          goto SuspendAndCreateNewRow;
-        }
-        case XFA_ItemLayoutProcessorStages::BreakAfter: {
-          CXFA_Node* pLeaderNode = nullptr;
-          CXFA_Node* pTrailerNode = nullptr;
-          bool bCreatePage = false;
-          if (!bUseBreakControl || !m_pPageMgr ||
-              !m_pPageMgr->ProcessBreakBeforeOrAfter(m_pCurChildNode, false,
-                                                     pLeaderNode, pTrailerNode,
-                                                     bCreatePage) ||
-              m_pFormNode->GetElementType() == XFA_Element::Form) {
-            break;
-          }
-
-          if (JudgeLeaderOrTrailerForOccur(pTrailerNode)) {
-            auto pTempProcessor = pdfium::MakeUnique<CXFA_ItemLayoutProcessor>(
-                pTrailerNode, nullptr);
-            InsertFlowedItem(
-                this, pTempProcessor.get(), bContainerWidthAutoSize,
-                bContainerHeightAutoSize, containerSize.height, eFlowStrategy,
-                &uCurHAlignState, rgCurLineLayoutItems, false, FLT_MAX, FLT_MAX,
-                fContentWidthLimit, &fContentCurRowY, &fContentCurRowAvailWidth,
-                &fContentCurRowHeight, &bAddedItemInRow, &bForceEndPage,
-                pContext, false);
-          }
-          if (!bCreatePage) {
-            if (JudgeLeaderOrTrailerForOccur(pLeaderNode)) {
-              CalculateRowChildPosition(
-                  rgCurLineLayoutItems, eFlowStrategy, bContainerHeightAutoSize,
-                  bContainerWidthAutoSize, &fContentCalculatedWidth,
-                  &fContentCalculatedHeight, &fContentCurRowY,
-                  fContentCurRowHeight, fContentWidthLimit, false);
-              rgCurLineLayoutItems->clear();
-              auto pTempProcessor =
-                  pdfium::MakeUnique<CXFA_ItemLayoutProcessor>(pLeaderNode,
-                                                               nullptr);
-              InsertFlowedItem(
-                  this, pTempProcessor.get(), bContainerWidthAutoSize,
-                  bContainerHeightAutoSize, containerSize.height, eFlowStrategy,
-                  &uCurHAlignState, rgCurLineLayoutItems, false, FLT_MAX,
-                  FLT_MAX, fContentWidthLimit, &fContentCurRowY,
-                  &fContentCurRowAvailWidth, &fContentCurRowHeight,
-                  &bAddedItemInRow, &bForceEndPage, pContext, false);
-            }
-          } else {
-            if (JudgeLeaderOrTrailerForOccur(pLeaderNode))
-              AddPendingNode(this, pLeaderNode, true);
-          }
-
-          GotoNextContainerNode(m_pCurChildNode, m_nCurChildNodeStage,
-                                m_pFormNode, true);
-          if (bCreatePage) {
-            bForceEndPage = true;
-            bIsManualBreak = true;
-            if (m_nCurChildNodeStage == XFA_ItemLayoutProcessorStages::Done)
-              bBreakDone = true;
-          }
-          goto SuspendAndCreateNewRow;
-        }
-        case XFA_ItemLayoutProcessorStages::BookendLeader: {
-          CXFA_Node* pLeaderNode = nullptr;
-          if (m_pCurChildPreprocessor) {
-            pProcessor.reset(m_pCurChildPreprocessor);
-            m_pCurChildPreprocessor = nullptr;
-          } else if (m_pPageMgr &&
-                     m_pPageMgr->ProcessBookendLeaderOrTrailer(
-                         m_pCurChildNode, true, pLeaderNode)) {
-            pProcessor = pdfium::MakeUnique<CXFA_ItemLayoutProcessor>(
-                pLeaderNode, m_pPageMgr);
-          }
-
-          if (pProcessor) {
-            if (InsertFlowedItem(
-                    this, pProcessor.get(), bContainerWidthAutoSize,
-                    bContainerHeightAutoSize, containerSize.height,
-                    eFlowStrategy, &uCurHAlignState, rgCurLineLayoutItems,
-                    bUseBreakControl, fAvailHeight, fRealHeight,
-                    fContentWidthLimit, &fContentCurRowY,
-                    &fContentCurRowAvailWidth, &fContentCurRowHeight,
-                    &bAddedItemInRow, &bForceEndPage, pContext,
-                    false) != XFA_ItemLayoutProcessorResult::Done) {
-              goto SuspendAndCreateNewRow;
-            } else {
-              pProcessor.reset();
-            }
-          }
-          break;
-        }
-        case XFA_ItemLayoutProcessorStages::BookendTrailer: {
-          CXFA_Node* pTrailerNode = nullptr;
-          if (m_pCurChildPreprocessor) {
-            pProcessor.reset(m_pCurChildPreprocessor);
-            m_pCurChildPreprocessor = nullptr;
-          } else if (m_pPageMgr &&
-                     m_pPageMgr->ProcessBookendLeaderOrTrailer(
-                         m_pCurChildNode, false, pTrailerNode)) {
-            pProcessor = pdfium::MakeUnique<CXFA_ItemLayoutProcessor>(
-                pTrailerNode, m_pPageMgr);
-          }
-          if (pProcessor) {
-            if (InsertFlowedItem(
-                    this, pProcessor.get(), bContainerWidthAutoSize,
-                    bContainerHeightAutoSize, containerSize.height,
-                    eFlowStrategy, &uCurHAlignState, rgCurLineLayoutItems,
-                    bUseBreakControl, fAvailHeight, fRealHeight,
-                    fContentWidthLimit, &fContentCurRowY,
-                    &fContentCurRowAvailWidth, &fContentCurRowHeight,
-                    &bAddedItemInRow, &bForceEndPage, pContext,
-                    false) != XFA_ItemLayoutProcessorResult::Done) {
-              goto SuspendAndCreateNewRow;
-            } else {
-              pProcessor.reset();
-            }
-          }
-          break;
-        }
-        case XFA_ItemLayoutProcessorStages::Container: {
-          ASSERT(m_pCurChildNode->IsContainerNode());
-          if (m_pCurChildNode->GetElementType() == XFA_Element::Variables)
-            break;
-          if (fContentCurRowY >= fHeightLimit + XFA_LAYOUT_FLOAT_PERCISION &&
-              XFA_ItemLayoutProcessor_IsTakingSpace(m_pCurChildNode)) {
-            bForceEndPage = true;
-            goto SuspendAndCreateNewRow;
-          }
-          if (!m_pCurChildNode->IsContainerNode())
-            break;
-
-          bool bNewRow = false;
-          if (m_pCurChildPreprocessor) {
-            pProcessor.reset(m_pCurChildPreprocessor);
-            m_pCurChildPreprocessor = nullptr;
-            bNewRow = true;
-          } else {
-            pProcessor = pdfium::MakeUnique<CXFA_ItemLayoutProcessor>(
-                m_pCurChildNode, m_pPageMgr);
-          }
-
-          InsertPendingItems(pProcessor.get(), m_pCurChildNode);
-          XFA_ItemLayoutProcessorResult rs = InsertFlowedItem(
-              this, pProcessor.get(), bContainerWidthAutoSize,
-              bContainerHeightAutoSize, containerSize.height, eFlowStrategy,
-              &uCurHAlignState, rgCurLineLayoutItems, bUseBreakControl,
-              fAvailHeight, fRealHeight, fContentWidthLimit, &fContentCurRowY,
-              &fContentCurRowAvailWidth, &fContentCurRowHeight,
-              &bAddedItemInRow, &bForceEndPage, pContext, bNewRow);
-          switch (rs) {
-            case XFA_ItemLayoutProcessorResult::ManualBreak:
-              bIsManualBreak = true;
-            case XFA_ItemLayoutProcessorResult::PageFullBreak:
-              bForceEndPage = true;
-            case XFA_ItemLayoutProcessorResult::RowFullBreak:
-              goto SuspendAndCreateNewRow;
-            case XFA_ItemLayoutProcessorResult::Done:
-            default:
-              fContentCurRowY +=
-                  InsertPendingItems(pProcessor.get(), m_pCurChildNode);
-              pProcessor.reset();
-          }
-          break;
-        }
-        case XFA_ItemLayoutProcessorStages::Done:
-          break;
-        default:
-          break;
-      }
-      GotoNextContainerNode(m_pCurChildNode, m_nCurChildNodeStage, m_pFormNode,
-                            true);
-      if (bAddedItemInRow && eFlowStrategy == XFA_AttributeEnum::Tb)
-        break;
-      continue;
-    SuspendAndCreateNewRow:
-      if (pProcessor)
-        m_pCurChildPreprocessor = pProcessor.release();
-      break;
-    }
-
-    CalculateRowChildPosition(
-        rgCurLineLayoutItems, eFlowStrategy, bContainerHeightAutoSize,
-        bContainerWidthAutoSize, &fContentCalculatedWidth,
-        &fContentCalculatedHeight, &fContentCurRowY, fContentCurRowHeight,
-        fContentWidthLimit, bRootForceTb);
-    m_fWidthLimite = fContentCurRowAvailWidth;
-    if (bForceEndPage)
-      break;
-  }
-
-  bool bRetValue =
-      m_nCurChildNodeStage == XFA_ItemLayoutProcessorStages::Done &&
-      m_PendingNodes.empty();
-  if (bBreakDone)
-    bRetValue = false;
-
-  containerSize = CalculateContainerComponentSizeFromContentSize(
-      m_pFormNode, bContainerWidthAutoSize, fContentCalculatedWidth,
-      bContainerHeightAutoSize, fContentCalculatedHeight, containerSize);
-
-  if (containerSize.height >= XFA_LAYOUT_FLOAT_PERCISION || m_pLayoutItem ||
-      bRetValue) {
-    if (!m_pLayoutItem)
-      m_pLayoutItem = CreateContentLayoutItem(m_pFormNode);
-    containerSize.height = std::max(containerSize.height, 0.f);
-
-    SetCurrentComponentSize(containerSize);
-    if (bForceEndPage)
-      m_fUsedSize = 0;
-    else
-      m_fUsedSize += m_pLayoutItem->m_sSize.height;
-  }
-
-  return bRetValue
-             ? XFA_ItemLayoutProcessorResult::Done
-             : (bIsManualBreak ? XFA_ItemLayoutProcessorResult::ManualBreak
-                               : XFA_ItemLayoutProcessorResult::PageFullBreak);
-}
-
-bool CXFA_ItemLayoutProcessor::CalculateRowChildPosition(
-    std::vector<CXFA_ContentLayoutItem*> (&rgCurLineLayoutItems)[3],
-    XFA_AttributeEnum eFlowStrategy,
-    bool bContainerHeightAutoSize,
-    bool bContainerWidthAutoSize,
-    float* fContentCalculatedWidth,
-    float* fContentCalculatedHeight,
-    float* fContentCurRowY,
-    float fContentCurRowHeight,
-    float fContentWidthLimit,
-    bool bRootForceTb) {
-  int32_t nGroupLengths[3] = {0, 0, 0};
-  float fGroupWidths[3] = {0, 0, 0};
-  int32_t nTotalLength = 0;
-  for (int32_t i = 0; i < 3; i++) {
-    nGroupLengths[i] = pdfium::CollectionSize<int32_t>(rgCurLineLayoutItems[i]);
-    for (int32_t c = nGroupLengths[i], j = 0; j < c; j++) {
-      nTotalLength++;
-      if (XFA_ItemLayoutProcessor_IsTakingSpace(
-              rgCurLineLayoutItems[i][j]->m_pFormNode)) {
-        fGroupWidths[i] += rgCurLineLayoutItems[i][j]->m_sSize.width;
-      }
-    }
-  }
-  if (!nTotalLength) {
-    if (bContainerHeightAutoSize) {
-      *fContentCalculatedHeight =
-          std::min(*fContentCalculatedHeight, *fContentCurRowY);
-    }
-    return false;
-  }
-  if (!m_pLayoutItem)
-    m_pLayoutItem = CreateContentLayoutItem(m_pFormNode);
-
-  if (eFlowStrategy != XFA_AttributeEnum::Rl_tb) {
-    float fCurPos;
-    fCurPos = 0;
-    for (int32_t c = nGroupLengths[0], j = 0; j < c; j++) {
-      if (bRootForceTb) {
-        rgCurLineLayoutItems[0][j]->m_sPos = CalculatePositionedContainerPos(
-            rgCurLineLayoutItems[0][j]->m_pFormNode,
-            rgCurLineLayoutItems[0][j]->m_sSize);
-      } else {
-        rgCurLineLayoutItems[0][j]->m_sPos =
-            CFX_PointF(fCurPos, *fContentCurRowY);
-        if (XFA_ItemLayoutProcessor_IsTakingSpace(
-                rgCurLineLayoutItems[0][j]->m_pFormNode)) {
-          fCurPos += rgCurLineLayoutItems[0][j]->m_sSize.width;
-        }
-      }
-      m_pLayoutItem->AddChild(rgCurLineLayoutItems[0][j]);
-      m_fLastRowWidth = fCurPos;
-    }
-    fCurPos = (fContentWidthLimit + fGroupWidths[0] - fGroupWidths[1] -
-               fGroupWidths[2]) /
-              2;
-    for (int32_t c = nGroupLengths[1], j = 0; j < c; j++) {
-      if (bRootForceTb) {
-        rgCurLineLayoutItems[1][j]->m_sPos = CalculatePositionedContainerPos(
-            rgCurLineLayoutItems[1][j]->m_pFormNode,
-            rgCurLineLayoutItems[1][j]->m_sSize);
-      } else {
-        rgCurLineLayoutItems[1][j]->m_sPos =
-            CFX_PointF(fCurPos, *fContentCurRowY);
-        if (XFA_ItemLayoutProcessor_IsTakingSpace(
-                rgCurLineLayoutItems[1][j]->m_pFormNode)) {
-          fCurPos += rgCurLineLayoutItems[1][j]->m_sSize.width;
-        }
-      }
-      m_pLayoutItem->AddChild(rgCurLineLayoutItems[1][j]);
-      m_fLastRowWidth = fCurPos;
-    }
-    fCurPos = fContentWidthLimit - fGroupWidths[2];
-    for (int32_t c = nGroupLengths[2], j = 0; j < c; j++) {
-      if (bRootForceTb) {
-        rgCurLineLayoutItems[2][j]->m_sPos = CalculatePositionedContainerPos(
-            rgCurLineLayoutItems[2][j]->m_pFormNode,
-            rgCurLineLayoutItems[2][j]->m_sSize);
-      } else {
-        rgCurLineLayoutItems[2][j]->m_sPos =
-            CFX_PointF(fCurPos, *fContentCurRowY);
-        if (XFA_ItemLayoutProcessor_IsTakingSpace(
-                rgCurLineLayoutItems[2][j]->m_pFormNode)) {
-          fCurPos += rgCurLineLayoutItems[2][j]->m_sSize.width;
-        }
-      }
-      m_pLayoutItem->AddChild(rgCurLineLayoutItems[2][j]);
-      m_fLastRowWidth = fCurPos;
-    }
-  } else {
-    float fCurPos;
-    fCurPos = fGroupWidths[0];
-    for (int32_t c = nGroupLengths[0], j = 0; j < c; j++) {
-      if (XFA_ItemLayoutProcessor_IsTakingSpace(
-              rgCurLineLayoutItems[0][j]->m_pFormNode)) {
-        fCurPos -= rgCurLineLayoutItems[0][j]->m_sSize.width;
-      }
-      rgCurLineLayoutItems[0][j]->m_sPos =
-          CFX_PointF(fCurPos, *fContentCurRowY);
-      m_pLayoutItem->AddChild(rgCurLineLayoutItems[0][j]);
-      m_fLastRowWidth = fCurPos;
-    }
-    fCurPos = (fContentWidthLimit + fGroupWidths[0] + fGroupWidths[1] -
-               fGroupWidths[2]) /
-              2;
-    for (int32_t c = nGroupLengths[1], j = 0; j < c; j++) {
-      if (XFA_ItemLayoutProcessor_IsTakingSpace(
-              rgCurLineLayoutItems[1][j]->m_pFormNode)) {
-        fCurPos -= rgCurLineLayoutItems[1][j]->m_sSize.width;
-      }
-      rgCurLineLayoutItems[1][j]->m_sPos =
-          CFX_PointF(fCurPos, *fContentCurRowY);
-      m_pLayoutItem->AddChild(rgCurLineLayoutItems[1][j]);
-      m_fLastRowWidth = fCurPos;
-    }
-    fCurPos = fContentWidthLimit;
-    for (int32_t c = nGroupLengths[2], j = 0; j < c; j++) {
-      if (XFA_ItemLayoutProcessor_IsTakingSpace(
-              rgCurLineLayoutItems[2][j]->m_pFormNode)) {
-        fCurPos -= rgCurLineLayoutItems[2][j]->m_sSize.width;
-      }
-      rgCurLineLayoutItems[2][j]->m_sPos =
-          CFX_PointF(fCurPos, *fContentCurRowY);
-      m_pLayoutItem->AddChild(rgCurLineLayoutItems[2][j]);
-      m_fLastRowWidth = fCurPos;
-    }
-  }
-  m_fLastRowY = *fContentCurRowY;
-  *fContentCurRowY += fContentCurRowHeight;
-  if (bContainerWidthAutoSize) {
-    float fChildSuppliedWidth = fGroupWidths[0];
-    if (fContentWidthLimit < FLT_MAX &&
-        fContentWidthLimit > fChildSuppliedWidth) {
-      fChildSuppliedWidth = fContentWidthLimit;
-    }
-    *fContentCalculatedWidth =
-        std::max(*fContentCalculatedWidth, fChildSuppliedWidth);
-  }
-  if (bContainerHeightAutoSize) {
-    *fContentCalculatedHeight =
-        std::max(*fContentCalculatedHeight, *fContentCurRowY);
-  }
-  return true;
-}
-
-CXFA_Node* CXFA_ItemLayoutProcessor::GetSubformSetParent(
-    CXFA_Node* pSubformSet) {
-  if (pSubformSet && pSubformSet->GetElementType() == XFA_Element::SubformSet) {
-    CXFA_Node* pParent = pSubformSet->GetParent();
-    while (pParent) {
-      if (pParent->GetElementType() != XFA_Element::SubformSet)
-        return pParent;
-      pParent = pParent->GetParent();
-    }
-  }
-  return pSubformSet;
-}
-
-void CXFA_ItemLayoutProcessor::DoLayoutField() {
-  if (m_pLayoutItem)
-    return;
-
-  ASSERT(m_pCurChildNode == XFA_LAYOUT_INVALIDNODE);
-  m_pLayoutItem = CreateContentLayoutItem(m_pFormNode);
-  if (!m_pLayoutItem)
-    return;
-
-  CXFA_Document* pDocument = m_pFormNode->GetDocument();
-  CXFA_FFNotify* pNotify = pDocument->GetNotify();
-  CFX_SizeF size(-1, -1);
-  pNotify->StartFieldDrawLayout(m_pFormNode, size.width, size.height);
-
-  int32_t nRotate = XFA_MapRotation(
-      m_pFormNode->JSObject()->GetInteger(XFA_Attribute::Rotate));
-  if (nRotate == 90 || nRotate == 270)
-    std::swap(size.width, size.height);
-
-  SetCurrentComponentSize(size);
-}
-
-XFA_ItemLayoutProcessorResult CXFA_ItemLayoutProcessor::DoLayout(
-    bool bUseBreakControl,
-    float fHeightLimit,
-    float fRealHeight,
-    CXFA_LayoutContext* pContext) {
-  switch (m_pFormNode->GetElementType()) {
-    case XFA_Element::Subform:
-    case XFA_Element::Area:
-    case XFA_Element::ExclGroup:
-    case XFA_Element::SubformSet: {
-      bool bRootForceTb = false;
-      CXFA_Node* pLayoutNode = GetSubformSetParent(m_pFormNode);
-      XFA_AttributeEnum eLayoutStrategy = GetLayout(pLayoutNode, &bRootForceTb);
-      switch (eLayoutStrategy) {
-        case XFA_AttributeEnum::Tb:
-        case XFA_AttributeEnum::Lr_tb:
-        case XFA_AttributeEnum::Rl_tb:
-          return DoLayoutFlowedContainer(bUseBreakControl, eLayoutStrategy,
-                                         fHeightLimit, fRealHeight, pContext,
-                                         bRootForceTb);
-        case XFA_AttributeEnum::Position:
-        case XFA_AttributeEnum::Row:
-        case XFA_AttributeEnum::Rl_row:
-        default:
-          DoLayoutPositionedContainer(pContext);
-          m_nCurChildNodeStage = XFA_ItemLayoutProcessorStages::Done;
-          return XFA_ItemLayoutProcessorResult::Done;
-        case XFA_AttributeEnum::Table:
-          DoLayoutTableContainer(pLayoutNode);
-          m_nCurChildNodeStage = XFA_ItemLayoutProcessorStages::Done;
-          return XFA_ItemLayoutProcessorResult::Done;
-      }
-    }
-    case XFA_Element::Draw:
-    case XFA_Element::Field:
-      DoLayoutField();
-      m_nCurChildNodeStage = XFA_ItemLayoutProcessorStages::Done;
-      return XFA_ItemLayoutProcessorResult::Done;
-    case XFA_Element::ContentArea:
-      return XFA_ItemLayoutProcessorResult::Done;
-    default:
-      return XFA_ItemLayoutProcessorResult::Done;
-  }
-}
-
-CFX_SizeF CXFA_ItemLayoutProcessor::GetCurrentComponentSize() {
-  return CFX_SizeF(m_pLayoutItem->m_sSize.width, m_pLayoutItem->m_sSize.height);
-}
-
-void CXFA_ItemLayoutProcessor::SetCurrentComponentPos(const CFX_PointF& pos) {
-  m_pLayoutItem->m_sPos = pos;
-}
-
-void CXFA_ItemLayoutProcessor::SetCurrentComponentSize(const CFX_SizeF& size) {
-  m_pLayoutItem->m_sSize = size;
-}
-
-bool CXFA_ItemLayoutProcessor::JudgeLeaderOrTrailerForOccur(
-    CXFA_Node* pFormNode) {
-  if (!pFormNode)
-    return false;
-
-  CXFA_Node* pTemplate = pFormNode->GetTemplateNodeIfExists();
-  if (!pTemplate)
-    pTemplate = pFormNode;
-
-  int32_t iMax =
-      pTemplate->GetFirstChildByClass<CXFA_Occur>(XFA_Element::Occur)->GetMax();
-  if (iMax < 0)
-    return true;
-
-  int32_t iCount = m_PendingNodesCount[pTemplate];
-  if (iCount >= iMax)
-    return false;
-
-  m_PendingNodesCount[pTemplate] = iCount + 1;
-  return true;
-}
diff --git a/xfa/fxfa/parser/cxfa_itemlayoutprocessor.h b/xfa/fxfa/parser/cxfa_itemlayoutprocessor.h
deleted file mode 100644
index e178095..0000000
--- a/xfa/fxfa/parser/cxfa_itemlayoutprocessor.h
+++ /dev/null
@@ -1,171 +0,0 @@
-// Copyright 2014 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_ITEMLAYOUTPROCESSOR_H_
-#define XFA_FXFA_PARSER_CXFA_ITEMLAYOUTPROCESSOR_H_
-
-#include <float.h>
-
-#include <list>
-#include <map>
-#include <tuple>
-#include <vector>
-
-#include "core/fxcrt/fx_coordinates.h"
-#include "xfa/fxfa/fxfa_basic.h"
-
-#define XFA_LAYOUT_INVALIDNODE ((CXFA_Node*)(intptr_t)-1)
-#define XFA_LAYOUT_FLOAT_PERCISION (0.0005f)
-
-class CXFA_ContainerLayoutItem;
-class CXFA_ContentLayoutItem;
-class CXFA_ItemLayoutProcessor;
-class CXFA_LayoutContext;
-class CXFA_LayoutPageMgr;
-class CXFA_LayoutProcessor;
-class CXFA_Node;
-
-enum class XFA_ItemLayoutProcessorResult {
-  Done,
-  PageFullBreak,
-  RowFullBreak,
-  ManualBreak,
-};
-
-enum class XFA_ItemLayoutProcessorStages {
-  None,
-  BookendLeader,
-  BreakBefore,
-  Keep,
-  Container,
-  BreakAfter,
-  BookendTrailer,
-  Done,
-};
-
-bool XFA_ItemLayoutProcessor_IsTakingSpace(CXFA_Node* pNode);
-
-class CXFA_ItemLayoutProcessor {
- public:
-  static bool IncrementRelayoutNode(CXFA_LayoutProcessor* pLayoutProcessor,
-                                    CXFA_Node* pNode,
-                                    CXFA_Node* pParentNode);
-
-  CXFA_ItemLayoutProcessor(CXFA_Node* pNode, CXFA_LayoutPageMgr* pPageMgr);
-  ~CXFA_ItemLayoutProcessor();
-
-  XFA_ItemLayoutProcessorResult DoLayout(bool bUseBreakControl,
-                                         float fHeightLimit,
-                                         float fRealHeight,
-                                         CXFA_LayoutContext* pContext);
-  void DoLayoutPageArea(CXFA_ContainerLayoutItem* pPageAreaLayoutItem);
-
-  CFX_SizeF GetCurrentComponentSize();
-  CXFA_Node* GetFormNode() { return m_pFormNode; }
-  bool HasLayoutItem() const { return !!m_pLayoutItem; }
-  CXFA_ContentLayoutItem* ExtractLayoutItem();
-  void SplitLayoutItem(float fSplitPos);
-
-  float FindSplitPos(float fProposedSplitPos);
-
-  bool ProcessKeepForSplit(
-      CXFA_ItemLayoutProcessor* pParentProcessor,
-      CXFA_ItemLayoutProcessor* pChildProcessor,
-      XFA_ItemLayoutProcessorResult eRetValue,
-      std::vector<CXFA_ContentLayoutItem*>* rgCurLineLayoutItem,
-      float* fContentCurRowAvailWidth,
-      float* fContentCurRowHeight,
-      float* fContentCurRowY,
-      bool* bAddedItemInRow,
-      bool* bForceEndPage,
-      XFA_ItemLayoutProcessorResult* result);
-  void ProcessUnUseOverFlow(CXFA_Node* pLeaderNode,
-                            CXFA_Node* pTrailerNode,
-                            CXFA_ContentLayoutItem* pTrailerItem,
-                            CXFA_Node* pFormNode);
-  bool IsAddNewRowForTrailer(CXFA_ContentLayoutItem* pTrailerItem);
-  bool JudgeLeaderOrTrailerForOccur(CXFA_Node* pFormNode);
-
-  CXFA_ContentLayoutItem* CreateContentLayoutItem(CXFA_Node* pFormNode);
-
-  CXFA_Node* m_pFormNode;
-  CXFA_ContentLayoutItem* m_pLayoutItem;
-  CXFA_Node* m_pCurChildNode;
-  float m_fUsedSize;
-  CXFA_LayoutPageMgr* m_pPageMgr;
-  std::list<CXFA_Node*> m_PendingNodes;
-  bool m_bBreakPending;
-  std::vector<float> m_rgSpecifiedColumnWidths;
-  std::vector<CXFA_ContentLayoutItem*> m_arrayKeepItems;
-  float m_fLastRowWidth;
-  float m_fLastRowY;
-  bool m_bUseInheriated;
-  XFA_ItemLayoutProcessorResult m_ePreProcessRs;
-
- private:
-  void SetCurrentComponentPos(const CFX_PointF& pos);
-  void SetCurrentComponentSize(const CFX_SizeF& size);
-
-  void SplitLayoutItem(CXFA_ContentLayoutItem* pLayoutItem,
-                       CXFA_ContentLayoutItem* pSecondParent,
-                       float fSplitPos);
-  float InsertKeepLayoutItems();
-  bool CalculateRowChildPosition(
-      std::vector<CXFA_ContentLayoutItem*> (&rgCurLineLayoutItems)[3],
-      XFA_AttributeEnum eFlowStrategy,
-      bool bContainerHeightAutoSize,
-      bool bContainerWidthAutoSize,
-      float* fContentCalculatedWidth,
-      float* fContentCalculatedHeight,
-      float* fContentCurRowY,
-      float fContentCurRowHeight,
-      float fContentWidthLimit,
-      bool bRootForceTb);
-  void ProcessUnUseBinds(CXFA_Node* pFormNode);
-  bool JudgePutNextPage(CXFA_ContentLayoutItem* pParentLayoutItem,
-                        float fChildHeight,
-                        std::vector<CXFA_ContentLayoutItem*>* pKeepItems);
-
-  void DoLayoutPositionedContainer(CXFA_LayoutContext* pContext);
-  void DoLayoutTableContainer(CXFA_Node* pLayoutNode);
-  XFA_ItemLayoutProcessorResult DoLayoutFlowedContainer(
-      bool bUseBreakControl,
-      XFA_AttributeEnum eFlowStrategy,
-      float fHeightLimit,
-      float fRealHeight,
-      CXFA_LayoutContext* pContext,
-      bool bRootForceTb);
-  void DoLayoutField();
-
-  void GotoNextContainerNode(CXFA_Node*& pCurActionNode,
-                             XFA_ItemLayoutProcessorStages& nCurStage,
-                             CXFA_Node* pParentContainer,
-                             bool bUsePageBreak);
-
-  bool ProcessKeepNodesForCheckNext(CXFA_Node*& pCurActionNode,
-                                    XFA_ItemLayoutProcessorStages& nCurStage,
-                                    CXFA_Node*& pNextContainer,
-                                    bool& bLastKeepNode);
-
-  bool ProcessKeepNodesForBreakBefore(CXFA_Node*& pCurActionNode,
-                                      XFA_ItemLayoutProcessorStages& nCurStage,
-                                      CXFA_Node* pContainerNode);
-
-  CXFA_Node* GetSubformSetParent(CXFA_Node* pSubformSet);
-
-  bool m_bKeepBreakFinish;
-  bool m_bIsProcessKeep;
-  CXFA_Node* m_pKeepHeadNode;
-  CXFA_Node* m_pKeepTailNode;
-  CXFA_ContentLayoutItem* m_pOldLayoutItem;
-  CXFA_ItemLayoutProcessor* m_pCurChildPreprocessor;
-  XFA_ItemLayoutProcessorStages m_nCurChildNodeStage;
-  std::map<CXFA_Node*, int32_t> m_PendingNodesCount;
-  float m_fWidthLimite;
-  bool m_bHasAvailHeight;
-};
-
-#endif  // XFA_FXFA_PARSER_CXFA_ITEMLAYOUTPROCESSOR_H_
diff --git a/xfa/fxfa/parser/cxfa_items.cpp b/xfa/fxfa/parser/cxfa_items.cpp
index 06feddb..89fee2b 100644
--- a/xfa/fxfa/parser/cxfa_items.cpp
+++ b/xfa/fxfa/parser/cxfa_items.cpp
@@ -6,23 +6,21 @@
 
 #include "xfa/fxfa/parser/cxfa_items.h"
 
-#include "fxjs/xfa/cjx_items.h"
+#include "fxjs/xfa/cjx_node.h"
 #include "third_party/base/ptr_util.h"
 
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kItemsAttributeData[] = {
     {XFA_Attribute::Id, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Name, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Ref, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Use, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Presence, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::Visible},
+     (void*)XFA_AttributeValue::Visible},
     {XFA_Attribute::Save, XFA_AttributeType::Boolean, (void*)0},
     {XFA_Attribute::Usehref, XFA_AttributeType::CData, nullptr},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"items";
+};
 
 }  // namespace
 
@@ -32,9 +30,8 @@
                 (XFA_XDPPACKET_Template | XFA_XDPPACKET_Form),
                 XFA_ObjectType::Node,
                 XFA_Element::Items,
-                nullptr,
-                kAttributeData,
-                kName,
-                pdfium::MakeUnique<CJX_Items>(this)) {}
+                {},
+                kItemsAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_Items::~CXFA_Items() {}
+CXFA_Items::~CXFA_Items() = default;
diff --git a/xfa/fxfa/parser/cxfa_items.h b/xfa/fxfa/parser/cxfa_items.h
index 586fabd..609b028 100644
--- a/xfa/fxfa/parser/cxfa_items.h
+++ b/xfa/fxfa/parser/cxfa_items.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Items : public CXFA_Node {
+class CXFA_Items final : public CXFA_Node {
  public:
   CXFA_Items(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Items() override;
diff --git a/xfa/fxfa/parser/cxfa_jog.cpp b/xfa/fxfa/parser/cxfa_jog.cpp
index 3735e2f..f979259 100644
--- a/xfa/fxfa/parser/cxfa_jog.cpp
+++ b/xfa/fxfa/parser/cxfa_jog.cpp
@@ -6,14 +6,15 @@
 
 #include "xfa/fxfa/parser/cxfa_jog.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kJogAttributeData[] = {
     {XFA_Attribute::Desc, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Lock, XFA_AttributeType::Integer, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"jog";
+};
 
 }  // namespace
 
@@ -23,8 +24,8 @@
                 XFA_XDPPACKET_Config,
                 XFA_ObjectType::ContentNode,
                 XFA_Element::Jog,
-                nullptr,
-                kAttributeData,
-                kName) {}
+                {},
+                kJogAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_Jog::~CXFA_Jog() {}
+CXFA_Jog::~CXFA_Jog() = default;
diff --git a/xfa/fxfa/parser/cxfa_jog.h b/xfa/fxfa/parser/cxfa_jog.h
index 266ccd1..a40a488 100644
--- a/xfa/fxfa/parser/cxfa_jog.h
+++ b/xfa/fxfa/parser/cxfa_jog.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Jog : public CXFA_Node {
+class CXFA_Jog final : public CXFA_Node {
  public:
   CXFA_Jog(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Jog() override;
diff --git a/xfa/fxfa/parser/cxfa_keep.cpp b/xfa/fxfa/parser/cxfa_keep.cpp
index beb22fa..e500ee6 100644
--- a/xfa/fxfa/parser/cxfa_keep.cpp
+++ b/xfa/fxfa/parser/cxfa_keep.cpp
@@ -6,26 +6,26 @@
 
 #include "xfa/fxfa/parser/cxfa_keep.h"
 
-#include "fxjs/xfa/cjx_keep.h"
+#include "fxjs/xfa/cjx_node.h"
 #include "third_party/base/ptr_util.h"
 
 namespace {
 
-const CXFA_Node::PropertyData kPropertyData[] = {{XFA_Element::Extras, 1, 0},
-                                                 {XFA_Element::Unknown, 0, 0}};
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::PropertyData kKeepPropertyData[] = {
+    {XFA_Element::Extras, 1, 0},
+};
+
+const CXFA_Node::AttributeData kKeepAttributeData[] = {
     {XFA_Attribute::Id, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Next, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::None},
+     (void*)XFA_AttributeValue::None},
     {XFA_Attribute::Use, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Previous, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::None},
+     (void*)XFA_AttributeValue::None},
     {XFA_Attribute::Usehref, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Intact, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::None},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"keep";
+     (void*)XFA_AttributeValue::None},
+};
 
 }  // namespace
 
@@ -35,9 +35,8 @@
                 (XFA_XDPPACKET_Template | XFA_XDPPACKET_Form),
                 XFA_ObjectType::Node,
                 XFA_Element::Keep,
-                kPropertyData,
-                kAttributeData,
-                kName,
-                pdfium::MakeUnique<CJX_Keep>(this)) {}
+                kKeepPropertyData,
+                kKeepAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_Keep::~CXFA_Keep() {}
+CXFA_Keep::~CXFA_Keep() = default;
diff --git a/xfa/fxfa/parser/cxfa_keep.h b/xfa/fxfa/parser/cxfa_keep.h
index 7d53f96..0d4a2e0 100644
--- a/xfa/fxfa/parser/cxfa_keep.h
+++ b/xfa/fxfa/parser/cxfa_keep.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Keep : public CXFA_Node {
+class CXFA_Keep final : public CXFA_Node {
  public:
   CXFA_Keep(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Keep() override;
diff --git a/xfa/fxfa/parser/cxfa_keyusage.cpp b/xfa/fxfa/parser/cxfa_keyusage.cpp
index 13054be..dda5c10 100644
--- a/xfa/fxfa/parser/cxfa_keyusage.cpp
+++ b/xfa/fxfa/parser/cxfa_keyusage.cpp
@@ -6,18 +6,18 @@
 
 #include "xfa/fxfa/parser/cxfa_keyusage.h"
 
-#include "fxjs/xfa/cjx_keyusage.h"
+#include "fxjs/xfa/cjx_node.h"
 #include "third_party/base/ptr_util.h"
 
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kKeyUsageAttributeData[] = {
     {XFA_Attribute::Id, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Use, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::NonRepudiation, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::EncipherOnly, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Type, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::Optional},
+     (void*)XFA_AttributeValue::Optional},
     {XFA_Attribute::DigitalSignature, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::CrlSign, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::KeyAgreement, XFA_AttributeType::CData, nullptr},
@@ -26,9 +26,7 @@
     {XFA_Attribute::DataEncipherment, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::KeyCertSign, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::DecipherOnly, XFA_AttributeType::CData, nullptr},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"keyUsage";
+};
 
 }  // namespace
 
@@ -38,9 +36,8 @@
                 (XFA_XDPPACKET_Template | XFA_XDPPACKET_Form),
                 XFA_ObjectType::Node,
                 XFA_Element::KeyUsage,
-                nullptr,
-                kAttributeData,
-                kName,
-                pdfium::MakeUnique<CJX_KeyUsage>(this)) {}
+                {},
+                kKeyUsageAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_KeyUsage::~CXFA_KeyUsage() {}
+CXFA_KeyUsage::~CXFA_KeyUsage() = default;
diff --git a/xfa/fxfa/parser/cxfa_keyusage.h b/xfa/fxfa/parser/cxfa_keyusage.h
index b258074..3409e3f 100644
--- a/xfa/fxfa/parser/cxfa_keyusage.h
+++ b/xfa/fxfa/parser/cxfa_keyusage.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_KeyUsage : public CXFA_Node {
+class CXFA_KeyUsage final : public CXFA_Node {
  public:
   CXFA_KeyUsage(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_KeyUsage() override;
diff --git a/xfa/fxfa/parser/cxfa_labelprinter.cpp b/xfa/fxfa/parser/cxfa_labelprinter.cpp
index 55b04da..40f3616 100644
--- a/xfa/fxfa/parser/cxfa_labelprinter.cpp
+++ b/xfa/fxfa/parser/cxfa_labelprinter.cpp
@@ -6,22 +6,24 @@
 
 #include "xfa/fxfa/parser/cxfa_labelprinter.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::PropertyData kPropertyData[] = {
+const CXFA_Node::PropertyData kLabelPrinterPropertyData[] = {
     {XFA_Element::FontInfo, 1, 0},
     {XFA_Element::Xdc, 1, 0},
     {XFA_Element::BatchOutput, 1, 0},
     {XFA_Element::FlipLabel, 1, 0},
-    {XFA_Element::Unknown, 0, 0}};
-const CXFA_Node::AttributeData kAttributeData[] = {
+};
+
+const CXFA_Node::AttributeData kLabelPrinterAttributeData[] = {
     {XFA_Attribute::Name, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::Zpl},
+     (void*)XFA_AttributeValue::Zpl},
     {XFA_Attribute::Desc, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Lock, XFA_AttributeType::Integer, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"labelPrinter";
+};
 
 }  // namespace
 
@@ -31,8 +33,8 @@
                 XFA_XDPPACKET_Config,
                 XFA_ObjectType::Node,
                 XFA_Element::LabelPrinter,
-                kPropertyData,
-                kAttributeData,
-                kName) {}
+                kLabelPrinterPropertyData,
+                kLabelPrinterAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_LabelPrinter::~CXFA_LabelPrinter() {}
+CXFA_LabelPrinter::~CXFA_LabelPrinter() = default;
diff --git a/xfa/fxfa/parser/cxfa_labelprinter.h b/xfa/fxfa/parser/cxfa_labelprinter.h
index e3f5d3b..74a5e82 100644
--- a/xfa/fxfa/parser/cxfa_labelprinter.h
+++ b/xfa/fxfa/parser/cxfa_labelprinter.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_LabelPrinter : public CXFA_Node {
+class CXFA_LabelPrinter final : public CXFA_Node {
  public:
   CXFA_LabelPrinter(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_LabelPrinter() override;
diff --git a/xfa/fxfa/parser/cxfa_layout.cpp b/xfa/fxfa/parser/cxfa_layout.cpp
index bc2933f..12d6f49 100644
--- a/xfa/fxfa/parser/cxfa_layout.cpp
+++ b/xfa/fxfa/parser/cxfa_layout.cpp
@@ -6,14 +6,15 @@
 
 #include "xfa/fxfa/parser/cxfa_layout.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kLayoutAttributeData[] = {
     {XFA_Attribute::Desc, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Lock, XFA_AttributeType::Integer, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"layout";
+};
 
 }  // namespace
 
@@ -23,8 +24,8 @@
                 XFA_XDPPACKET_Config,
                 XFA_ObjectType::ContentNode,
                 XFA_Element::Layout,
-                nullptr,
-                kAttributeData,
-                kName) {}
+                {},
+                kLayoutAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_Layout::~CXFA_Layout() {}
+CXFA_Layout::~CXFA_Layout() = default;
diff --git a/xfa/fxfa/parser/cxfa_layout.h b/xfa/fxfa/parser/cxfa_layout.h
index 93e069e..ad25efa 100644
--- a/xfa/fxfa/parser/cxfa_layout.h
+++ b/xfa/fxfa/parser/cxfa_layout.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Layout : public CXFA_Node {
+class CXFA_Layout final : public CXFA_Node {
  public:
   CXFA_Layout(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Layout() override;
diff --git a/xfa/fxfa/parser/cxfa_layoutcontext.h b/xfa/fxfa/parser/cxfa_layoutcontext.h
deleted file mode 100644
index a133ee1..0000000
--- a/xfa/fxfa/parser/cxfa_layoutcontext.h
+++ /dev/null
@@ -1,32 +0,0 @@
-// 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_LAYOUTCONTEXT_H_
-#define XFA_FXFA_PARSER_CXFA_LAYOUTCONTEXT_H_
-
-#include <vector>
-
-class CXFA_ItemLayoutProcess;
-class CXFA_Node;
-
-class CXFA_LayoutContext {
- public:
-  CXFA_LayoutContext()
-      : m_prgSpecifiedColumnWidths(nullptr),
-        m_fCurColumnWidth(0),
-        m_bCurColumnWidthAvaiable(false),
-        m_pOverflowProcessor(nullptr),
-        m_pOverflowNode(nullptr) {}
-  ~CXFA_LayoutContext() {}
-
-  std::vector<float>* m_prgSpecifiedColumnWidths;
-  float m_fCurColumnWidth;
-  bool m_bCurColumnWidthAvaiable;
-  CXFA_ItemLayoutProcessor* m_pOverflowProcessor;
-  CXFA_Node* m_pOverflowNode;
-};
-
-#endif  // XFA_FXFA_PARSER_CXFA_LAYOUTCONTEXT_H_
diff --git a/xfa/fxfa/parser/cxfa_layoutitem.cpp b/xfa/fxfa/parser/cxfa_layoutitem.cpp
deleted file mode 100644
index 7fb921a..0000000
--- a/xfa/fxfa/parser/cxfa_layoutitem.cpp
+++ /dev/null
@@ -1,226 +0,0 @@
-// Copyright 2016 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
-
-#include "xfa/fxfa/parser/cxfa_layoutitem.h"
-
-#include "fxjs/xfa/cjx_object.h"
-#include "xfa/fxfa/cxfa_ffnotify.h"
-#include "xfa/fxfa/parser/cxfa_containerlayoutitem.h"
-#include "xfa/fxfa/parser/cxfa_contentlayoutitem.h"
-#include "xfa/fxfa/parser/cxfa_margin.h"
-#include "xfa/fxfa/parser/cxfa_measurement.h"
-#include "xfa/fxfa/parser/cxfa_node.h"
-
-void XFA_ReleaseLayoutItem(CXFA_LayoutItem* pLayoutItem) {
-  CXFA_LayoutItem* pNode = pLayoutItem->m_pFirstChild;
-  CXFA_FFNotify* pNotify = pLayoutItem->m_pFormNode->GetDocument()->GetNotify();
-  CXFA_LayoutProcessor* pDocLayout =
-      pLayoutItem->m_pFormNode->GetDocument()->GetDocLayout();
-  while (pNode) {
-    CXFA_LayoutItem* pNext = pNode->m_pNextSibling;
-    pNode->m_pParent = nullptr;
-    pNotify->OnLayoutItemRemoving(pDocLayout, pNode);
-    XFA_ReleaseLayoutItem(pNode);
-    pNode = pNext;
-  }
-  pNotify->OnLayoutItemRemoving(pDocLayout, pLayoutItem);
-  if (pLayoutItem->m_pFormNode->GetElementType() == XFA_Element::PageArea) {
-    pNotify->OnPageEvent(static_cast<CXFA_ContainerLayoutItem*>(pLayoutItem),
-                         XFA_PAGEVIEWEVENT_PostRemoved);
-  }
-  delete pLayoutItem;
-}
-
-CXFA_LayoutItem::CXFA_LayoutItem(CXFA_Node* pNode, bool bIsContentLayoutItem)
-    : m_pFormNode(pNode),
-      m_pParent(nullptr),
-      m_pNextSibling(nullptr),
-      m_pFirstChild(nullptr),
-      m_bIsContentLayoutItem(bIsContentLayoutItem) {}
-
-CXFA_LayoutItem::~CXFA_LayoutItem() {}
-
-CXFA_ContainerLayoutItem* CXFA_LayoutItem::AsContainerLayoutItem() {
-  return IsContainerLayoutItem() ? static_cast<CXFA_ContainerLayoutItem*>(this)
-                                 : nullptr;
-}
-
-CXFA_ContentLayoutItem* CXFA_LayoutItem::AsContentLayoutItem() {
-  return IsContentLayoutItem() ? static_cast<CXFA_ContentLayoutItem*>(this)
-                               : nullptr;
-}
-
-CXFA_ContainerLayoutItem* CXFA_LayoutItem::GetPage() const {
-  for (CXFA_LayoutItem* pCurNode = const_cast<CXFA_LayoutItem*>(this); pCurNode;
-       pCurNode = pCurNode->m_pParent) {
-    if (pCurNode->m_pFormNode->GetElementType() == XFA_Element::PageArea)
-      return static_cast<CXFA_ContainerLayoutItem*>(pCurNode);
-  }
-  return nullptr;
-}
-
-CFX_RectF CXFA_LayoutItem::GetRect(bool bRelative) const {
-  ASSERT(m_bIsContentLayoutItem);
-
-  auto* pThis = static_cast<const CXFA_ContentLayoutItem*>(this);
-  CFX_PointF sPos = pThis->m_sPos;
-  CFX_SizeF sSize = pThis->m_sSize;
-  if (bRelative)
-    return CFX_RectF(sPos, sSize);
-
-  for (CXFA_LayoutItem* pLayoutItem = pThis->m_pParent; pLayoutItem;
-       pLayoutItem = pLayoutItem->m_pParent) {
-    if (CXFA_ContentLayoutItem* pContent = pLayoutItem->AsContentLayoutItem()) {
-      sPos += pContent->m_sPos;
-      CXFA_Margin* pMarginNode =
-          pLayoutItem->m_pFormNode->GetFirstChildByClass<CXFA_Margin>(
-              XFA_Element::Margin);
-      if (pMarginNode) {
-        sPos += CFX_PointF(pMarginNode->JSObject()
-                               ->GetMeasure(XFA_Attribute::LeftInset)
-                               .ToUnit(XFA_Unit::Pt),
-                           pMarginNode->JSObject()
-                               ->GetMeasure(XFA_Attribute::TopInset)
-                               .ToUnit(XFA_Unit::Pt));
-      }
-      continue;
-    }
-
-    if (pLayoutItem->m_pFormNode->GetElementType() ==
-        XFA_Element::ContentArea) {
-      sPos += CFX_PointF(pLayoutItem->m_pFormNode->JSObject()
-                             ->GetMeasure(XFA_Attribute::X)
-                             .ToUnit(XFA_Unit::Pt),
-                         pLayoutItem->m_pFormNode->JSObject()
-                             ->GetMeasure(XFA_Attribute::Y)
-                             .ToUnit(XFA_Unit::Pt));
-      break;
-    }
-    if (pLayoutItem->m_pFormNode->GetElementType() == XFA_Element::PageArea)
-      break;
-  }
-  return CFX_RectF(sPos, sSize);
-}
-
-CXFA_LayoutItem* CXFA_LayoutItem::GetFirst() {
-  ASSERT(m_bIsContentLayoutItem);
-  CXFA_ContentLayoutItem* pCurNode = static_cast<CXFA_ContentLayoutItem*>(this);
-  while (pCurNode->m_pPrev)
-    pCurNode = pCurNode->m_pPrev;
-
-  return pCurNode;
-}
-
-const CXFA_LayoutItem* CXFA_LayoutItem::GetLast() const {
-  ASSERT(m_bIsContentLayoutItem);
-  const CXFA_ContentLayoutItem* pCurNode =
-      static_cast<const CXFA_ContentLayoutItem*>(this);
-  while (pCurNode->m_pNext)
-    pCurNode = pCurNode->m_pNext;
-
-  return pCurNode;
-}
-
-CXFA_LayoutItem* CXFA_LayoutItem::GetPrev() const {
-  ASSERT(m_bIsContentLayoutItem);
-
-  return static_cast<const CXFA_ContentLayoutItem*>(this)->m_pPrev;
-}
-
-CXFA_LayoutItem* CXFA_LayoutItem::GetNext() const {
-  ASSERT(m_bIsContentLayoutItem);
-  return static_cast<const CXFA_ContentLayoutItem*>(this)->m_pNext;
-}
-
-int32_t CXFA_LayoutItem::GetIndex() const {
-  ASSERT(m_bIsContentLayoutItem);
-  int32_t iIndex = 0;
-  const CXFA_ContentLayoutItem* pCurNode =
-      static_cast<const CXFA_ContentLayoutItem*>(this);
-  while (pCurNode->m_pPrev) {
-    pCurNode = pCurNode->m_pPrev;
-    ++iIndex;
-  }
-  return iIndex;
-}
-
-int32_t CXFA_LayoutItem::GetCount() const {
-  ASSERT(m_bIsContentLayoutItem);
-
-  int32_t iCount = GetIndex() + 1;
-  const CXFA_ContentLayoutItem* pCurNode =
-      static_cast<const CXFA_ContentLayoutItem*>(this);
-  while (pCurNode->m_pNext) {
-    pCurNode = pCurNode->m_pNext;
-    iCount++;
-  }
-  return iCount;
-}
-
-void CXFA_LayoutItem::AddChild(CXFA_LayoutItem* pChildItem) {
-  if (pChildItem->m_pParent)
-    pChildItem->m_pParent->RemoveChild(pChildItem);
-
-  pChildItem->m_pParent = this;
-  if (!m_pFirstChild) {
-    m_pFirstChild = pChildItem;
-    return;
-  }
-
-  CXFA_LayoutItem* pExistingChildItem = m_pFirstChild;
-  while (pExistingChildItem->m_pNextSibling)
-    pExistingChildItem = pExistingChildItem->m_pNextSibling;
-
-  pExistingChildItem->m_pNextSibling = pChildItem;
-}
-
-void CXFA_LayoutItem::AddHeadChild(CXFA_LayoutItem* pChildItem) {
-  if (pChildItem->m_pParent)
-    pChildItem->m_pParent->RemoveChild(pChildItem);
-
-  pChildItem->m_pParent = this;
-  if (!m_pFirstChild) {
-    m_pFirstChild = pChildItem;
-    return;
-  }
-
-  CXFA_LayoutItem* pExistingChildItem = m_pFirstChild;
-  m_pFirstChild = pChildItem;
-  m_pFirstChild->m_pNextSibling = pExistingChildItem;
-}
-
-void CXFA_LayoutItem::InsertChild(CXFA_LayoutItem* pBeforeItem,
-                                  CXFA_LayoutItem* pChildItem) {
-  if (pBeforeItem->m_pParent != this)
-    return;
-  if (pChildItem->m_pParent)
-    pChildItem->m_pParent = nullptr;
-
-  pChildItem->m_pParent = this;
-
-  CXFA_LayoutItem* pExistingChildItem = pBeforeItem->m_pNextSibling;
-  pBeforeItem->m_pNextSibling = pChildItem;
-  pChildItem->m_pNextSibling = pExistingChildItem;
-}
-
-void CXFA_LayoutItem::RemoveChild(CXFA_LayoutItem* pChildItem) {
-  if (pChildItem->m_pParent != this)
-    return;
-
-  if (m_pFirstChild == pChildItem) {
-    m_pFirstChild = pChildItem->m_pNextSibling;
-  } else {
-    CXFA_LayoutItem* pExistingChildItem = m_pFirstChild;
-    while (pExistingChildItem &&
-           pExistingChildItem->m_pNextSibling != pChildItem) {
-      pExistingChildItem = pExistingChildItem->m_pNextSibling;
-    }
-    if (pExistingChildItem)
-      pExistingChildItem->m_pNextSibling = pChildItem->m_pNextSibling;
-  }
-  pChildItem->m_pNextSibling = nullptr;
-  pChildItem->m_pParent = nullptr;
-}
diff --git a/xfa/fxfa/parser/cxfa_layoutitem.h b/xfa/fxfa/parser/cxfa_layoutitem.h
deleted file mode 100644
index 9c08860..0000000
--- a/xfa/fxfa/parser/cxfa_layoutitem.h
+++ /dev/null
@@ -1,56 +0,0 @@
-// Copyright 2016 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_LAYOUTITEM_H_
-#define XFA_FXFA_PARSER_CXFA_LAYOUTITEM_H_
-
-#include "xfa/fxfa/parser/cxfa_document.h"
-
-class CXFA_ContainerLayoutItem;
-class CXFA_ContentLayoutItem;
-class CXFA_LayoutProcessor;
-
-void XFA_ReleaseLayoutItem(CXFA_LayoutItem* pLayoutItem);
-
-class CXFA_LayoutItem {
- public:
-  virtual ~CXFA_LayoutItem();
-
-  bool IsContainerLayoutItem() const { return !m_bIsContentLayoutItem; }
-  bool IsContentLayoutItem() const { return m_bIsContentLayoutItem; }
-  CXFA_ContainerLayoutItem* AsContainerLayoutItem();
-  CXFA_ContentLayoutItem* AsContentLayoutItem();
-
-  CXFA_ContainerLayoutItem* GetPage() const;
-  CXFA_Node* GetFormNode() const { return m_pFormNode; }
-  CFX_RectF GetRect(bool bRelative) const;
-
-  int32_t GetIndex() const;
-  int32_t GetCount() const;
-
-  CXFA_LayoutItem* GetParent() const { return m_pParent; }
-  CXFA_LayoutItem* GetFirst();
-  const CXFA_LayoutItem* GetLast() const;
-  CXFA_LayoutItem* GetPrev() const;
-  CXFA_LayoutItem* GetNext() const;
-
-  void AddChild(CXFA_LayoutItem* pChildItem);
-  void AddHeadChild(CXFA_LayoutItem* pChildItem);
-  void RemoveChild(CXFA_LayoutItem* pChildItem);
-  void InsertChild(CXFA_LayoutItem* pBeforeItem, CXFA_LayoutItem* pChildItem);
-
-  CXFA_Node* m_pFormNode;
-  CXFA_LayoutItem* m_pParent;
-  CXFA_LayoutItem* m_pNextSibling;
-  CXFA_LayoutItem* m_pFirstChild;
-
- protected:
-  CXFA_LayoutItem(CXFA_Node* pNode, bool bIsContentLayoutItem);
-
-  bool m_bIsContentLayoutItem;
-};
-
-#endif  // XFA_FXFA_PARSER_CXFA_LAYOUTITEM_H_
diff --git a/xfa/fxfa/parser/cxfa_layoutpagemgr.cpp b/xfa/fxfa/parser/cxfa_layoutpagemgr.cpp
deleted file mode 100644
index 123cafb..0000000
--- a/xfa/fxfa/parser/cxfa_layoutpagemgr.cpp
+++ /dev/null
@@ -1,2014 +0,0 @@
-// Copyright 2014 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
-
-#include "xfa/fxfa/parser/cxfa_layoutpagemgr.h"
-
-#include "fxjs/cfxjse_engine.h"
-#include "fxjs/xfa/cjx_object.h"
-#include "third_party/base/stl_util.h"
-#include "xfa/fxfa/cxfa_ffnotify.h"
-#include "xfa/fxfa/parser/cxfa_containerlayoutitem.h"
-#include "xfa/fxfa/parser/cxfa_contentarea.h"
-#include "xfa/fxfa/parser/cxfa_contentlayoutitem.h"
-#include "xfa/fxfa/parser/cxfa_document.h"
-#include "xfa/fxfa/parser/cxfa_itemlayoutprocessor.h"
-#include "xfa/fxfa/parser/cxfa_layoutprocessor.h"
-#include "xfa/fxfa/parser/cxfa_localemgr.h"
-#include "xfa/fxfa/parser/cxfa_measurement.h"
-#include "xfa/fxfa/parser/cxfa_medium.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_occur.h"
-#include "xfa/fxfa/parser/cxfa_pageset.h"
-#include "xfa/fxfa/parser/cxfa_subform.h"
-#include "xfa/fxfa/parser/cxfa_traversestrategy_contentareacontainerlayoutitem.h"
-#include "xfa/fxfa/parser/cxfa_traversestrategy_layoutitem.h"
-#include "xfa/fxfa/parser/cxfa_traversestrategy_xfacontainernode.h"
-#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"
-
-namespace {
-
-class PageSetContainerLayoutItem {
- public:
-  static CXFA_ContainerLayoutItem* GetFirstChild(
-      CXFA_ContainerLayoutItem* pLayoutItem) {
-    if (pLayoutItem->m_pFormNode->GetElementType() != XFA_Element::PageSet)
-      return nullptr;
-
-    CXFA_ContainerLayoutItem* pChildItem =
-        static_cast<CXFA_ContainerLayoutItem*>(pLayoutItem->m_pFirstChild);
-    while (pChildItem &&
-           pChildItem->m_pFormNode->GetElementType() != XFA_Element::PageSet) {
-      pChildItem =
-          static_cast<CXFA_ContainerLayoutItem*>(pChildItem->m_pNextSibling);
-    }
-    return pChildItem;
-  }
-
-  static CXFA_ContainerLayoutItem* GetNextSibling(
-      CXFA_ContainerLayoutItem* pLayoutItem) {
-    CXFA_ContainerLayoutItem* pChildItem =
-        static_cast<CXFA_ContainerLayoutItem*>(pLayoutItem->m_pNextSibling);
-    while (pChildItem &&
-           pChildItem->m_pFormNode->GetElementType() != XFA_Element::PageSet) {
-      pChildItem =
-          static_cast<CXFA_ContainerLayoutItem*>(pChildItem->m_pNextSibling);
-    }
-    return pChildItem;
-  }
-
-  static CXFA_ContainerLayoutItem* GetParent(
-      CXFA_ContainerLayoutItem* pLayoutItem) {
-    return static_cast<CXFA_ContainerLayoutItem*>(pLayoutItem->m_pParent);
-  }
-};
-
-uint32_t GetRelevant(CXFA_Node* pFormItem, uint32_t dwParentRelvant) {
-  uint32_t dwRelevant = XFA_WidgetStatus_Viewable | XFA_WidgetStatus_Printable;
-  WideString wsRelevant =
-      pFormItem->JSObject()->GetCData(XFA_Attribute::Relevant);
-  if (!wsRelevant.IsEmpty()) {
-    if (wsRelevant == L"+print" || wsRelevant == L"print")
-      dwRelevant &= ~XFA_WidgetStatus_Viewable;
-    else if (wsRelevant == L"-print")
-      dwRelevant &= ~XFA_WidgetStatus_Printable;
-  }
-
-  if (!(dwParentRelvant & XFA_WidgetStatus_Viewable) &&
-      (dwRelevant != XFA_WidgetStatus_Viewable)) {
-    dwRelevant &= ~XFA_WidgetStatus_Viewable;
-  }
-
-  if (!(dwParentRelvant & XFA_WidgetStatus_Printable) &&
-      (dwRelevant != XFA_WidgetStatus_Printable)) {
-    dwRelevant &= ~XFA_WidgetStatus_Printable;
-  }
-  return dwRelevant;
-}
-
-void SyncContainer(CXFA_FFNotify* pNotify,
-                   CXFA_LayoutProcessor* pDocLayout,
-                   CXFA_LayoutItem* pContainerItem,
-                   uint32_t dwRelevant,
-                   bool bVisible,
-                   int32_t nPageIndex) {
-  bool bVisibleItem = false;
-  uint32_t dwStatus = 0;
-  uint32_t dwRelevantContainer = 0;
-  if (bVisible) {
-    XFA_AttributeEnum eAttributeValue =
-        pContainerItem->m_pFormNode->JSObject()
-            ->TryEnum(XFA_Attribute::Presence, true)
-            .value_or(XFA_AttributeEnum::Visible);
-    if (eAttributeValue == XFA_AttributeEnum::Visible)
-      bVisibleItem = true;
-
-    dwRelevantContainer = GetRelevant(pContainerItem->m_pFormNode, dwRelevant);
-    dwStatus =
-        (bVisibleItem ? XFA_WidgetStatus_Visible : 0) | dwRelevantContainer;
-  }
-  pNotify->OnLayoutItemAdded(pDocLayout, pContainerItem, nPageIndex, dwStatus);
-  for (CXFA_LayoutItem* pChild = pContainerItem->m_pFirstChild; pChild;
-       pChild = pChild->m_pNextSibling) {
-    if (pChild->IsContentLayoutItem()) {
-      SyncContainer(pNotify, pDocLayout, pChild, dwRelevantContainer,
-                    bVisibleItem, nPageIndex);
-    }
-  }
-}
-
-void ReorderLayoutItemToTail(CXFA_ContainerLayoutItem* pLayoutItem) {
-  CXFA_ContainerLayoutItem* pParentLayoutItem =
-      static_cast<CXFA_ContainerLayoutItem*>(pLayoutItem->m_pParent);
-  if (!pParentLayoutItem)
-    return;
-
-  pParentLayoutItem->RemoveChild(pLayoutItem);
-  pParentLayoutItem->AddChild(pLayoutItem);
-}
-
-void RemoveLayoutItem(CXFA_ContainerLayoutItem* pLayoutItem) {
-  CXFA_ContainerLayoutItem* pParentLayoutItem =
-      static_cast<CXFA_ContainerLayoutItem*>(pLayoutItem->m_pParent);
-  if (!pParentLayoutItem)
-    return;
-
-  pParentLayoutItem->RemoveChild(pLayoutItem);
-}
-
-CXFA_Node* ResolveBreakTarget(CXFA_Node* pPageSetRoot,
-                              bool bNewExprStyle,
-                              WideString& wsTargetAll) {
-  if (!pPageSetRoot)
-    return nullptr;
-
-  CXFA_Document* pDocument = pPageSetRoot->GetDocument();
-  if (wsTargetAll.IsEmpty())
-    return nullptr;
-
-  wsTargetAll.Trim();
-  int32_t iSplitIndex = 0;
-  bool bTargetAllFind = true;
-  while (iSplitIndex != -1) {
-    WideString wsExpr;
-    Optional<size_t> iSplitNextIndex = 0;
-    if (!bTargetAllFind) {
-      iSplitNextIndex = wsTargetAll.Find(' ', iSplitIndex);
-      if (!iSplitNextIndex.has_value())
-        return nullptr;
-      wsExpr =
-          wsTargetAll.Mid(iSplitIndex, iSplitNextIndex.value() - iSplitIndex);
-    } else {
-      wsExpr = wsTargetAll;
-    }
-    if (wsExpr.IsEmpty())
-      return nullptr;
-
-    bTargetAllFind = false;
-    if (wsExpr[0] == '#') {
-      CXFA_Node* pNode = pDocument->GetNodeByID(
-          ToNode(pDocument->GetXFAObject(XFA_HASHCODE_Template)),
-          wsExpr.Right(wsExpr.GetLength() - 1).AsStringView());
-      if (pNode)
-        return pNode;
-    } else if (bNewExprStyle) {
-      WideString wsProcessedTarget = wsExpr;
-      if (wsExpr.Left(4) == L"som(" && wsExpr.Last() == L')') {
-        wsProcessedTarget = wsExpr.Mid(4, wsExpr.GetLength() - 5);
-      }
-      XFA_RESOLVENODE_RS rs;
-      bool iRet = pDocument->GetScriptContext()->ResolveObjects(
-          pPageSetRoot, wsProcessedTarget.AsStringView(), &rs,
-          XFA_RESOLVENODE_Children | XFA_RESOLVENODE_Properties |
-              XFA_RESOLVENODE_Attributes | XFA_RESOLVENODE_Siblings |
-              XFA_RESOLVENODE_Parent,
-          nullptr);
-      if (iRet && rs.objects.front()->IsNode())
-        return rs.objects.front()->AsNode();
-    }
-    iSplitIndex = iSplitNextIndex.value();
-  }
-  return nullptr;
-}
-
-void SetLayoutGeneratedNodeFlag(CXFA_Node* pNode) {
-  pNode->SetFlag(XFA_NodeFlag_LayoutGeneratedNode, false);
-  pNode->ClearFlag(XFA_NodeFlag_UnusedNode);
-}
-
-bool CheckContentAreaNotUsed(
-    CXFA_ContainerLayoutItem* pPageAreaLayoutItem,
-    CXFA_Node* pContentArea,
-    CXFA_ContainerLayoutItem*& pContentAreaLayoutItem) {
-  for (CXFA_ContainerLayoutItem* pLayoutItem =
-           static_cast<CXFA_ContainerLayoutItem*>(
-               pPageAreaLayoutItem->m_pFirstChild);
-       pLayoutItem; pLayoutItem = static_cast<CXFA_ContainerLayoutItem*>(
-                        pLayoutItem->m_pNextSibling)) {
-    if (pLayoutItem->m_pFormNode == pContentArea) {
-      if (!pLayoutItem->m_pFirstChild) {
-        pContentAreaLayoutItem = pLayoutItem;
-        return true;
-      }
-      return false;
-    }
-  }
-  return true;
-}
-
-void SyncRemoveLayoutItem(CXFA_LayoutItem* pParentLayoutItem,
-                          CXFA_FFNotify* pNotify,
-                          CXFA_LayoutProcessor* pDocLayout) {
-  CXFA_LayoutItem* pNextLayoutItem;
-  CXFA_LayoutItem* pCurLayoutItem = pParentLayoutItem->m_pFirstChild;
-  while (pCurLayoutItem) {
-    pNextLayoutItem = pCurLayoutItem->m_pNextSibling;
-    if (pCurLayoutItem->m_pFirstChild)
-      SyncRemoveLayoutItem(pCurLayoutItem, pNotify, pDocLayout);
-
-    pNotify->OnLayoutItemRemoving(pDocLayout, pCurLayoutItem);
-    delete pCurLayoutItem;
-    pCurLayoutItem = pNextLayoutItem;
-  }
-}
-
-bool RunBreakTestScript(CXFA_Script* pTestScript) {
-  WideString wsExpression = pTestScript->JSObject()->GetContent(false);
-  if (wsExpression.IsEmpty())
-    return true;
-  return pTestScript->GetDocument()->GetNotify()->RunScript(
-      pTestScript, pTestScript->GetContainerParent());
-}
-
-}  // namespace
-
-class CXFA_ContainerRecord {
- public:
-  CXFA_ContainerRecord(CXFA_ContainerLayoutItem* pPageSet = nullptr,
-                       CXFA_ContainerLayoutItem* pPageArea = nullptr,
-                       CXFA_ContainerLayoutItem* pContentArea = nullptr)
-      : pCurPageSet(pPageSet),
-        pCurPageArea(pPageArea),
-        pCurContentArea(pContentArea) {}
-
-  CXFA_ContainerLayoutItem* pCurPageSet;
-  CXFA_ContainerLayoutItem* pCurPageArea;
-  CXFA_ContainerLayoutItem* pCurContentArea;
-};
-
-CXFA_LayoutPageMgr::CXFA_LayoutPageMgr(CXFA_LayoutProcessor* pLayoutProcessor)
-    : m_pLayoutProcessor(pLayoutProcessor),
-      m_pTemplatePageSetRoot(nullptr),
-      m_pPageSetLayoutItemRoot(nullptr),
-      m_pPageSetCurRoot(nullptr),
-      m_CurrentContainerRecordIter(m_ProposedContainerRecords.end()),
-      m_pCurPageArea(nullptr),
-      m_nAvailPages(0),
-      m_nCurPageCount(0),
-      m_ePageSetMode(XFA_AttributeEnum::OrderedOccurrence),
-      m_bCreateOverFlowPage(false) {}
-
-CXFA_LayoutPageMgr::~CXFA_LayoutPageMgr() {
-  ClearData();
-  CXFA_LayoutItem* pLayoutItem = GetRootLayoutItem();
-  CXFA_LayoutItem* pNextLayout = nullptr;
-  for (; pLayoutItem; pLayoutItem = pNextLayout) {
-    pNextLayout = pLayoutItem->m_pNextSibling;
-    XFA_ReleaseLayoutItem(pLayoutItem);
-  }
-}
-
-bool CXFA_LayoutPageMgr::InitLayoutPage(CXFA_Node* pFormNode) {
-  PrepareLayout();
-  CXFA_Node* pTemplateNode = pFormNode->GetTemplateNodeIfExists();
-  if (!pTemplateNode)
-    return false;
-
-  m_pTemplatePageSetRoot =
-      pTemplateNode->JSObject()->GetOrCreateProperty<CXFA_PageSet>(
-          0, XFA_Element::PageSet);
-  ASSERT(m_pTemplatePageSetRoot);
-
-  if (m_pPageSetLayoutItemRoot) {
-    m_pPageSetLayoutItemRoot->m_pParent = nullptr;
-    m_pPageSetLayoutItemRoot->m_pFirstChild = nullptr;
-    m_pPageSetLayoutItemRoot->m_pNextSibling = nullptr;
-    m_pPageSetLayoutItemRoot->m_pFormNode = m_pTemplatePageSetRoot;
-  } else {
-    m_pPageSetLayoutItemRoot =
-        new CXFA_ContainerLayoutItem(m_pTemplatePageSetRoot);
-  }
-  m_pPageSetCurRoot = m_pPageSetLayoutItemRoot;
-  m_pTemplatePageSetRoot->JSObject()->SetLayoutItem(m_pPageSetLayoutItemRoot);
-
-  XFA_AttributeEnum eRelation =
-      m_pTemplatePageSetRoot->JSObject()->GetEnum(XFA_Attribute::Relation);
-  if (eRelation != XFA_AttributeEnum::Unknown)
-    m_ePageSetMode = eRelation;
-
-  InitPageSetMap();
-  CXFA_Node* pPageArea = nullptr;
-  int32_t iCount = 0;
-  for (pPageArea = m_pTemplatePageSetRoot->GetFirstChild(); pPageArea;
-       pPageArea = pPageArea->GetNextSibling()) {
-    if (pPageArea->GetElementType() == XFA_Element::PageArea) {
-      iCount++;
-      if (pPageArea->GetFirstChildByClass<CXFA_ContentArea>(
-              XFA_Element::ContentArea))
-        return true;
-    }
-  }
-  if (iCount > 0)
-    return false;
-
-  CXFA_Document* pDocument = pTemplateNode->GetDocument();
-  pPageArea = m_pTemplatePageSetRoot->GetChild<CXFA_Node>(
-      0, XFA_Element::PageArea, false);
-  if (!pPageArea) {
-    pPageArea = pDocument->CreateNode(m_pTemplatePageSetRoot->GetPacketType(),
-                                      XFA_Element::PageArea);
-    if (!pPageArea)
-      return false;
-
-    m_pTemplatePageSetRoot->InsertChild(pPageArea, nullptr);
-    pPageArea->SetFlag(XFA_NodeFlag_Initialized, true);
-  }
-  CXFA_ContentArea* pContentArea =
-      pPageArea->GetChild<CXFA_ContentArea>(0, XFA_Element::ContentArea, false);
-  if (!pContentArea) {
-    pContentArea = static_cast<CXFA_ContentArea*>(pDocument->CreateNode(
-        pPageArea->GetPacketType(), XFA_Element::ContentArea));
-    if (!pContentArea)
-      return false;
-
-    pPageArea->InsertChild(pContentArea, nullptr);
-    pContentArea->SetFlag(XFA_NodeFlag_Initialized, true);
-    pContentArea->JSObject()->SetMeasure(
-        XFA_Attribute::X, CXFA_Measurement(0.25f, XFA_Unit::In), false);
-    pContentArea->JSObject()->SetMeasure(
-        XFA_Attribute::Y, CXFA_Measurement(0.25f, XFA_Unit::In), false);
-    pContentArea->JSObject()->SetMeasure(
-        XFA_Attribute::W, CXFA_Measurement(8.0f, XFA_Unit::In), false);
-    pContentArea->JSObject()->SetMeasure(
-        XFA_Attribute::H, CXFA_Measurement(10.5f, XFA_Unit::In), false);
-  }
-  CXFA_Medium* pMedium =
-      pPageArea->GetChild<CXFA_Medium>(0, XFA_Element::Medium, false);
-  if (!pMedium) {
-    pMedium = static_cast<CXFA_Medium*>(
-        pDocument->CreateNode(pPageArea->GetPacketType(), XFA_Element::Medium));
-    if (!pContentArea)
-      return false;
-
-    pPageArea->InsertChild(pMedium, nullptr);
-    pMedium->SetFlag(XFA_NodeFlag_Initialized, true);
-    pMedium->JSObject()->SetMeasure(
-        XFA_Attribute::Short, CXFA_Measurement(8.5f, XFA_Unit::In), false);
-    pMedium->JSObject()->SetMeasure(
-        XFA_Attribute::Long, CXFA_Measurement(11.0f, XFA_Unit::In), false);
-  }
-  return true;
-}
-
-bool CXFA_LayoutPageMgr::PrepareFirstPage(CXFA_Node* pRootSubform) {
-  bool bProBreakBefore = false;
-  CXFA_Node* pBreakBeforeNode = nullptr;
-  while (pRootSubform) {
-    for (CXFA_Node* pBreakNode = pRootSubform->GetFirstChild(); pBreakNode;
-         pBreakNode = pBreakNode->GetNextSibling()) {
-      XFA_Element eType = pBreakNode->GetElementType();
-      if (eType == XFA_Element::BreakBefore ||
-          (eType == XFA_Element::Break &&
-           pBreakNode->JSObject()->GetEnum(XFA_Attribute::Before) !=
-               XFA_AttributeEnum::Auto)) {
-        bProBreakBefore = true;
-        pBreakBeforeNode = pBreakNode;
-        break;
-      }
-    }
-    if (bProBreakBefore)
-      break;
-
-    bProBreakBefore = true;
-    pRootSubform =
-        pRootSubform->GetFirstChildByClass<CXFA_Subform>(XFA_Element::Subform);
-    while (pRootSubform &&
-           !XFA_ItemLayoutProcessor_IsTakingSpace(pRootSubform)) {
-      pRootSubform = pRootSubform->GetNextSameClassSibling<CXFA_Subform>(
-          XFA_Element::Subform);
-    }
-  }
-  CXFA_Node* pLeader;
-  CXFA_Node* pTrailer;
-  if (pBreakBeforeNode &&
-      ExecuteBreakBeforeOrAfter(pBreakBeforeNode, true, pLeader, pTrailer)) {
-    m_CurrentContainerRecordIter = m_ProposedContainerRecords.begin();
-    return true;
-  }
-  return AppendNewPage(true);
-}
-
-bool CXFA_LayoutPageMgr::AppendNewPage(bool bFirstTemPage) {
-  if (m_CurrentContainerRecordIter != GetTailPosition())
-    return true;
-
-  CXFA_Node* pPageNode = GetNextAvailPageArea(nullptr);
-  if (!pPageNode)
-    return false;
-
-  if (bFirstTemPage &&
-      m_CurrentContainerRecordIter == m_ProposedContainerRecords.end()) {
-    m_CurrentContainerRecordIter = m_ProposedContainerRecords.begin();
-  }
-  return !bFirstTemPage ||
-         m_CurrentContainerRecordIter != m_ProposedContainerRecords.end();
-}
-
-void CXFA_LayoutPageMgr::RemoveLayoutRecord(CXFA_ContainerRecord* pNewRecord,
-                                            CXFA_ContainerRecord* pPrevRecord) {
-  if (!pNewRecord || !pPrevRecord)
-    return;
-  if (pNewRecord->pCurPageSet != pPrevRecord->pCurPageSet) {
-    RemoveLayoutItem(pNewRecord->pCurPageSet);
-    return;
-  }
-  if (pNewRecord->pCurPageArea != pPrevRecord->pCurPageArea) {
-    RemoveLayoutItem(pNewRecord->pCurPageArea);
-    return;
-  }
-  if (pNewRecord->pCurContentArea != pPrevRecord->pCurContentArea) {
-    RemoveLayoutItem(pNewRecord->pCurContentArea);
-    return;
-  }
-}
-
-void CXFA_LayoutPageMgr::ReorderPendingLayoutRecordToTail(
-    CXFA_ContainerRecord* pNewRecord,
-    CXFA_ContainerRecord* pPrevRecord) {
-  if (!pNewRecord || !pPrevRecord)
-    return;
-  if (pNewRecord->pCurPageSet != pPrevRecord->pCurPageSet) {
-    ReorderLayoutItemToTail(pNewRecord->pCurPageSet);
-    return;
-  }
-  if (pNewRecord->pCurPageArea != pPrevRecord->pCurPageArea) {
-    ReorderLayoutItemToTail(pNewRecord->pCurPageArea);
-    return;
-  }
-  if (pNewRecord->pCurContentArea != pPrevRecord->pCurContentArea) {
-    ReorderLayoutItemToTail(pNewRecord->pCurContentArea);
-    return;
-  }
-}
-
-void CXFA_LayoutPageMgr::SubmitContentItem(
-    CXFA_ContentLayoutItem* pContentLayoutItem,
-    XFA_ItemLayoutProcessorResult eStatus) {
-  if (pContentLayoutItem) {
-    GetCurrentContainerRecord()->pCurContentArea->AddChild(pContentLayoutItem);
-    m_bCreateOverFlowPage = false;
-  }
-
-  if (eStatus != XFA_ItemLayoutProcessorResult::Done) {
-    if (eStatus == XFA_ItemLayoutProcessorResult::PageFullBreak &&
-        m_CurrentContainerRecordIter == GetTailPosition()) {
-      AppendNewPage();
-    }
-    m_CurrentContainerRecordIter = GetTailPosition();
-    m_pCurPageArea = GetCurrentContainerRecord()->pCurPageArea->m_pFormNode;
-  }
-}
-
-float CXFA_LayoutPageMgr::GetAvailHeight() {
-  CXFA_ContainerLayoutItem* pLayoutItem =
-      GetCurrentContainerRecord()->pCurContentArea;
-  if (!pLayoutItem || !pLayoutItem->m_pFormNode)
-    return 0.0f;
-
-  float fAvailHeight = pLayoutItem->m_pFormNode->JSObject()
-                           ->GetMeasure(XFA_Attribute::H)
-                           .ToUnit(XFA_Unit::Pt);
-  if (fAvailHeight >= XFA_LAYOUT_FLOAT_PERCISION)
-    return fAvailHeight;
-  if (m_CurrentContainerRecordIter == m_ProposedContainerRecords.begin())
-    return 0.0f;
-  return FLT_MAX;
-}
-
-CXFA_ContainerRecord* CXFA_LayoutPageMgr::CreateContainerRecord(
-    CXFA_Node* pPageNode,
-    bool bCreateNew) {
-  CXFA_ContainerRecord* pNewRecord = new CXFA_ContainerRecord();
-  if (m_CurrentContainerRecordIter != m_ProposedContainerRecords.end()) {
-    if (!IsPageSetRootOrderedOccurrence() || !pPageNode) {
-      *pNewRecord = *GetCurrentContainerRecord();
-      m_ProposedContainerRecords.push_back(pNewRecord);
-      return pNewRecord;
-    }
-    CXFA_Node* pPageSet = pPageNode->GetParent();
-    if (!bCreateNew) {
-      if (pPageSet == m_pTemplatePageSetRoot) {
-        pNewRecord->pCurPageSet = m_pPageSetCurRoot;
-      } else {
-        CXFA_ContainerLayoutItem* pParentLayoutItem =
-            static_cast<CXFA_ContainerLayoutItem*>(
-                pPageSet->JSObject()->GetLayoutItem());
-        if (!pParentLayoutItem)
-          pParentLayoutItem = m_pPageSetCurRoot;
-
-        pNewRecord->pCurPageSet = pParentLayoutItem;
-      }
-    } else {
-      CXFA_ContainerLayoutItem* pParentPageSetLayout = nullptr;
-      if (pPageSet == GetCurrentContainerRecord()->pCurPageSet->m_pFormNode) {
-        pParentPageSetLayout = static_cast<CXFA_ContainerLayoutItem*>(
-            GetCurrentContainerRecord()->pCurPageSet->m_pParent);
-      } else {
-        pParentPageSetLayout = static_cast<CXFA_ContainerLayoutItem*>(
-            pPageSet->GetParent()->JSObject()->GetLayoutItem());
-      }
-      CXFA_ContainerLayoutItem* pPageSetLayoutItem =
-          new CXFA_ContainerLayoutItem(pPageSet);
-      pPageSet->JSObject()->SetLayoutItem(pPageSetLayoutItem);
-      if (!pParentPageSetLayout) {
-        CXFA_ContainerLayoutItem* pPrePageSet = m_pPageSetLayoutItemRoot;
-        while (pPrePageSet->m_pNextSibling) {
-          pPrePageSet = static_cast<CXFA_ContainerLayoutItem*>(
-              pPrePageSet->m_pNextSibling);
-        }
-
-        pPrePageSet->m_pNextSibling = pPageSetLayoutItem;
-        m_pPageSetCurRoot = pPageSetLayoutItem;
-      } else {
-        pParentPageSetLayout->AddChild(pPageSetLayoutItem);
-      }
-      pNewRecord->pCurPageSet = pPageSetLayoutItem;
-    }
-  } else {
-    if (pPageNode) {
-      CXFA_Node* pPageSet = pPageNode->GetParent();
-      if (pPageSet == m_pTemplatePageSetRoot) {
-        pNewRecord->pCurPageSet = m_pPageSetLayoutItemRoot;
-      } else {
-        CXFA_ContainerLayoutItem* pPageSetLayoutItem =
-            new CXFA_ContainerLayoutItem(pPageSet);
-        pPageSet->JSObject()->SetLayoutItem(pPageSetLayoutItem);
-        m_pPageSetLayoutItemRoot->AddChild(pPageSetLayoutItem);
-        pNewRecord->pCurPageSet = pPageSetLayoutItem;
-      }
-    } else {
-      pNewRecord->pCurPageSet = m_pPageSetLayoutItemRoot;
-    }
-  }
-  m_ProposedContainerRecords.push_back(pNewRecord);
-  return pNewRecord;
-}
-
-void CXFA_LayoutPageMgr::AddPageAreaLayoutItem(CXFA_ContainerRecord* pNewRecord,
-                                               CXFA_Node* pNewPageArea) {
-  CXFA_ContainerLayoutItem* pNewPageAreaLayoutItem = nullptr;
-  if (pdfium::IndexInBounds(m_PageArray, m_nAvailPages)) {
-    CXFA_ContainerLayoutItem* pContainerItem = m_PageArray[m_nAvailPages];
-    pContainerItem->m_pFormNode = pNewPageArea;
-    m_nAvailPages++;
-    pNewPageAreaLayoutItem = pContainerItem;
-  } else {
-    CXFA_FFNotify* pNotify = pNewPageArea->GetDocument()->GetNotify();
-    auto* pContainerItem = pNotify->OnCreateContainerLayoutItem(pNewPageArea);
-    m_PageArray.push_back(pContainerItem);
-    m_nAvailPages++;
-    pNotify->OnPageEvent(pContainerItem, XFA_PAGEVIEWEVENT_PostRemoved);
-    pNewPageAreaLayoutItem = pContainerItem;
-  }
-  pNewRecord->pCurPageSet->AddChild(pNewPageAreaLayoutItem);
-  pNewRecord->pCurPageArea = pNewPageAreaLayoutItem;
-  pNewRecord->pCurContentArea = nullptr;
-}
-
-void CXFA_LayoutPageMgr::AddContentAreaLayoutItem(
-    CXFA_ContainerRecord* pNewRecord,
-    CXFA_Node* pContentArea) {
-  if (!pContentArea) {
-    pNewRecord->pCurContentArea = nullptr;
-    return;
-  }
-  CXFA_ContainerLayoutItem* pNewContentAreaLayoutItem =
-      new CXFA_ContainerLayoutItem(pContentArea);
-  ASSERT(pNewRecord->pCurPageArea);
-  pNewRecord->pCurPageArea->AddChild(pNewContentAreaLayoutItem);
-  pNewRecord->pCurContentArea = pNewContentAreaLayoutItem;
-}
-
-void CXFA_LayoutPageMgr::FinishPaginatedPageSets() {
-  CXFA_ContainerLayoutItem* pRootPageSetLayoutItem = m_pPageSetLayoutItemRoot;
-  for (; pRootPageSetLayoutItem;
-       pRootPageSetLayoutItem = static_cast<CXFA_ContainerLayoutItem*>(
-           pRootPageSetLayoutItem->m_pNextSibling)) {
-    CXFA_NodeIteratorTemplate<CXFA_ContainerLayoutItem,
-                              PageSetContainerLayoutItem>
-        sIterator(pRootPageSetLayoutItem);
-    for (CXFA_ContainerLayoutItem* pPageSetLayoutItem = sIterator.GetCurrent();
-         pPageSetLayoutItem; pPageSetLayoutItem = sIterator.MoveToNext()) {
-      XFA_AttributeEnum ePageRelation =
-          pPageSetLayoutItem->m_pFormNode->JSObject()->GetEnum(
-              XFA_Attribute::Relation);
-      switch (ePageRelation) {
-        case XFA_AttributeEnum::OrderedOccurrence:
-        default: { ProcessLastPageSet(); } break;
-        case XFA_AttributeEnum::SimplexPaginated:
-        case XFA_AttributeEnum::DuplexPaginated: {
-          CXFA_LayoutItem* pLastPageAreaLayoutItem = nullptr;
-          int32_t nPageAreaCount = 0;
-          for (CXFA_LayoutItem* pPageAreaLayoutItem =
-                   pPageSetLayoutItem->m_pFirstChild;
-               pPageAreaLayoutItem;
-               pPageAreaLayoutItem = pPageAreaLayoutItem->m_pNextSibling) {
-            if (pPageAreaLayoutItem->m_pFormNode->GetElementType() !=
-                XFA_Element::PageArea) {
-              continue;
-            }
-            nPageAreaCount++;
-            pLastPageAreaLayoutItem = pPageAreaLayoutItem;
-          }
-          if (!pLastPageAreaLayoutItem)
-            break;
-
-          if (!FindPageAreaFromPageSet_SimplexDuplex(
-                  pPageSetLayoutItem->m_pFormNode, nullptr, nullptr, nullptr,
-                  true, true,
-                  nPageAreaCount == 1 ? XFA_AttributeEnum::Only
-                                      : XFA_AttributeEnum::Last) &&
-              (nPageAreaCount == 1 &&
-               !FindPageAreaFromPageSet_SimplexDuplex(
-                   pPageSetLayoutItem->m_pFormNode, nullptr, nullptr, nullptr,
-                   true, true, XFA_AttributeEnum::Last))) {
-            break;
-          }
-          CXFA_Node* pNode = m_pCurPageArea;
-          XFA_AttributeEnum eCurChoice =
-              pNode->JSObject()->GetEnum(XFA_Attribute::PagePosition);
-          if (eCurChoice == XFA_AttributeEnum::Last) {
-            XFA_AttributeEnum eOddOrEven =
-                pNode->JSObject()->GetEnum(XFA_Attribute::OddOrEven);
-            XFA_AttributeEnum eLastChoice =
-                pLastPageAreaLayoutItem->m_pFormNode->JSObject()->GetEnum(
-                    XFA_Attribute::PagePosition);
-            if (eLastChoice == XFA_AttributeEnum::First &&
-                (ePageRelation == XFA_AttributeEnum::SimplexPaginated ||
-                 eOddOrEven != XFA_AttributeEnum::Odd)) {
-              CXFA_ContainerRecord* pRecord = CreateContainerRecord();
-              AddPageAreaLayoutItem(pRecord, pNode);
-              break;
-            }
-          }
-          bool bUsable = true;
-          std::vector<float> rgUsedHeights;
-          for (CXFA_LayoutItem* pChildLayoutItem =
-                   pLastPageAreaLayoutItem->m_pFirstChild;
-               pChildLayoutItem;
-               pChildLayoutItem = pChildLayoutItem->m_pNextSibling) {
-            if (pChildLayoutItem->m_pFormNode->GetElementType() !=
-                XFA_Element::ContentArea) {
-              continue;
-            }
-            float fUsedHeight = 0;
-            for (CXFA_LayoutItem* pContentChildLayoutItem =
-                     pChildLayoutItem->m_pFirstChild;
-                 pContentChildLayoutItem;
-                 pContentChildLayoutItem =
-                     pContentChildLayoutItem->m_pNextSibling) {
-              if (CXFA_ContentLayoutItem* pContent =
-                      pContentChildLayoutItem->AsContentLayoutItem()) {
-                fUsedHeight += pContent->m_sSize.height;
-              }
-            }
-            rgUsedHeights.push_back(fUsedHeight);
-          }
-          int32_t iCurContentAreaIndex = -1;
-          for (CXFA_Node* pContentAreaNode = pNode->GetFirstChild();
-               pContentAreaNode;
-               pContentAreaNode = pContentAreaNode->GetNextSibling()) {
-            if (pContentAreaNode->GetElementType() !=
-                XFA_Element::ContentArea) {
-              continue;
-            }
-            iCurContentAreaIndex++;
-            if (rgUsedHeights[iCurContentAreaIndex] >
-                pContentAreaNode->JSObject()
-                        ->GetMeasure(XFA_Attribute::H)
-                        .ToUnit(XFA_Unit::Pt) +
-                    XFA_LAYOUT_FLOAT_PERCISION) {
-              bUsable = false;
-              break;
-            }
-          }
-          if (bUsable) {
-            CXFA_LayoutItem* pChildLayoutItem =
-                pLastPageAreaLayoutItem->m_pFirstChild;
-            CXFA_Node* pContentAreaNode = pNode->GetFirstChild();
-            pLastPageAreaLayoutItem->m_pFormNode = pNode;
-            while (pChildLayoutItem && pContentAreaNode) {
-              if (pChildLayoutItem->m_pFormNode->GetElementType() !=
-                  XFA_Element::ContentArea) {
-                pChildLayoutItem = pChildLayoutItem->m_pNextSibling;
-                continue;
-              }
-              if (pContentAreaNode->GetElementType() !=
-                  XFA_Element::ContentArea) {
-                pContentAreaNode = pContentAreaNode->GetNextSibling();
-                continue;
-              }
-              pChildLayoutItem->m_pFormNode = pContentAreaNode;
-              pChildLayoutItem = pChildLayoutItem->m_pNextSibling;
-              pContentAreaNode = pContentAreaNode->GetNextSibling();
-            }
-          } else if (pNode->JSObject()->GetEnum(XFA_Attribute::PagePosition) ==
-                     XFA_AttributeEnum::Last) {
-            CXFA_ContainerRecord* pRecord = CreateContainerRecord();
-            AddPageAreaLayoutItem(pRecord, pNode);
-          }
-        } break;
-      }
-    }
-  }
-}
-
-int32_t CXFA_LayoutPageMgr::GetPageCount() const {
-  return pdfium::CollectionSize<int32_t>(m_PageArray);
-}
-
-CXFA_ContainerLayoutItem* CXFA_LayoutPageMgr::GetPage(int32_t index) const {
-  if (!pdfium::IndexInBounds(m_PageArray, index))
-    return nullptr;
-  return m_PageArray[index];
-}
-
-int32_t CXFA_LayoutPageMgr::GetPageIndex(
-    const CXFA_ContainerLayoutItem* pPage) const {
-  auto it = std::find(m_PageArray.begin(), m_PageArray.end(), pPage);
-  return it != m_PageArray.end() ? it - m_PageArray.begin() : -1;
-}
-
-bool CXFA_LayoutPageMgr::RunBreak(XFA_Element eBreakType,
-                                  XFA_AttributeEnum eTargetType,
-                                  CXFA_Node* pTarget,
-                                  bool bStartNew) {
-  bool bRet = false;
-  switch (eTargetType) {
-    case XFA_AttributeEnum::ContentArea:
-      if (pTarget && pTarget->GetElementType() != XFA_Element::ContentArea)
-        pTarget = nullptr;
-      if (!pTarget ||
-          m_CurrentContainerRecordIter == m_ProposedContainerRecords.end() ||
-          pTarget !=
-              GetCurrentContainerRecord()->pCurContentArea->m_pFormNode ||
-          bStartNew) {
-        CXFA_Node* pPageArea = nullptr;
-        if (pTarget)
-          pPageArea = pTarget->GetParent();
-
-        pPageArea = GetNextAvailPageArea(pPageArea, pTarget);
-        bRet = !!pPageArea;
-      }
-      break;
-    case XFA_AttributeEnum::PageArea:
-      if (pTarget && pTarget->GetElementType() != XFA_Element::PageArea)
-        pTarget = nullptr;
-      if (!pTarget ||
-          m_CurrentContainerRecordIter == m_ProposedContainerRecords.end() ||
-          pTarget != GetCurrentContainerRecord()->pCurPageArea->m_pFormNode ||
-          bStartNew) {
-        CXFA_Node* pPageArea = GetNextAvailPageArea(pTarget, nullptr, true);
-        bRet = !!pPageArea;
-      }
-      break;
-    case XFA_AttributeEnum::PageOdd:
-      if (pTarget && pTarget->GetElementType() != XFA_Element::PageArea)
-        pTarget = nullptr;
-      break;
-    case XFA_AttributeEnum::PageEven:
-      if (pTarget && pTarget->GetElementType() != XFA_Element::PageArea)
-        pTarget = nullptr;
-      break;
-    case XFA_AttributeEnum::Auto:
-    default:
-      break;
-  }
-  return bRet;
-}
-
-bool CXFA_LayoutPageMgr::ExecuteBreakBeforeOrAfter(
-    CXFA_Node* pCurNode,
-    bool bBefore,
-    CXFA_Node*& pBreakLeaderTemplate,
-    CXFA_Node*& pBreakTrailerTemplate) {
-  XFA_Element eType = pCurNode->GetElementType();
-  switch (eType) {
-    case XFA_Element::BreakBefore:
-    case XFA_Element::BreakAfter: {
-      WideString wsBreakLeader;
-      WideString wsBreakTrailer;
-      CXFA_Node* pFormNode = pCurNode->GetContainerParent();
-      CXFA_Node* pContainer = pFormNode->GetTemplateNodeIfExists();
-      bool bStartNew =
-          pCurNode->JSObject()->GetInteger(XFA_Attribute::StartNew) != 0;
-      CXFA_Script* pScript =
-          pCurNode->GetFirstChildByClass<CXFA_Script>(XFA_Element::Script);
-      if (pScript && !RunBreakTestScript(pScript))
-        return false;
-
-      WideString wsTarget =
-          pCurNode->JSObject()->GetCData(XFA_Attribute::Target);
-      CXFA_Node* pTarget =
-          ResolveBreakTarget(m_pTemplatePageSetRoot, true, wsTarget);
-      wsBreakTrailer = pCurNode->JSObject()->GetCData(XFA_Attribute::Trailer);
-      wsBreakLeader = pCurNode->JSObject()->GetCData(XFA_Attribute::Leader);
-      pBreakLeaderTemplate =
-          ResolveBreakTarget(pContainer, true, wsBreakLeader);
-      pBreakTrailerTemplate =
-          ResolveBreakTarget(pContainer, true, wsBreakTrailer);
-      if (RunBreak(eType,
-                   pCurNode->JSObject()->GetEnum(XFA_Attribute::TargetType),
-                   pTarget, bStartNew)) {
-        return true;
-      }
-      if (!m_ProposedContainerRecords.empty() &&
-          m_CurrentContainerRecordIter == m_ProposedContainerRecords.begin() &&
-          eType == XFA_Element::BreakBefore) {
-        CXFA_Node* pParentNode = pFormNode->GetContainerParent();
-        if (!pParentNode ||
-            pFormNode != pParentNode->GetFirstContainerChild()) {
-          break;
-        }
-        pParentNode = pParentNode->GetParent();
-        if (!pParentNode ||
-            pParentNode->GetElementType() != XFA_Element::Form) {
-          break;
-        }
-        return true;
-      }
-      break;
-    }
-    case XFA_Element::Break: {
-      bool bStartNew =
-          pCurNode->JSObject()->GetInteger(XFA_Attribute::StartNew) != 0;
-      WideString wsTarget = pCurNode->JSObject()->GetCData(
-          bBefore ? XFA_Attribute::BeforeTarget : XFA_Attribute::AfterTarget);
-      CXFA_Node* pTarget =
-          ResolveBreakTarget(m_pTemplatePageSetRoot, true, wsTarget);
-      if (RunBreak(bBefore ? XFA_Element::BreakBefore : XFA_Element::BreakAfter,
-                   pCurNode->JSObject()->GetEnum(
-                       bBefore ? XFA_Attribute::Before : XFA_Attribute::After),
-                   pTarget, bStartNew)) {
-        return true;
-      }
-      break;
-    }
-    default:
-      break;
-  }
-  return false;
-}
-
-bool CXFA_LayoutPageMgr::ProcessBreakBeforeOrAfter(
-    CXFA_Node* pBreakNode,
-    bool bBefore,
-    CXFA_Node*& pBreakLeaderNode,
-    CXFA_Node*& pBreakTrailerNode,
-    bool& bCreatePage) {
-  CXFA_Node* pLeaderTemplate = nullptr;
-  CXFA_Node* pTrailerTemplate = nullptr;
-  CXFA_Node* pFormNode = pBreakNode->GetContainerParent();
-  if (XFA_ItemLayoutProcessor_IsTakingSpace(pFormNode)) {
-    bCreatePage = ExecuteBreakBeforeOrAfter(pBreakNode, bBefore,
-                                            pLeaderTemplate, pTrailerTemplate);
-    CXFA_Document* pDocument = pBreakNode->GetDocument();
-    CXFA_Node* pDataScope = nullptr;
-    pFormNode = pFormNode->GetContainerParent();
-    if (pLeaderTemplate) {
-      if (!pDataScope)
-        pDataScope = XFA_DataMerge_FindDataScope(pFormNode);
-
-      pBreakLeaderNode = pDocument->DataMerge_CopyContainer(
-          pLeaderTemplate, pFormNode, pDataScope, true, true, true);
-      pDocument->DataMerge_UpdateBindingRelations(pBreakLeaderNode);
-      SetLayoutGeneratedNodeFlag(pBreakLeaderNode);
-    }
-    if (pTrailerTemplate) {
-      if (!pDataScope)
-        pDataScope = XFA_DataMerge_FindDataScope(pFormNode);
-
-      pBreakTrailerNode = pDocument->DataMerge_CopyContainer(
-          pTrailerTemplate, pFormNode, pDataScope, true, true, true);
-      pDocument->DataMerge_UpdateBindingRelations(pBreakTrailerNode);
-      SetLayoutGeneratedNodeFlag(pBreakTrailerNode);
-    }
-    return true;
-  }
-  return false;
-}
-
-bool CXFA_LayoutPageMgr::ProcessBookendLeaderOrTrailer(
-    CXFA_Node* pBookendNode,
-    bool bLeader,
-    CXFA_Node*& pBookendAppendNode) {
-  CXFA_Node* pLeaderTemplate = nullptr;
-  CXFA_Node* pFormNode = pBookendNode->GetContainerParent();
-  if (ResolveBookendLeaderOrTrailer(pBookendNode, bLeader, pLeaderTemplate)) {
-    CXFA_Document* pDocument = pBookendNode->GetDocument();
-    CXFA_Node* pDataScope = nullptr;
-    if (pLeaderTemplate) {
-      if (!pDataScope)
-        pDataScope = XFA_DataMerge_FindDataScope(pFormNode);
-
-      pBookendAppendNode = pDocument->DataMerge_CopyContainer(
-          pLeaderTemplate, pFormNode, pDataScope, true, true, true);
-      pDocument->DataMerge_UpdateBindingRelations(pBookendAppendNode);
-      SetLayoutGeneratedNodeFlag(pBookendAppendNode);
-      return true;
-    }
-  }
-  return false;
-}
-
-CXFA_Node* CXFA_LayoutPageMgr::BreakOverflow(CXFA_Node* pOverflowNode,
-                                             CXFA_Node*& pLeaderTemplate,
-                                             CXFA_Node*& pTrailerTemplate,
-                                             bool bCreatePage) {
-  CXFA_Node* pContainer =
-      pOverflowNode->GetContainerParent()->GetTemplateNodeIfExists();
-  if (pOverflowNode->GetElementType() == XFA_Element::Break) {
-    WideString wsOverflowLeader =
-        pOverflowNode->JSObject()->GetCData(XFA_Attribute::OverflowLeader);
-    WideString wsOverflowTarget =
-        pOverflowNode->JSObject()->GetCData(XFA_Attribute::OverflowTarget);
-    WideString wsOverflowTrailer =
-        pOverflowNode->JSObject()->GetCData(XFA_Attribute::OverflowTrailer);
-    if (wsOverflowTarget.IsEmpty() && wsOverflowLeader.IsEmpty() &&
-        wsOverflowTrailer.IsEmpty()) {
-      return nullptr;
-    }
-
-    if (!wsOverflowTarget.IsEmpty() && bCreatePage && !m_bCreateOverFlowPage) {
-      CXFA_Node* pTarget =
-          ResolveBreakTarget(m_pTemplatePageSetRoot, true, wsOverflowTarget);
-      if (pTarget) {
-        m_bCreateOverFlowPage = true;
-        switch (pTarget->GetElementType()) {
-          case XFA_Element::PageArea:
-            RunBreak(XFA_Element::Overflow, XFA_AttributeEnum::PageArea,
-                     pTarget, true);
-            break;
-          case XFA_Element::ContentArea:
-            RunBreak(XFA_Element::Overflow, XFA_AttributeEnum::ContentArea,
-                     pTarget, true);
-            break;
-          default:
-            break;
-        }
-      }
-    }
-    if (!bCreatePage) {
-      pLeaderTemplate = ResolveBreakTarget(pContainer, true, wsOverflowLeader);
-      pTrailerTemplate =
-          ResolveBreakTarget(pContainer, true, wsOverflowTrailer);
-    }
-    return pOverflowNode;
-  }
-
-  if (pOverflowNode->GetElementType() != XFA_Element::Overflow)
-    return nullptr;
-
-  WideString wsOverflowTarget =
-      pOverflowNode->JSObject()->GetCData(XFA_Attribute::Target);
-  if (!wsOverflowTarget.IsEmpty() && bCreatePage && !m_bCreateOverFlowPage) {
-    CXFA_Node* pTarget =
-        ResolveBreakTarget(m_pTemplatePageSetRoot, true, wsOverflowTarget);
-    if (pTarget) {
-      m_bCreateOverFlowPage = true;
-      switch (pTarget->GetElementType()) {
-        case XFA_Element::PageArea:
-          RunBreak(XFA_Element::Overflow, XFA_AttributeEnum::PageArea, pTarget,
-                   true);
-          break;
-        case XFA_Element::ContentArea:
-          RunBreak(XFA_Element::Overflow, XFA_AttributeEnum::ContentArea,
-                   pTarget, true);
-          break;
-        default:
-          break;
-      }
-    }
-  }
-  if (!bCreatePage) {
-    WideString wsLeader =
-        pOverflowNode->JSObject()->GetCData(XFA_Attribute::Leader);
-    WideString wsTrailer =
-        pOverflowNode->JSObject()->GetCData(XFA_Attribute::Trailer);
-    pLeaderTemplate = ResolveBreakTarget(pContainer, true, wsLeader);
-    pTrailerTemplate = ResolveBreakTarget(pContainer, true, wsTrailer);
-  }
-  return pOverflowNode;
-}
-
-bool CXFA_LayoutPageMgr::ProcessOverflow(CXFA_Node* pFormNode,
-                                         CXFA_Node*& pLeaderNode,
-                                         CXFA_Node*& pTrailerNode,
-                                         bool bDataMerge,
-                                         bool bCreatePage) {
-  if (!pFormNode)
-    return false;
-
-  CXFA_Node* pLeaderTemplate = nullptr;
-  CXFA_Node* pTrailerTemplate = nullptr;
-  bool bIsOverflowNode = false;
-  if (pFormNode->GetElementType() == XFA_Element::Overflow ||
-      pFormNode->GetElementType() == XFA_Element::Break) {
-    bIsOverflowNode = true;
-  }
-  for (CXFA_Node* pCurNode = bIsOverflowNode ? pFormNode
-                                             : pFormNode->GetFirstChild();
-       pCurNode; pCurNode = pCurNode->GetNextSibling()) {
-    if (BreakOverflow(pCurNode, pLeaderTemplate, pTrailerTemplate,
-                      bCreatePage)) {
-      if (bIsOverflowNode)
-        pFormNode = pCurNode->GetParent();
-
-      CXFA_Document* pDocument = pCurNode->GetDocument();
-      CXFA_Node* pDataScope = nullptr;
-      if (pLeaderTemplate) {
-        if (!pDataScope)
-          pDataScope = XFA_DataMerge_FindDataScope(pFormNode);
-
-        pLeaderNode = pDocument->DataMerge_CopyContainer(
-            pLeaderTemplate, pFormNode, pDataScope, true, true, true);
-        pDocument->DataMerge_UpdateBindingRelations(pLeaderNode);
-        SetLayoutGeneratedNodeFlag(pLeaderNode);
-      }
-      if (pTrailerTemplate) {
-        if (!pDataScope)
-          pDataScope = XFA_DataMerge_FindDataScope(pFormNode);
-
-        pTrailerNode = pDocument->DataMerge_CopyContainer(
-            pTrailerTemplate, pFormNode, pDataScope, true, true, true);
-        pDocument->DataMerge_UpdateBindingRelations(pTrailerNode);
-        SetLayoutGeneratedNodeFlag(pTrailerNode);
-      }
-      return true;
-    }
-    if (bIsOverflowNode) {
-      break;
-    }
-  }
-  return false;
-}
-
-bool CXFA_LayoutPageMgr::ResolveBookendLeaderOrTrailer(
-    CXFA_Node* pBookendNode,
-    bool bLeader,
-    CXFA_Node*& pBookendAppendTemplate) {
-  CXFA_Node* pContainer =
-      pBookendNode->GetContainerParent()->GetTemplateNodeIfExists();
-  if (pBookendNode->GetElementType() == XFA_Element::Break) {
-    WideString leader = pBookendNode->JSObject()->GetCData(
-        bLeader ? XFA_Attribute::BookendLeader : XFA_Attribute::BookendTrailer);
-    if (!leader.IsEmpty()) {
-      pBookendAppendTemplate = ResolveBreakTarget(pContainer, false, leader);
-      return true;
-    }
-    return false;
-  }
-
-  if (pBookendNode->GetElementType() == XFA_Element::Bookend) {
-    WideString leader = pBookendNode->JSObject()->GetCData(
-        bLeader ? XFA_Attribute::Leader : XFA_Attribute::Trailer);
-    pBookendAppendTemplate = ResolveBreakTarget(pContainer, true, leader);
-    return true;
-  }
-  return false;
-}
-
-bool CXFA_LayoutPageMgr::FindPageAreaFromPageSet(CXFA_Node* pPageSet,
-                                                 CXFA_Node* pStartChild,
-                                                 CXFA_Node* pTargetPageArea,
-                                                 CXFA_Node* pTargetContentArea,
-                                                 bool bNewPage,
-                                                 bool bQuery) {
-  if (!pPageSet && !pStartChild)
-    return false;
-
-  if (IsPageSetRootOrderedOccurrence()) {
-    return FindPageAreaFromPageSet_Ordered(pPageSet, pStartChild,
-                                           pTargetPageArea, pTargetContentArea,
-                                           bNewPage, bQuery);
-  }
-  XFA_AttributeEnum ePreferredPosition =
-      m_CurrentContainerRecordIter != m_ProposedContainerRecords.end()
-          ? XFA_AttributeEnum::Rest
-          : XFA_AttributeEnum::First;
-  return FindPageAreaFromPageSet_SimplexDuplex(
-      pPageSet, pStartChild, pTargetPageArea, pTargetContentArea, bNewPage,
-      bQuery, ePreferredPosition);
-}
-
-bool CXFA_LayoutPageMgr::FindPageAreaFromPageSet_Ordered(
-    CXFA_Node* pPageSet,
-    CXFA_Node* pStartChild,
-    CXFA_Node* pTargetPageArea,
-    CXFA_Node* pTargetContentArea,
-    bool bNewPage,
-    bool bQuery) {
-  int32_t iPageSetCount = 0;
-  if (!pStartChild && !bQuery) {
-    auto it = m_pPageSetMap.find(pPageSet);
-    if (it != m_pPageSetMap.end())
-      iPageSetCount = it->second;
-    int32_t iMax = -1;
-    CXFA_Node* pOccurNode =
-        pPageSet->GetFirstChildByClass<CXFA_Occur>(XFA_Element::Occur);
-    if (pOccurNode) {
-      Optional<int32_t> ret =
-          pOccurNode->JSObject()->TryInteger(XFA_Attribute::Max, false);
-      if (ret)
-        iMax = *ret;
-    }
-    if (iMax >= 0 && iMax <= iPageSetCount)
-      return false;
-  }
-
-  bool bRes = false;
-  CXFA_Node* pCurrentNode =
-      pStartChild ? pStartChild->GetNextSibling() : pPageSet->GetFirstChild();
-  for (; pCurrentNode; pCurrentNode = pCurrentNode->GetNextSibling()) {
-    if (pCurrentNode->GetElementType() == XFA_Element::PageArea) {
-      if ((pTargetPageArea == pCurrentNode || !pTargetPageArea)) {
-        if (!pCurrentNode->GetFirstChildByClass<CXFA_ContentArea>(
-                XFA_Element::ContentArea)) {
-          if (pTargetPageArea == pCurrentNode) {
-            CreateMinPageRecord(pCurrentNode, true);
-            pTargetPageArea = nullptr;
-          }
-          continue;
-        }
-        if (!bQuery) {
-          CXFA_ContainerRecord* pNewRecord =
-              CreateContainerRecord(pCurrentNode, !pStartChild);
-          AddPageAreaLayoutItem(pNewRecord, pCurrentNode);
-          if (!pTargetContentArea) {
-            pTargetContentArea =
-                pCurrentNode->GetFirstChildByClass<CXFA_ContentArea>(
-                    XFA_Element::ContentArea);
-          }
-          AddContentAreaLayoutItem(pNewRecord, pTargetContentArea);
-        }
-        m_pCurPageArea = pCurrentNode;
-        m_nCurPageCount = 1;
-        bRes = true;
-        break;
-      }
-      if (!bQuery)
-        CreateMinPageRecord(pCurrentNode, false);
-    } else if (pCurrentNode->GetElementType() == XFA_Element::PageSet) {
-      if (FindPageAreaFromPageSet_Ordered(pCurrentNode, nullptr,
-                                          pTargetPageArea, pTargetContentArea,
-                                          bNewPage, bQuery)) {
-        bRes = true;
-        break;
-      }
-      if (!bQuery)
-        CreateMinPageSetRecord(pCurrentNode, true);
-    }
-  }
-  if (!pStartChild && bRes && !bQuery)
-    m_pPageSetMap[pPageSet] = ++iPageSetCount;
-  return bRes;
-}
-
-bool CXFA_LayoutPageMgr::FindPageAreaFromPageSet_SimplexDuplex(
-    CXFA_Node* pPageSet,
-    CXFA_Node* pStartChild,
-    CXFA_Node* pTargetPageArea,
-    CXFA_Node* pTargetContentArea,
-    bool bNewPage,
-    bool bQuery,
-    XFA_AttributeEnum ePreferredPosition) {
-  const XFA_AttributeEnum eFallbackPosition = XFA_AttributeEnum::Any;
-  CXFA_Node* pPreferredPageArea = nullptr;
-  CXFA_Node* pFallbackPageArea = nullptr;
-  CXFA_Node* pCurrentNode = nullptr;
-  if (!pStartChild || pStartChild->GetElementType() == XFA_Element::PageArea)
-    pCurrentNode = pPageSet->GetFirstChild();
-  else
-    pCurrentNode = pStartChild->GetNextSibling();
-
-  for (; pCurrentNode; pCurrentNode = pCurrentNode->GetNextSibling()) {
-    if (pCurrentNode->GetElementType() == XFA_Element::PageArea) {
-      if (!MatchPageAreaOddOrEven(pCurrentNode))
-        continue;
-
-      XFA_AttributeEnum eCurPagePosition =
-          pCurrentNode->JSObject()->GetEnum(XFA_Attribute::PagePosition);
-      if (ePreferredPosition == XFA_AttributeEnum::Last) {
-        if (eCurPagePosition != ePreferredPosition)
-          continue;
-        if (m_ePageSetMode == XFA_AttributeEnum::SimplexPaginated ||
-            pCurrentNode->JSObject()->GetEnum(XFA_Attribute::OddOrEven) ==
-                XFA_AttributeEnum::Any) {
-          pPreferredPageArea = pCurrentNode;
-          break;
-        }
-        CXFA_ContainerRecord* pNewRecord = CreateContainerRecord();
-        AddPageAreaLayoutItem(pNewRecord, pCurrentNode);
-        AddContentAreaLayoutItem(
-            pNewRecord, pCurrentNode->GetFirstChildByClass<CXFA_ContentArea>(
-                            XFA_Element::ContentArea));
-        pPreferredPageArea = pCurrentNode;
-        return false;
-      }
-      if (ePreferredPosition == XFA_AttributeEnum::Only) {
-        if (eCurPagePosition != ePreferredPosition)
-          continue;
-        if (m_ePageSetMode != XFA_AttributeEnum::DuplexPaginated ||
-            pCurrentNode->JSObject()->GetEnum(XFA_Attribute::OddOrEven) ==
-                XFA_AttributeEnum::Any) {
-          pPreferredPageArea = pCurrentNode;
-          break;
-        }
-        return false;
-      }
-      if ((pTargetPageArea == pCurrentNode || !pTargetPageArea)) {
-        if (!pCurrentNode->GetFirstChildByClass<CXFA_ContentArea>(
-                XFA_Element::ContentArea)) {
-          if (pTargetPageArea == pCurrentNode) {
-            CXFA_ContainerRecord* pNewRecord = CreateContainerRecord();
-            AddPageAreaLayoutItem(pNewRecord, pCurrentNode);
-            pTargetPageArea = nullptr;
-          }
-          continue;
-        }
-        if ((ePreferredPosition == XFA_AttributeEnum::Rest &&
-             eCurPagePosition == XFA_AttributeEnum::Any) ||
-            eCurPagePosition == ePreferredPosition) {
-          pPreferredPageArea = pCurrentNode;
-          break;
-        }
-        if (eCurPagePosition == eFallbackPosition && !pFallbackPageArea) {
-          pFallbackPageArea = pCurrentNode;
-        }
-      } else if (pTargetPageArea && !MatchPageAreaOddOrEven(pTargetPageArea)) {
-        CXFA_ContainerRecord* pNewRecord = CreateContainerRecord();
-        AddPageAreaLayoutItem(pNewRecord, pCurrentNode);
-        AddContentAreaLayoutItem(
-            pNewRecord, pCurrentNode->GetFirstChildByClass<CXFA_ContentArea>(
-                            XFA_Element::ContentArea));
-      }
-    } else if (pCurrentNode->GetElementType() == XFA_Element::PageSet) {
-      if (FindPageAreaFromPageSet_SimplexDuplex(
-              pCurrentNode, nullptr, pTargetPageArea, pTargetContentArea,
-              bNewPage, bQuery, ePreferredPosition)) {
-        break;
-      }
-    }
-  }
-
-  CXFA_Node* pCurPageArea = nullptr;
-  if (pPreferredPageArea)
-    pCurPageArea = pPreferredPageArea;
-  else if (pFallbackPageArea)
-    pCurPageArea = pFallbackPageArea;
-
-  if (!pCurPageArea)
-    return false;
-
-  if (!bQuery) {
-    CXFA_ContainerRecord* pNewRecord = CreateContainerRecord();
-    AddPageAreaLayoutItem(pNewRecord, pCurPageArea);
-    if (!pTargetContentArea) {
-      pTargetContentArea = pCurPageArea->GetFirstChildByClass<CXFA_ContentArea>(
-          XFA_Element::ContentArea);
-    }
-    AddContentAreaLayoutItem(pNewRecord, pTargetContentArea);
-  }
-  m_pCurPageArea = pCurPageArea;
-  return true;
-}
-
-bool CXFA_LayoutPageMgr::MatchPageAreaOddOrEven(CXFA_Node* pPageArea) {
-  if (m_ePageSetMode != XFA_AttributeEnum::DuplexPaginated)
-    return true;
-
-  Optional<XFA_AttributeEnum> ret =
-      pPageArea->JSObject()->TryEnum(XFA_Attribute::OddOrEven, true);
-  if (!ret || *ret == XFA_AttributeEnum::Any)
-    return true;
-
-  int32_t iPageLast = GetPageCount() % 2;
-  return *ret == XFA_AttributeEnum::Odd ? iPageLast == 0 : iPageLast == 1;
-}
-
-CXFA_Node* CXFA_LayoutPageMgr::GetNextAvailPageArea(
-    CXFA_Node* pTargetPageArea,
-    CXFA_Node* pTargetContentArea,
-    bool bNewPage,
-    bool bQuery) {
-  if (!m_pCurPageArea) {
-    FindPageAreaFromPageSet(m_pTemplatePageSetRoot, nullptr, pTargetPageArea,
-                            pTargetContentArea, bNewPage, bQuery);
-    ASSERT(m_pCurPageArea);
-    return m_pCurPageArea;
-  }
-
-  if (!pTargetPageArea || pTargetPageArea == m_pCurPageArea) {
-    if (!bNewPage && GetNextContentArea(pTargetContentArea))
-      return m_pCurPageArea;
-
-    if (IsPageSetRootOrderedOccurrence()) {
-      int32_t iMax = -1;
-      CXFA_Node* pOccurNode =
-          m_pCurPageArea->GetFirstChildByClass<CXFA_Occur>(XFA_Element::Occur);
-      if (pOccurNode) {
-        Optional<int32_t> ret =
-            pOccurNode->JSObject()->TryInteger(XFA_Attribute::Max, false);
-        if (ret)
-          iMax = *ret;
-      }
-      if ((iMax < 0 || m_nCurPageCount < iMax)) {
-        if (!bQuery) {
-          CXFA_ContainerRecord* pNewRecord =
-              CreateContainerRecord(m_pCurPageArea);
-          AddPageAreaLayoutItem(pNewRecord, m_pCurPageArea);
-          if (!pTargetContentArea) {
-            pTargetContentArea =
-                m_pCurPageArea->GetFirstChildByClass<CXFA_ContentArea>(
-                    XFA_Element::ContentArea);
-          }
-          AddContentAreaLayoutItem(pNewRecord, pTargetContentArea);
-        }
-        m_nCurPageCount++;
-        return m_pCurPageArea;
-      }
-    }
-  }
-
-  if (!bQuery && IsPageSetRootOrderedOccurrence())
-    CreateMinPageRecord(m_pCurPageArea, false, true);
-  if (FindPageAreaFromPageSet(m_pCurPageArea->GetParent(), m_pCurPageArea,
-                              pTargetPageArea, pTargetContentArea, bNewPage,
-                              bQuery)) {
-    return m_pCurPageArea;
-  }
-
-  CXFA_Node* pPageSet = m_pCurPageArea->GetParent();
-  while (true) {
-    if (FindPageAreaFromPageSet(pPageSet, nullptr, pTargetPageArea,
-                                pTargetContentArea, bNewPage, bQuery)) {
-      return m_pCurPageArea;
-    }
-    if (!bQuery && IsPageSetRootOrderedOccurrence())
-      CreateMinPageSetRecord(pPageSet);
-    if (FindPageAreaFromPageSet(nullptr, pPageSet, pTargetPageArea,
-                                pTargetContentArea, bNewPage, bQuery)) {
-      return m_pCurPageArea;
-    }
-    if (pPageSet == m_pTemplatePageSetRoot)
-      break;
-
-    pPageSet = pPageSet->GetParent();
-  }
-  return nullptr;
-}
-
-bool CXFA_LayoutPageMgr::GetNextContentArea(CXFA_Node* pContentArea) {
-  CXFA_Node* pCurContentNode =
-      GetCurrentContainerRecord()->pCurContentArea->m_pFormNode;
-  if (!pContentArea) {
-    pContentArea = pCurContentNode->GetNextSameClassSibling<CXFA_ContentArea>(
-        XFA_Element::ContentArea);
-    if (!pContentArea)
-      return false;
-  } else {
-    if (pContentArea->GetParent() != m_pCurPageArea)
-      return false;
-
-    CXFA_ContainerLayoutItem* pContentAreaLayout = nullptr;
-    if (!CheckContentAreaNotUsed(GetCurrentContainerRecord()->pCurPageArea,
-                                 pContentArea, pContentAreaLayout)) {
-      return false;
-    }
-    if (pContentAreaLayout) {
-      if (pContentAreaLayout->m_pFormNode != pCurContentNode) {
-        CXFA_ContainerRecord* pNewRecord = CreateContainerRecord();
-        pNewRecord->pCurContentArea = pContentAreaLayout;
-        return true;
-      }
-      return false;
-    }
-  }
-
-  CXFA_ContainerRecord* pNewRecord = CreateContainerRecord();
-  AddContentAreaLayoutItem(pNewRecord, pContentArea);
-  return true;
-}
-
-void CXFA_LayoutPageMgr::InitPageSetMap() {
-  if (!IsPageSetRootOrderedOccurrence())
-    return;
-
-  CXFA_NodeIterator sIterator(m_pTemplatePageSetRoot);
-  for (CXFA_Node* pPageSetNode = sIterator.GetCurrent(); pPageSetNode;
-       pPageSetNode = sIterator.MoveToNext()) {
-    if (pPageSetNode->GetElementType() == XFA_Element::PageSet) {
-      XFA_AttributeEnum eRelation =
-          pPageSetNode->JSObject()->GetEnum(XFA_Attribute::Relation);
-      if (eRelation == XFA_AttributeEnum::OrderedOccurrence)
-        m_pPageSetMap[pPageSetNode] = 0;
-    }
-  }
-}
-
-int32_t CXFA_LayoutPageMgr::CreateMinPageRecord(CXFA_Node* pPageArea,
-                                                bool bTargetPageArea,
-                                                bool bCreateLast) {
-  if (!pPageArea)
-    return 0;
-
-  int32_t iMin = 0;
-  Optional<int32_t> ret;
-  CXFA_Node* pOccurNode =
-      pPageArea->GetFirstChildByClass<CXFA_Occur>(XFA_Element::Occur);
-  if (pOccurNode) {
-    ret = pOccurNode->JSObject()->TryInteger(XFA_Attribute::Min, false);
-    if (ret)
-      iMin = *ret;
-  }
-
-  if (!ret && !bTargetPageArea)
-    return iMin;
-
-  CXFA_Node* pContentArea = pPageArea->GetFirstChildByClass<CXFA_ContentArea>(
-      XFA_Element::ContentArea);
-  if (iMin < 1 && bTargetPageArea && !pContentArea)
-    iMin = 1;
-
-  int32_t i = 0;
-  if (bCreateLast)
-    i = m_nCurPageCount;
-
-  for (; i < iMin; i++) {
-    CXFA_ContainerRecord* pNewRecord = CreateContainerRecord();
-    AddPageAreaLayoutItem(pNewRecord, pPageArea);
-    AddContentAreaLayoutItem(pNewRecord, pContentArea);
-  }
-  return iMin;
-}
-
-void CXFA_LayoutPageMgr::CreateMinPageSetRecord(CXFA_Node* pPageSet,
-                                                bool bCreateAll) {
-  if (!pPageSet)
-    return;
-
-  auto it = m_pPageSetMap.find(pPageSet);
-  if (it == m_pPageSetMap.end())
-    return;
-
-  int32_t iCurSetCount = it->second;
-  if (bCreateAll)
-    iCurSetCount = 0;
-
-  CXFA_Node* pOccurNode =
-      pPageSet->GetFirstChildByClass<CXFA_Occur>(XFA_Element::Occur);
-  if (!pOccurNode)
-    return;
-
-  Optional<int32_t> iMin =
-      pOccurNode->JSObject()->TryInteger(XFA_Attribute::Min, false);
-  if (!iMin || iCurSetCount >= *iMin)
-    return;
-
-  for (int32_t i = 0; i < *iMin - iCurSetCount; i++) {
-    for (CXFA_Node* node = pPageSet->GetFirstChild(); node;
-         node = node->GetNextSibling()) {
-      if (node->GetElementType() == XFA_Element::PageArea)
-        CreateMinPageRecord(node, false);
-      else if (node->GetElementType() == XFA_Element::PageSet)
-        CreateMinPageSetRecord(node, true);
-    }
-  }
-  m_pPageSetMap[pPageSet] = *iMin;
-}
-
-void CXFA_LayoutPageMgr::CreateNextMinRecord(CXFA_Node* pRecordNode) {
-  if (!pRecordNode)
-    return;
-
-  for (CXFA_Node* pCurrentNode = pRecordNode->GetNextSibling(); pCurrentNode;
-       pCurrentNode = pCurrentNode->GetNextSibling()) {
-    if (pCurrentNode->GetElementType() == XFA_Element::PageArea)
-      CreateMinPageRecord(pCurrentNode, false);
-    else if (pCurrentNode->GetElementType() == XFA_Element::PageSet)
-      CreateMinPageSetRecord(pCurrentNode, true);
-  }
-}
-
-void CXFA_LayoutPageMgr::ProcessLastPageSet() {
-  CreateMinPageRecord(m_pCurPageArea, false, true);
-  CreateNextMinRecord(m_pCurPageArea);
-  CXFA_Node* pPageSet = m_pCurPageArea->GetParent();
-  while (true) {
-    CreateMinPageSetRecord(pPageSet);
-    if (pPageSet == m_pTemplatePageSetRoot)
-      break;
-
-    CreateNextMinRecord(pPageSet);
-    pPageSet = pPageSet->GetParent();
-  }
-}
-
-bool CXFA_LayoutPageMgr::GetNextAvailContentHeight(float fChildHeight) {
-  CXFA_Node* pCurContentNode =
-      GetCurrentContainerRecord()->pCurContentArea->m_pFormNode;
-  if (!pCurContentNode)
-    return false;
-
-  pCurContentNode = pCurContentNode->GetNextSameClassSibling<CXFA_ContentArea>(
-      XFA_Element::ContentArea);
-  if (pCurContentNode) {
-    float fNextContentHeight = pCurContentNode->JSObject()
-                                   ->GetMeasure(XFA_Attribute::H)
-                                   .ToUnit(XFA_Unit::Pt);
-    return fNextContentHeight > fChildHeight;
-  }
-
-  CXFA_Node* pPageNode = GetCurrentContainerRecord()->pCurPageArea->m_pFormNode;
-  CXFA_Node* pOccurNode =
-      pPageNode->GetFirstChildByClass<CXFA_Occur>(XFA_Element::Occur);
-  int32_t iMax = 0;
-  Optional<int32_t> ret;
-  if (pOccurNode) {
-    ret = pOccurNode->JSObject()->TryInteger(XFA_Attribute::Max, false);
-    if (ret)
-      iMax = *ret;
-  }
-  if (ret) {
-    if (m_nCurPageCount == iMax) {
-      CXFA_Node* pSrcPage = m_pCurPageArea;
-      int32_t nSrcPageCount = m_nCurPageCount;
-      auto psSrcIter = GetTailPosition();
-      CXFA_Node* pNextPage =
-          GetNextAvailPageArea(nullptr, nullptr, false, true);
-      m_pCurPageArea = pSrcPage;
-      m_nCurPageCount = nSrcPageCount;
-      CXFA_ContainerRecord* pPrevRecord = *psSrcIter++;
-      while (psSrcIter != m_ProposedContainerRecords.end()) {
-        auto psSaveIter = psSrcIter;
-        CXFA_ContainerRecord* pInsertRecord = *psSrcIter++;
-        RemoveLayoutRecord(pInsertRecord, pPrevRecord);
-        delete pInsertRecord;
-        m_ProposedContainerRecords.erase(psSaveIter);
-      }
-      if (pNextPage) {
-        CXFA_Node* pContentArea =
-            pNextPage->GetFirstChildByClass<CXFA_ContentArea>(
-                XFA_Element::ContentArea);
-        if (pContentArea) {
-          float fNextContentHeight = pContentArea->JSObject()
-                                         ->GetMeasure(XFA_Attribute::H)
-                                         .ToUnit(XFA_Unit::Pt);
-          if (fNextContentHeight > fChildHeight)
-            return true;
-        }
-      }
-      return false;
-    }
-  }
-
-  CXFA_Node* pContentArea = pPageNode->GetFirstChildByClass<CXFA_ContentArea>(
-      XFA_Element::ContentArea);
-  float fNextContentHeight = pContentArea->JSObject()
-                                 ->GetMeasure(XFA_Attribute::H)
-                                 .ToUnit(XFA_Unit::Pt);
-  if (fNextContentHeight < XFA_LAYOUT_FLOAT_PERCISION)
-    return true;
-  if (fNextContentHeight > fChildHeight)
-    return true;
-  return false;
-}
-
-void CXFA_LayoutPageMgr::ClearData() {
-  if (!m_pTemplatePageSetRoot)
-    return;
-
-  auto sPos = m_ProposedContainerRecords.begin();
-  while (sPos != m_ProposedContainerRecords.end()) {
-    CXFA_ContainerRecord* pRecord = *sPos++;
-    delete pRecord;
-  }
-  m_ProposedContainerRecords.clear();
-  m_CurrentContainerRecordIter = m_ProposedContainerRecords.end();
-  m_pCurPageArea = nullptr;
-  m_nCurPageCount = 0;
-  m_bCreateOverFlowPage = false;
-  m_pPageSetMap.clear();
-}
-
-void CXFA_LayoutPageMgr::SaveLayoutItem(CXFA_LayoutItem* pParentLayoutItem) {
-  CXFA_LayoutItem* pNextLayoutItem;
-  CXFA_LayoutItem* pCurLayoutItem = pParentLayoutItem->m_pFirstChild;
-  while (pCurLayoutItem) {
-    pNextLayoutItem = pCurLayoutItem->m_pNextSibling;
-    if (pCurLayoutItem->IsContentLayoutItem()) {
-      if (pCurLayoutItem->m_pFormNode->HasRemovedChildren()) {
-        CXFA_FFNotify* pNotify =
-            m_pTemplatePageSetRoot->GetDocument()->GetNotify();
-        CXFA_LayoutProcessor* pDocLayout =
-            m_pTemplatePageSetRoot->GetDocument()->GetDocLayout();
-        if (pCurLayoutItem->m_pFirstChild)
-          SyncRemoveLayoutItem(pCurLayoutItem, pNotify, pDocLayout);
-
-        pNotify->OnLayoutItemRemoving(pDocLayout, pCurLayoutItem);
-        delete pCurLayoutItem;
-        pCurLayoutItem = pNextLayoutItem;
-        continue;
-      }
-
-      if (pCurLayoutItem->m_pFormNode->IsLayoutGeneratedNode()) {
-        CXFA_NodeIteratorTemplate<CXFA_Node, CXFA_TraverseStrategy_XFANode>
-            sIterator(pCurLayoutItem->m_pFormNode);
-        for (CXFA_Node* pNode = sIterator.GetCurrent(); pNode;
-             pNode = sIterator.MoveToNext()) {
-          pNode->SetFlag(XFA_NodeFlag_UnusedNode, false);
-        }
-      }
-    }
-
-    if (pCurLayoutItem->m_pFirstChild)
-      SaveLayoutItem(pCurLayoutItem);
-
-    pCurLayoutItem->m_pParent = nullptr;
-    pCurLayoutItem->m_pNextSibling = nullptr;
-    pCurLayoutItem->m_pFirstChild = nullptr;
-    if (!pCurLayoutItem->IsContentLayoutItem() &&
-        pCurLayoutItem->m_pFormNode->GetElementType() !=
-            XFA_Element::PageArea) {
-      delete pCurLayoutItem;
-    }
-    pCurLayoutItem = pNextLayoutItem;
-  }
-}
-
-CXFA_Node* CXFA_LayoutPageMgr::QueryOverflow(CXFA_Node* pFormNode) {
-  for (CXFA_Node* pCurNode = pFormNode->GetFirstChild(); pCurNode;
-       pCurNode = pCurNode->GetNextSibling()) {
-    if (pCurNode->GetElementType() == XFA_Element::Break) {
-      WideString wsOverflowLeader =
-          pCurNode->JSObject()->GetCData(XFA_Attribute::OverflowLeader);
-      WideString wsOverflowTarget =
-          pCurNode->JSObject()->GetCData(XFA_Attribute::OverflowTarget);
-      WideString wsOverflowTrailer =
-          pCurNode->JSObject()->GetCData(XFA_Attribute::OverflowTrailer);
-
-      if (!wsOverflowLeader.IsEmpty() || !wsOverflowTrailer.IsEmpty() ||
-          !wsOverflowTarget.IsEmpty()) {
-        return pCurNode;
-      }
-      return nullptr;
-    }
-    if (pCurNode->GetElementType() == XFA_Element::Overflow)
-      return pCurNode;
-  }
-  return nullptr;
-}
-
-void CXFA_LayoutPageMgr::MergePageSetContents() {
-  CXFA_Document* pDocument = m_pTemplatePageSetRoot->GetDocument();
-  CXFA_FFNotify* pNotify = pDocument->GetNotify();
-  CXFA_LayoutProcessor* pDocLayout = pDocument->GetDocLayout();
-  CXFA_ContainerLayoutItem* pRootLayout = GetRootLayoutItem();
-  for (CXFA_Node* pPageNode : pDocument->m_pPendingPageSet) {
-    CXFA_NodeIteratorTemplate<CXFA_Node, CXFA_TraverseStrategy_XFANode>
-        sIterator(pPageNode);
-    for (CXFA_Node* pNode = sIterator.GetCurrent(); pNode;
-         pNode = sIterator.MoveToNext()) {
-      if (pNode->IsContainerNode()) {
-        CXFA_Node* pBindNode = pNode->GetBindData();
-        if (pBindNode) {
-          pBindNode->RemoveBindItem(pNode);
-          pNode->SetBindingNode(nullptr);
-        }
-      }
-      pNode->SetFlag(XFA_NodeFlag_UnusedNode, true);
-    }
-  }
-
-  int32_t iIndex = 0;
-  for (; pRootLayout; pRootLayout = static_cast<CXFA_ContainerLayoutItem*>(
-                          pRootLayout->m_pNextSibling)) {
-    CXFA_Node* pPendingPageSet = nullptr;
-    CXFA_NodeIteratorTemplate<
-        CXFA_ContainerLayoutItem,
-        CXFA_TraverseStrategy_ContentAreaContainerLayoutItem>
-        iterator(pRootLayout);
-    CXFA_ContainerLayoutItem* pRootPageSetContainerItem = iterator.GetCurrent();
-    ASSERT(pRootPageSetContainerItem->m_pFormNode->GetElementType() ==
-           XFA_Element::PageSet);
-    if (iIndex <
-        pdfium::CollectionSize<int32_t>(pDocument->m_pPendingPageSet)) {
-      pPendingPageSet = pDocument->m_pPendingPageSet[iIndex];
-      iIndex++;
-    }
-    if (!pPendingPageSet) {
-      if (pRootPageSetContainerItem->m_pFormNode->GetPacketType() ==
-          XFA_PacketType::Template) {
-        pPendingPageSet =
-            pRootPageSetContainerItem->m_pFormNode->CloneTemplateToForm(false);
-      } else {
-        pPendingPageSet = pRootPageSetContainerItem->m_pFormNode;
-      }
-    }
-    if (pRootPageSetContainerItem->m_pFormNode->JSObject()->GetLayoutItem() ==
-        pRootPageSetContainerItem) {
-      pRootPageSetContainerItem->m_pFormNode->JSObject()->SetLayoutItem(
-          nullptr);
-    }
-    pRootPageSetContainerItem->m_pFormNode = pPendingPageSet;
-    pPendingPageSet->ClearFlag(XFA_NodeFlag_UnusedNode);
-    for (CXFA_ContainerLayoutItem* pContainerItem = iterator.MoveToNext();
-         pContainerItem; pContainerItem = iterator.MoveToNext()) {
-      CXFA_Node* pNode = pContainerItem->m_pFormNode;
-      if (pNode->GetPacketType() != XFA_PacketType::Template)
-        continue;
-
-      switch (pNode->GetElementType()) {
-        case XFA_Element::PageSet: {
-          CXFA_Node* pParentNode = pContainerItem->m_pParent->m_pFormNode;
-          pContainerItem->m_pFormNode = XFA_NodeMerge_CloneOrMergeContainer(
-              pDocument, pParentNode, pContainerItem->m_pFormNode, true,
-              nullptr);
-          break;
-        }
-        case XFA_Element::PageArea: {
-          CXFA_LayoutItem* pFormLayout = pContainerItem;
-          CXFA_Node* pParentNode = pContainerItem->m_pParent->m_pFormNode;
-          bool bIsExistForm = true;
-          for (int32_t iLevel = 0; iLevel < 3; iLevel++) {
-            pFormLayout = pFormLayout->m_pFirstChild;
-            if (iLevel == 2) {
-              while (pFormLayout &&
-                     !XFA_ItemLayoutProcessor_IsTakingSpace(
-                         pFormLayout->m_pFormNode)) {
-                pFormLayout = pFormLayout->m_pNextSibling;
-              }
-            }
-            if (!pFormLayout) {
-              bIsExistForm = false;
-              break;
-            }
-          }
-          if (bIsExistForm) {
-            CXFA_Node* pNewSubform = pFormLayout->m_pFormNode;
-            if (pContainerItem->m_pOldSubform &&
-                pContainerItem->m_pOldSubform != pNewSubform) {
-              CXFA_Node* pExistingNode = XFA_DataMerge_FindFormDOMInstance(
-                  pDocument, pContainerItem->m_pFormNode->GetElementType(),
-                  pContainerItem->m_pFormNode->GetNameHash(), pParentNode);
-              CXFA_ContainerIterator sIterator(pExistingNode);
-              for (CXFA_Node* pIter = sIterator.GetCurrent(); pIter;
-                   pIter = sIterator.MoveToNext()) {
-                if (pIter->GetElementType() != XFA_Element::ContentArea) {
-                  CXFA_LayoutItem* pLayoutItem =
-                      pIter->JSObject()->GetLayoutItem();
-                  if (pLayoutItem) {
-                    pNotify->OnLayoutItemRemoving(pDocLayout, pLayoutItem);
-                    delete pLayoutItem;
-                  }
-                }
-              }
-              if (pExistingNode) {
-                pParentNode->RemoveChild(pExistingNode, true);
-              }
-            }
-            pContainerItem->m_pOldSubform = pNewSubform;
-          }
-          pContainerItem->m_pFormNode = pDocument->DataMerge_CopyContainer(
-              pContainerItem->m_pFormNode, pParentNode,
-              ToNode(pDocument->GetXFAObject(XFA_HASHCODE_Record)), true, true,
-              true);
-          break;
-        }
-        case XFA_Element::ContentArea: {
-          CXFA_Node* pParentNode = pContainerItem->m_pParent->m_pFormNode;
-          for (CXFA_Node* pChildNode = pParentNode->GetFirstChild(); pChildNode;
-               pChildNode = pChildNode->GetNextSibling()) {
-            if (pChildNode->GetTemplateNodeIfExists() !=
-                pContainerItem->m_pFormNode) {
-              continue;
-            }
-            pContainerItem->m_pFormNode = pChildNode;
-            break;
-          }
-          break;
-        }
-        default:
-          break;
-      }
-    }
-    if (!pPendingPageSet->GetParent()) {
-      CXFA_Node* pFormToplevelSubform =
-          pDocument->GetXFAObject(XFA_HASHCODE_Form)
-              ->AsNode()
-              ->GetFirstChildByClass<CXFA_Subform>(XFA_Element::Subform);
-      pFormToplevelSubform->InsertChild(pPendingPageSet, nullptr);
-    }
-    pDocument->DataMerge_UpdateBindingRelations(pPendingPageSet);
-    pPendingPageSet->SetFlag(XFA_NodeFlag_Initialized, true);
-  }
-
-  CXFA_Node* pPageSet = GetRootLayoutItem()->m_pFormNode;
-  while (pPageSet) {
-    CXFA_Node* pNextPageSet =
-        pPageSet->GetNextSameClassSibling<CXFA_PageSet>(XFA_Element::PageSet);
-    CXFA_NodeIteratorTemplate<CXFA_Node, CXFA_TraverseStrategy_XFANode>
-        sIterator(pPageSet);
-    CXFA_Node* pNode = sIterator.GetCurrent();
-    while (pNode) {
-      if (pNode->IsUnusedNode()) {
-        if (pNode->IsContainerNode()) {
-          XFA_Element eType = pNode->GetElementType();
-          if (eType == XFA_Element::PageArea || eType == XFA_Element::PageSet) {
-            CXFA_ContainerIterator iteChild(pNode);
-            CXFA_Node* pChildNode = iteChild.MoveToNext();
-            for (; pChildNode; pChildNode = iteChild.MoveToNext()) {
-              CXFA_LayoutItem* pLayoutItem =
-                  pChildNode->JSObject()->GetLayoutItem();
-              if (pLayoutItem) {
-                pNotify->OnLayoutItemRemoving(pDocLayout, pLayoutItem);
-                delete pLayoutItem;
-              }
-            }
-          } else if (eType != XFA_Element::ContentArea) {
-            CXFA_LayoutItem* pLayoutItem = pNode->JSObject()->GetLayoutItem();
-            if (pLayoutItem) {
-              pNotify->OnLayoutItemRemoving(pDocLayout, pLayoutItem);
-              delete pLayoutItem;
-            }
-          }
-          CXFA_Node* pNext = sIterator.SkipChildrenAndMoveToNext();
-          pNode->GetParent()->RemoveChild(pNode, true);
-          pNode = pNext;
-        } else {
-          pNode->ClearFlag(XFA_NodeFlag_UnusedNode);
-          pNode->SetFlag(XFA_NodeFlag_Initialized, true);
-          pNode = sIterator.MoveToNext();
-        }
-      } else {
-        pNode->SetFlag(XFA_NodeFlag_Initialized, true);
-        pNode = sIterator.MoveToNext();
-      }
-    }
-    pPageSet = pNextPageSet;
-  }
-}
-
-void CXFA_LayoutPageMgr::LayoutPageSetContents() {
-  CXFA_ContainerLayoutItem* pRootLayoutItem = GetRootLayoutItem();
-  for (; pRootLayoutItem;
-       pRootLayoutItem = static_cast<CXFA_ContainerLayoutItem*>(
-           pRootLayoutItem->m_pNextSibling)) {
-    CXFA_NodeIteratorTemplate<
-        CXFA_ContainerLayoutItem,
-        CXFA_TraverseStrategy_ContentAreaContainerLayoutItem>
-        iterator(pRootLayoutItem);
-    for (CXFA_ContainerLayoutItem* pContainerItem = iterator.GetCurrent();
-         pContainerItem; pContainerItem = iterator.MoveToNext()) {
-      CXFA_Node* pNode = pContainerItem->m_pFormNode;
-      switch (pNode->GetElementType()) {
-        case XFA_Element::PageArea:
-          m_pLayoutProcessor->GetRootRootItemLayoutProcessor()
-              ->DoLayoutPageArea(pContainerItem);
-          break;
-        default:
-          break;
-      }
-    }
-  }
-}
-
-void CXFA_LayoutPageMgr::SyncLayoutData() {
-  MergePageSetContents();
-  LayoutPageSetContents();
-  CXFA_FFNotify* pNotify = m_pTemplatePageSetRoot->GetDocument()->GetNotify();
-  int32_t nPageIdx = -1;
-  CXFA_ContainerLayoutItem* pRootLayoutItem = GetRootLayoutItem();
-  for (; pRootLayoutItem;
-       pRootLayoutItem = static_cast<CXFA_ContainerLayoutItem*>(
-           pRootLayoutItem->m_pNextSibling)) {
-    CXFA_NodeIteratorTemplate<
-        CXFA_ContainerLayoutItem,
-        CXFA_TraverseStrategy_ContentAreaContainerLayoutItem>
-        iteratorParent(pRootLayoutItem);
-    for (CXFA_ContainerLayoutItem* pContainerItem = iteratorParent.GetCurrent();
-         pContainerItem; pContainerItem = iteratorParent.MoveToNext()) {
-      switch (pContainerItem->m_pFormNode->GetElementType()) {
-        case XFA_Element::PageArea: {
-          nPageIdx++;
-          uint32_t dwRelevant =
-              XFA_WidgetStatus_Viewable | XFA_WidgetStatus_Printable;
-          CXFA_NodeIteratorTemplate<CXFA_LayoutItem,
-                                    CXFA_TraverseStrategy_LayoutItem>
-              iterator(pContainerItem);
-          CXFA_LayoutItem* pChildLayoutItem = iterator.GetCurrent();
-          while (pChildLayoutItem) {
-            CXFA_ContentLayoutItem* pContentItem =
-                pChildLayoutItem->AsContentLayoutItem();
-            if (!pContentItem) {
-              pChildLayoutItem = iterator.MoveToNext();
-              continue;
-            }
-
-            XFA_AttributeEnum presence =
-                pContentItem->m_pFormNode->JSObject()
-                    ->TryEnum(XFA_Attribute::Presence, true)
-                    .value_or(XFA_AttributeEnum::Visible);
-            bool bVisible = presence == XFA_AttributeEnum::Visible;
-            uint32_t dwRelevantChild =
-                GetRelevant(pContentItem->m_pFormNode, dwRelevant);
-            SyncContainer(pNotify, m_pLayoutProcessor, pContentItem,
-                          dwRelevantChild, bVisible, nPageIdx);
-            pChildLayoutItem = iterator.SkipChildrenAndMoveToNext();
-          }
-          break;
-        }
-        default:
-          break;
-      }
-    }
-  }
-
-  int32_t nPage = pdfium::CollectionSize<int32_t>(m_PageArray);
-  for (int32_t i = nPage - 1; i >= m_nAvailPages; i--) {
-    CXFA_ContainerLayoutItem* pPage = m_PageArray[i];
-    m_PageArray.erase(m_PageArray.begin() + i);
-    pNotify->OnPageEvent(pPage, XFA_PAGEVIEWEVENT_PostRemoved);
-    delete pPage;
-  }
-  ClearData();
-}
-
-void XFA_ReleaseLayoutItem_NoPageArea(CXFA_LayoutItem* pLayoutItem) {
-  CXFA_LayoutItem *pNext, *pNode = pLayoutItem->m_pFirstChild;
-  while (pNode) {
-    pNext = pNode->m_pNextSibling;
-    pNode->m_pParent = nullptr;
-    XFA_ReleaseLayoutItem_NoPageArea(pNode);
-    pNode = pNext;
-  }
-  if (pLayoutItem->m_pFormNode->GetElementType() != XFA_Element::PageArea)
-    delete pLayoutItem;
-}
-
-void CXFA_LayoutPageMgr::PrepareLayout() {
-  m_pPageSetCurRoot = nullptr;
-  m_ePageSetMode = XFA_AttributeEnum::OrderedOccurrence;
-  m_nAvailPages = 0;
-  ClearData();
-  if (!m_pPageSetLayoutItemRoot)
-    return;
-
-  CXFA_ContainerLayoutItem* pRootLayoutItem = m_pPageSetLayoutItemRoot;
-  if (pRootLayoutItem &&
-      pRootLayoutItem->m_pFormNode->GetPacketType() == XFA_PacketType::Form) {
-    CXFA_Node* pPageSetFormNode = pRootLayoutItem->m_pFormNode;
-    pRootLayoutItem->m_pFormNode->GetDocument()->m_pPendingPageSet.clear();
-    if (pPageSetFormNode->HasRemovedChildren()) {
-      XFA_ReleaseLayoutItem(pRootLayoutItem);
-      m_pPageSetLayoutItemRoot = nullptr;
-      pRootLayoutItem = nullptr;
-      pPageSetFormNode = nullptr;
-      m_PageArray.clear();
-    }
-    while (pPageSetFormNode) {
-      CXFA_Node* pNextPageSet =
-          pPageSetFormNode->GetNextSameClassSibling<CXFA_PageSet>(
-              XFA_Element::PageSet);
-      pPageSetFormNode->GetParent()->RemoveChild(pPageSetFormNode, false);
-      pRootLayoutItem->m_pFormNode->GetDocument()->m_pPendingPageSet.push_back(
-          pPageSetFormNode);
-      pPageSetFormNode = pNextPageSet;
-    }
-  }
-  pRootLayoutItem = m_pPageSetLayoutItemRoot;
-  CXFA_ContainerLayoutItem* pNextLayout = nullptr;
-  for (; pRootLayoutItem; pRootLayoutItem = pNextLayout) {
-    pNextLayout =
-        static_cast<CXFA_ContainerLayoutItem*>(pRootLayoutItem->m_pNextSibling);
-    SaveLayoutItem(pRootLayoutItem);
-    delete pRootLayoutItem;
-  }
-  m_pPageSetLayoutItemRoot = nullptr;
-}
diff --git a/xfa/fxfa/parser/cxfa_layoutpagemgr.h b/xfa/fxfa/parser/cxfa_layoutpagemgr.h
deleted file mode 100644
index 42fa4e6..0000000
--- a/xfa/fxfa/parser/cxfa_layoutpagemgr.h
+++ /dev/null
@@ -1,147 +0,0 @@
-// Copyright 2014 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_LAYOUTPAGEMGR_H_
-#define XFA_FXFA_PARSER_CXFA_LAYOUTPAGEMGR_H_
-
-#include <iterator>
-#include <list>
-#include <map>
-#include <vector>
-
-#include "xfa/fxfa/parser/cxfa_itemlayoutprocessor.h"
-
-class CXFA_ContainerRecord;
-class CXFA_LayoutItem;
-class CXFA_Node;
-
-class CXFA_LayoutPageMgr {
- public:
-  explicit CXFA_LayoutPageMgr(CXFA_LayoutProcessor* pLayoutProcessor);
-  ~CXFA_LayoutPageMgr();
-
-  bool InitLayoutPage(CXFA_Node* pFormNode);
-  bool PrepareFirstPage(CXFA_Node* pRootSubform);
-  float GetAvailHeight();
-  bool GetNextAvailContentHeight(float fChildHeight);
-  void SubmitContentItem(CXFA_ContentLayoutItem* pContentLayoutItem,
-                         XFA_ItemLayoutProcessorResult eStatus);
-  void FinishPaginatedPageSets();
-  void SyncLayoutData();
-  int32_t GetPageCount() const;
-  CXFA_ContainerLayoutItem* GetPage(int32_t index) const;
-  int32_t GetPageIndex(const CXFA_ContainerLayoutItem* pPage) const;
-  inline CXFA_ContainerLayoutItem* GetRootLayoutItem() const {
-    return m_pPageSetLayoutItemRoot;
-  }
-  bool ProcessBreakBeforeOrAfter(CXFA_Node* pBreakNode,
-                                 bool bBefore,
-                                 CXFA_Node*& pBreakLeaderNode,
-                                 CXFA_Node*& pBreakTrailerNode,
-                                 bool& bCreatePage);
-  bool ProcessOverflow(CXFA_Node* pFormNode,
-                       CXFA_Node*& pLeaderNode,
-                       CXFA_Node*& pTrailerNode,
-                       bool bDataMerge = false,
-                       bool bCreatePage = true);
-  CXFA_Node* QueryOverflow(CXFA_Node* pFormNode);
-  bool ProcessBookendLeaderOrTrailer(CXFA_Node* pBookendNode,
-                                     bool bLeader,
-                                     CXFA_Node*& pBookendAppendNode);
-
- private:
-  bool AppendNewPage(bool bFirstTemPage = false);
-  void ReorderPendingLayoutRecordToTail(CXFA_ContainerRecord* pNewRecord,
-                                        CXFA_ContainerRecord* pPrevRecord);
-  void RemoveLayoutRecord(CXFA_ContainerRecord* pNewRecord,
-                          CXFA_ContainerRecord* pPrevRecord);
-  CXFA_ContainerRecord* GetCurrentContainerRecord() {
-    return *m_CurrentContainerRecordIter;
-  }
-  std::list<CXFA_ContainerRecord*>::iterator GetTailPosition() {
-    auto iter = m_ProposedContainerRecords.end();
-    return !m_ProposedContainerRecords.empty() ? std::prev(iter) : iter;
-  }
-  CXFA_ContainerRecord* CreateContainerRecord(CXFA_Node* pPageNode = nullptr,
-                                              bool bCreateNew = false);
-  void AddPageAreaLayoutItem(CXFA_ContainerRecord* pNewRecord,
-                             CXFA_Node* pNewPageArea);
-  void AddContentAreaLayoutItem(CXFA_ContainerRecord* pNewRecord,
-                                CXFA_Node* pContentArea);
-  bool RunBreak(XFA_Element eBreakType,
-                XFA_AttributeEnum eTargetType,
-                CXFA_Node* pTarget,
-                bool bStartNew);
-  CXFA_Node* BreakOverflow(CXFA_Node* pOverflowNode,
-                           CXFA_Node*& pLeaderTemplate,
-                           CXFA_Node*& pTrailerTemplate,
-                           bool bCreatePage = true);
-  bool ResolveBookendLeaderOrTrailer(CXFA_Node* pBookendNode,
-                                     bool bLeader,
-                                     CXFA_Node*& pBookendAppendTemplate);
-  bool ExecuteBreakBeforeOrAfter(CXFA_Node* pCurNode,
-                                 bool bBefore,
-                                 CXFA_Node*& pBreakLeaderTemplate,
-                                 CXFA_Node*& pBreakTrailerTemplate);
-
-  int32_t CreateMinPageRecord(CXFA_Node* pPageArea,
-                              bool bTargetPageArea,
-                              bool bCreateLast = false);
-  void CreateMinPageSetRecord(CXFA_Node* pPageSet, bool bCreateAll = false);
-  void CreateNextMinRecord(CXFA_Node* pRecordNode);
-  bool FindPageAreaFromPageSet(CXFA_Node* pPageSet,
-                               CXFA_Node* pStartChild,
-                               CXFA_Node* pTargetPageArea = nullptr,
-                               CXFA_Node* pTargetContentArea = nullptr,
-                               bool bNewPage = false,
-                               bool bQuery = false);
-  bool FindPageAreaFromPageSet_Ordered(CXFA_Node* pPageSet,
-                                       CXFA_Node* pStartChild,
-                                       CXFA_Node* pTargetPageArea = nullptr,
-                                       CXFA_Node* pTargetContentArea = nullptr,
-                                       bool bNewPage = false,
-                                       bool bQuery = false);
-  bool FindPageAreaFromPageSet_SimplexDuplex(
-      CXFA_Node* pPageSet,
-      CXFA_Node* pStartChild,
-      CXFA_Node* pTargetPageArea = nullptr,
-      CXFA_Node* pTargetContentArea = nullptr,
-      bool bNewPage = false,
-      bool bQuery = false,
-      XFA_AttributeEnum ePreferredPosition = XFA_AttributeEnum::First);
-  bool MatchPageAreaOddOrEven(CXFA_Node* pPageArea);
-  CXFA_Node* GetNextAvailPageArea(CXFA_Node* pTargetPageArea,
-                                  CXFA_Node* pTargetContentArea = nullptr,
-                                  bool bNewPage = false,
-                                  bool bQuery = false);
-  bool GetNextContentArea(CXFA_Node* pTargetContentArea);
-  void InitPageSetMap();
-  void ProcessLastPageSet();
-  bool IsPageSetRootOrderedOccurrence() const {
-    return m_ePageSetMode == XFA_AttributeEnum::OrderedOccurrence;
-  }
-  void ClearData();
-  void MergePageSetContents();
-  void LayoutPageSetContents();
-  void PrepareLayout();
-  void SaveLayoutItem(CXFA_LayoutItem* pParentLayoutItem);
-
-  CXFA_LayoutProcessor* m_pLayoutProcessor;
-  CXFA_Node* m_pTemplatePageSetRoot;
-  CXFA_ContainerLayoutItem* m_pPageSetLayoutItemRoot;
-  CXFA_ContainerLayoutItem* m_pPageSetCurRoot;
-  std::list<CXFA_ContainerRecord*> m_ProposedContainerRecords;
-  std::list<CXFA_ContainerRecord*>::iterator m_CurrentContainerRecordIter;
-  CXFA_Node* m_pCurPageArea;
-  int32_t m_nAvailPages;
-  int32_t m_nCurPageCount;
-  XFA_AttributeEnum m_ePageSetMode;
-  bool m_bCreateOverFlowPage;
-  std::map<CXFA_Node*, int32_t> m_pPageSetMap;
-  std::vector<CXFA_ContainerLayoutItem*> m_PageArray;
-};
-
-#endif  // XFA_FXFA_PARSER_CXFA_LAYOUTPAGEMGR_H_
diff --git a/xfa/fxfa/parser/cxfa_layoutprocessor.cpp b/xfa/fxfa/parser/cxfa_layoutprocessor.cpp
deleted file mode 100644
index 540e1c91..0000000
--- a/xfa/fxfa/parser/cxfa_layoutprocessor.cpp
+++ /dev/null
@@ -1,140 +0,0 @@
-// Copyright 2016 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
-
-#include "xfa/fxfa/parser/cxfa_layoutprocessor.h"
-
-#include "fxjs/xfa/cjx_object.h"
-#include "third_party/base/ptr_util.h"
-#include "third_party/base/stl_util.h"
-#include "xfa/fxfa/parser/cxfa_contentlayoutitem.h"
-#include "xfa/fxfa/parser/cxfa_document.h"
-#include "xfa/fxfa/parser/cxfa_itemlayoutprocessor.h"
-#include "xfa/fxfa/parser/cxfa_layoutpagemgr.h"
-#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_subform.h"
-#include "xfa/fxfa/parser/xfa_document_datamerger_imp.h"
-#include "xfa/fxfa/parser/xfa_utils.h"
-
-CXFA_LayoutProcessor::CXFA_LayoutProcessor(CXFA_Document* pDocument)
-    : m_pDocument(pDocument), m_nProgressCounter(0), m_bNeedLayout(true) {}
-
-CXFA_LayoutProcessor::~CXFA_LayoutProcessor() {}
-
-CXFA_Document* CXFA_LayoutProcessor::GetDocument() const {
-  return m_pDocument.Get();
-}
-
-int32_t CXFA_LayoutProcessor::StartLayout(bool bForceRestart) {
-  if (!bForceRestart && !IsNeedLayout())
-    return 100;
-
-  m_pRootItemLayoutProcessor.reset();
-  m_nProgressCounter = 0;
-  CXFA_Node* pFormPacketNode =
-      ToNode(m_pDocument->GetXFAObject(XFA_HASHCODE_Form));
-  if (!pFormPacketNode)
-    return -1;
-
-  CXFA_Subform* pFormRoot =
-      pFormPacketNode->GetFirstChildByClass<CXFA_Subform>(XFA_Element::Subform);
-  if (!pFormRoot)
-    return -1;
-
-  if (!m_pLayoutPageMgr)
-    m_pLayoutPageMgr = pdfium::MakeUnique<CXFA_LayoutPageMgr>(this);
-  if (!m_pLayoutPageMgr->InitLayoutPage(pFormRoot))
-    return -1;
-
-  if (!m_pLayoutPageMgr->PrepareFirstPage(pFormRoot))
-    return -1;
-
-  m_pRootItemLayoutProcessor = pdfium::MakeUnique<CXFA_ItemLayoutProcessor>(
-      pFormRoot, m_pLayoutPageMgr.get());
-  m_nProgressCounter = 1;
-  return 0;
-}
-
-int32_t CXFA_LayoutProcessor::DoLayout() {
-  if (m_nProgressCounter < 1)
-    return -1;
-
-  XFA_ItemLayoutProcessorResult eStatus;
-  CXFA_Node* pFormNode = m_pRootItemLayoutProcessor->GetFormNode();
-  float fPosX =
-      pFormNode->JSObject()->GetMeasure(XFA_Attribute::X).ToUnit(XFA_Unit::Pt);
-  float fPosY =
-      pFormNode->JSObject()->GetMeasure(XFA_Attribute::Y).ToUnit(XFA_Unit::Pt);
-  do {
-    float fAvailHeight = m_pLayoutPageMgr->GetAvailHeight();
-    eStatus = m_pRootItemLayoutProcessor->DoLayout(true, fAvailHeight,
-                                                   fAvailHeight, nullptr);
-    if (eStatus != XFA_ItemLayoutProcessorResult::Done)
-      m_nProgressCounter++;
-
-    CXFA_ContentLayoutItem* pLayoutItem =
-        m_pRootItemLayoutProcessor->ExtractLayoutItem();
-    if (pLayoutItem)
-      pLayoutItem->m_sPos = CFX_PointF(fPosX, fPosY);
-
-    m_pLayoutPageMgr->SubmitContentItem(pLayoutItem, eStatus);
-  } while (eStatus != XFA_ItemLayoutProcessorResult::Done);
-
-  if (eStatus == XFA_ItemLayoutProcessorResult::Done) {
-    m_pLayoutPageMgr->FinishPaginatedPageSets();
-    m_pLayoutPageMgr->SyncLayoutData();
-    m_bNeedLayout = false;
-    m_rgChangedContainers.clear();
-  }
-  return 100 * (eStatus == XFA_ItemLayoutProcessorResult::Done
-                    ? m_nProgressCounter
-                    : m_nProgressCounter - 1) /
-         m_nProgressCounter;
-}
-
-bool CXFA_LayoutProcessor::IncrementLayout() {
-  if (m_bNeedLayout) {
-    StartLayout(true);
-    return DoLayout() == 100;
-  }
-  for (CXFA_Node* pNode : m_rgChangedContainers) {
-    CXFA_Node* pParentNode = pNode->GetContainerParent();
-    if (!pParentNode)
-      return false;
-    if (!CXFA_ItemLayoutProcessor::IncrementRelayoutNode(this, pNode,
-                                                         pParentNode)) {
-      return false;
-    }
-  }
-  m_rgChangedContainers.clear();
-  return true;
-}
-
-int32_t CXFA_LayoutProcessor::CountPages() const {
-  return m_pLayoutPageMgr ? m_pLayoutPageMgr->GetPageCount() : 0;
-}
-
-CXFA_ContainerLayoutItem* CXFA_LayoutProcessor::GetPage(int32_t index) const {
-  return m_pLayoutPageMgr ? m_pLayoutPageMgr->GetPage(index) : nullptr;
-}
-
-CXFA_LayoutItem* CXFA_LayoutProcessor::GetLayoutItem(CXFA_Node* pFormItem) {
-  return pFormItem->JSObject()->GetLayoutItem();
-}
-
-void CXFA_LayoutProcessor::AddChangedContainer(CXFA_Node* pContainer) {
-  if (!pdfium::ContainsValue(m_rgChangedContainers, pContainer))
-    m_rgChangedContainers.push_back(pContainer);
-}
-
-CXFA_ContainerLayoutItem* CXFA_LayoutProcessor::GetRootLayoutItem() const {
-  return m_pLayoutPageMgr ? m_pLayoutPageMgr->GetRootLayoutItem() : nullptr;
-}
-
-bool CXFA_LayoutProcessor::IsNeedLayout() {
-  return m_bNeedLayout || !m_rgChangedContainers.empty();
-}
diff --git a/xfa/fxfa/parser/cxfa_layoutprocessor.h b/xfa/fxfa/parser/cxfa_layoutprocessor.h
deleted file mode 100644
index e8391be..0000000
--- a/xfa/fxfa/parser/cxfa_layoutprocessor.h
+++ /dev/null
@@ -1,56 +0,0 @@
-// Copyright 2016 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_LAYOUTPROCESSOR_H_
-#define XFA_FXFA_PARSER_CXFA_LAYOUTPROCESSOR_H_
-
-#include <memory>
-#include <vector>
-
-#include "core/fxcrt/fx_system.h"
-#include "core/fxcrt/unowned_ptr.h"
-
-class CXFA_ContainerLayoutItem;
-class CXFA_Document;
-class CXFA_ItemLayoutProcessor;
-class CXFA_LayoutItem;
-class CXFA_LayoutPageMgr;
-class CXFA_Node;
-
-class CXFA_LayoutProcessor {
- public:
-  explicit CXFA_LayoutProcessor(CXFA_Document* pDocument);
-  ~CXFA_LayoutProcessor();
-
-  CXFA_Document* GetDocument() const;
-  int32_t StartLayout(bool bForceRestart = false);
-  int32_t DoLayout();
-  bool IncrementLayout();
-  int32_t CountPages() const;
-  CXFA_ContainerLayoutItem* GetPage(int32_t index) const;
-  CXFA_LayoutItem* GetLayoutItem(CXFA_Node* pFormItem);
-  void AddChangedContainer(CXFA_Node* pContainer);
-  void SetForceReLayout(bool bForceRestart) { m_bNeedLayout = bForceRestart; }
-  CXFA_ContainerLayoutItem* GetRootLayoutItem() const;
-  CXFA_ItemLayoutProcessor* GetRootRootItemLayoutProcessor() const {
-    return m_pRootItemLayoutProcessor.get();
-  }
-  CXFA_LayoutPageMgr* GetLayoutPageMgr() const {
-    return m_pLayoutPageMgr.get();
-  }
-
- private:
-  bool IsNeedLayout();
-
-  UnownedPtr<CXFA_Document> const m_pDocument;
-  std::unique_ptr<CXFA_ItemLayoutProcessor> m_pRootItemLayoutProcessor;
-  std::unique_ptr<CXFA_LayoutPageMgr> m_pLayoutPageMgr;
-  std::vector<CXFA_Node*> m_rgChangedContainers;
-  uint32_t m_nProgressCounter;
-  bool m_bNeedLayout;
-};
-
-#endif  // XFA_FXFA_PARSER_CXFA_LAYOUTPROCESSOR_H_
diff --git a/xfa/fxfa/parser/cxfa_level.cpp b/xfa/fxfa/parser/cxfa_level.cpp
index 7343805..b738081 100644
--- a/xfa/fxfa/parser/cxfa_level.cpp
+++ b/xfa/fxfa/parser/cxfa_level.cpp
@@ -6,14 +6,15 @@
 
 #include "xfa/fxfa/parser/cxfa_level.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kLevelAttributeData[] = {
     {XFA_Attribute::Desc, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Lock, XFA_AttributeType::Integer, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"level";
+};
 
 }  // namespace
 
@@ -23,8 +24,8 @@
                 XFA_XDPPACKET_Config,
                 XFA_ObjectType::ContentNode,
                 XFA_Element::Level,
-                nullptr,
-                kAttributeData,
-                kName) {}
+                {},
+                kLevelAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_Level::~CXFA_Level() {}
+CXFA_Level::~CXFA_Level() = default;
diff --git a/xfa/fxfa/parser/cxfa_level.h b/xfa/fxfa/parser/cxfa_level.h
index abdd048..8cc03dc 100644
--- a/xfa/fxfa/parser/cxfa_level.h
+++ b/xfa/fxfa/parser/cxfa_level.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Level : public CXFA_Node {
+class CXFA_Level final : public CXFA_Node {
  public:
   CXFA_Level(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Level() override;
diff --git a/xfa/fxfa/parser/cxfa_line.cpp b/xfa/fxfa/parser/cxfa_line.cpp
index 4e656c2..2ac97b2 100644
--- a/xfa/fxfa/parser/cxfa_line.cpp
+++ b/xfa/fxfa/parser/cxfa_line.cpp
@@ -6,26 +6,26 @@
 
 #include "xfa/fxfa/parser/cxfa_line.h"
 
-#include "fxjs/xfa/cjx_line.h"
+#include "fxjs/xfa/cjx_node.h"
 #include "third_party/base/ptr_util.h"
 #include "xfa/fxfa/parser/cxfa_edge.h"
 #include "xfa/fxfa/parser/cxfa_node.h"
 
 namespace {
 
-const CXFA_Node::PropertyData kPropertyData[] = {{XFA_Element::Edge, 1, 0},
-                                                 {XFA_Element::Unknown, 0, 0}};
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::PropertyData kLinePropertyData[] = {
+    {XFA_Element::Edge, 1, 0},
+};
+
+const CXFA_Node::AttributeData kLineAttributeData[] = {
     {XFA_Attribute::Id, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Use, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Slope, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::Backslash},
+     (void*)XFA_AttributeValue::Backslash},
     {XFA_Attribute::Usehref, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Hand, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::Even},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"line";
+     (void*)XFA_AttributeValue::Even},
+};
 
 }  // namespace
 
@@ -35,19 +35,18 @@
                 (XFA_XDPPACKET_Template | XFA_XDPPACKET_Form),
                 XFA_ObjectType::Node,
                 XFA_Element::Line,
-                kPropertyData,
-                kAttributeData,
-                kName,
-                pdfium::MakeUnique<CJX_Line>(this)) {}
+                kLinePropertyData,
+                kLineAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_Line::~CXFA_Line() {}
+CXFA_Line::~CXFA_Line() = default;
 
-XFA_AttributeEnum CXFA_Line::GetHand() {
+XFA_AttributeValue CXFA_Line::GetHand() {
   return JSObject()->GetEnum(XFA_Attribute::Hand);
 }
 
 bool CXFA_Line::GetSlope() {
-  return JSObject()->GetEnum(XFA_Attribute::Slope) == XFA_AttributeEnum::Slash;
+  return JSObject()->GetEnum(XFA_Attribute::Slope) == XFA_AttributeValue::Slash;
 }
 
 CXFA_Edge* CXFA_Line::GetEdgeIfExists() {
diff --git a/xfa/fxfa/parser/cxfa_line.h b/xfa/fxfa/parser/cxfa_line.h
index 18faacd..53584fa 100644
--- a/xfa/fxfa/parser/cxfa_line.h
+++ b/xfa/fxfa/parser/cxfa_line.h
@@ -11,12 +11,12 @@
 
 class CXFA_Edge;
 
-class CXFA_Line : public CXFA_Node {
+class CXFA_Line final : public CXFA_Node {
  public:
   CXFA_Line(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Line() override;
 
-  XFA_AttributeEnum GetHand();
+  XFA_AttributeValue GetHand();
   bool GetSlope();
   CXFA_Edge* GetEdgeIfExists();
 };
diff --git a/xfa/fxfa/parser/cxfa_linear.cpp b/xfa/fxfa/parser/cxfa_linear.cpp
index 8506d24..b482d27 100644
--- a/xfa/fxfa/parser/cxfa_linear.cpp
+++ b/xfa/fxfa/parser/cxfa_linear.cpp
@@ -6,25 +6,26 @@
 
 #include "xfa/fxfa/parser/cxfa_linear.h"
 
-#include "fxjs/xfa/cjx_linear.h"
+#include "core/fxge/render_defines.h"
+#include "fxjs/xfa/cjx_node.h"
 #include "third_party/base/ptr_util.h"
 #include "xfa/fxfa/parser/cxfa_color.h"
 #include "xfa/fxgraphics/cxfa_geshading.h"
 
 namespace {
 
-const CXFA_Node::PropertyData kPropertyData[] = {{XFA_Element::Color, 1, 0},
-                                                 {XFA_Element::Extras, 1, 0},
-                                                 {XFA_Element::Unknown, 0, 0}};
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::PropertyData kLinearPropertyData[] = {
+    {XFA_Element::Color, 1, 0},
+    {XFA_Element::Extras, 1, 0},
+};
+
+const CXFA_Node::AttributeData kLinearAttributeData[] = {
     {XFA_Attribute::Id, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Use, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Type, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::ToRight},
+     (void*)XFA_AttributeValue::ToRight},
     {XFA_Attribute::Usehref, XFA_AttributeType::CData, nullptr},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"linear";
+};
 
 }  // namespace
 
@@ -34,17 +35,16 @@
                 (XFA_XDPPACKET_Template | XFA_XDPPACKET_Form),
                 XFA_ObjectType::Node,
                 XFA_Element::Linear,
-                kPropertyData,
-                kAttributeData,
-                kName,
-                pdfium::MakeUnique<CJX_Linear>(this)) {}
+                kLinearPropertyData,
+                kLinearAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_Linear::~CXFA_Linear() {}
+CXFA_Linear::~CXFA_Linear() = default;
 
-XFA_AttributeEnum CXFA_Linear::GetType() {
+XFA_AttributeValue CXFA_Linear::GetType() {
   return JSObject()
       ->TryEnum(XFA_Attribute::Type, true)
-      .value_or(XFA_AttributeEnum::ToRight);
+      .value_or(XFA_AttributeValue::ToRight);
 }
 
 CXFA_Color* CXFA_Linear::GetColorIfExists() {
@@ -62,19 +62,19 @@
   CFX_PointF ptStart;
   CFX_PointF ptEnd;
   switch (GetType()) {
-    case XFA_AttributeEnum::ToRight:
+    case XFA_AttributeValue::ToRight:
       ptStart = CFX_PointF(rtFill.left, rtFill.top);
       ptEnd = CFX_PointF(rtFill.right(), rtFill.top);
       break;
-    case XFA_AttributeEnum::ToBottom:
+    case XFA_AttributeValue::ToBottom:
       ptStart = CFX_PointF(rtFill.left, rtFill.top);
       ptEnd = CFX_PointF(rtFill.left, rtFill.bottom());
       break;
-    case XFA_AttributeEnum::ToLeft:
+    case XFA_AttributeValue::ToLeft:
       ptStart = CFX_PointF(rtFill.right(), rtFill.top);
       ptEnd = CFX_PointF(rtFill.left, rtFill.top);
       break;
-    case XFA_AttributeEnum::ToTop:
+    case XFA_AttributeValue::ToTop:
       ptStart = CFX_PointF(rtFill.left, rtFill.bottom());
       ptEnd = CFX_PointF(rtFill.left, rtFill.top);
       break;
diff --git a/xfa/fxfa/parser/cxfa_linear.h b/xfa/fxfa/parser/cxfa_linear.h
index bb55f80..0fa5e1a 100644
--- a/xfa/fxfa/parser/cxfa_linear.h
+++ b/xfa/fxfa/parser/cxfa_linear.h
@@ -14,9 +14,10 @@
 class CXFA_Color;
 class CXFA_Graphics;
 
-class CXFA_Linear : public CXFA_Node {
+class CXFA_Linear final : public CXFA_Node {
  public:
-  static constexpr XFA_AttributeEnum kDefaultType = XFA_AttributeEnum::ToRight;
+  static constexpr XFA_AttributeValue kDefaultType =
+      XFA_AttributeValue::ToRight;
 
   CXFA_Linear(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Linear() override;
@@ -28,7 +29,7 @@
             const CFX_Matrix& matrix);
 
  private:
-  XFA_AttributeEnum GetType();
+  XFA_AttributeValue GetType();
   CXFA_Color* GetColorIfExists();
 };
 
diff --git a/xfa/fxfa/parser/cxfa_linearized.cpp b/xfa/fxfa/parser/cxfa_linearized.cpp
index 0ae6b8d..6c2ffe1 100644
--- a/xfa/fxfa/parser/cxfa_linearized.cpp
+++ b/xfa/fxfa/parser/cxfa_linearized.cpp
@@ -6,14 +6,15 @@
 
 #include "xfa/fxfa/parser/cxfa_linearized.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kLinearizedAttributeData[] = {
     {XFA_Attribute::Desc, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Lock, XFA_AttributeType::Integer, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"linearized";
+};
 
 }  // namespace
 
@@ -23,8 +24,8 @@
                 XFA_XDPPACKET_Config,
                 XFA_ObjectType::ContentNode,
                 XFA_Element::Linearized,
-                nullptr,
-                kAttributeData,
-                kName) {}
+                {},
+                kLinearizedAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_Linearized::~CXFA_Linearized() {}
+CXFA_Linearized::~CXFA_Linearized() = default;
diff --git a/xfa/fxfa/parser/cxfa_linearized.h b/xfa/fxfa/parser/cxfa_linearized.h
index df7846e..d2fe2d7 100644
--- a/xfa/fxfa/parser/cxfa_linearized.h
+++ b/xfa/fxfa/parser/cxfa_linearized.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Linearized : public CXFA_Node {
+class CXFA_Linearized final : public CXFA_Node {
  public:
   CXFA_Linearized(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Linearized() override;
diff --git a/xfa/fxfa/parser/cxfa_list.cpp b/xfa/fxfa/parser/cxfa_list.cpp
index 6f5fc29..6329cec 100644
--- a/xfa/fxfa/parser/cxfa_list.cpp
+++ b/xfa/fxfa/parser/cxfa_list.cpp
@@ -9,7 +9,7 @@
 #include <utility>
 
 #include "core/fxcrt/fx_extension.h"
-#include "fxjs/cfxjse_engine.h"
+#include "fxjs/xfa/cfxjse_engine.h"
 #include "fxjs/xfa/cjx_treelist.h"
 #include "xfa/fxfa/parser/cxfa_document.h"
 #include "xfa/fxfa/parser/cxfa_node.h"
@@ -18,15 +18,13 @@
     : CXFA_List(pDocument,
                 XFA_ObjectType::List,
                 XFA_Element::List,
-                WideStringView(L"list"),
                 std::move(obj)) {}
 
 CXFA_List::CXFA_List(CXFA_Document* pDocument,
                      XFA_ObjectType objectType,
                      XFA_Element eType,
-                     const WideStringView& elementName,
                      std::unique_ptr<CJX_Object> obj)
-    : CXFA_Object(pDocument, objectType, eType, elementName, std::move(obj)) {
+    : CXFA_Object(pDocument, objectType, eType, std::move(obj)) {
   m_pDocument->GetScriptContext()->AddToCacheList(
       std::unique_ptr<CXFA_List>(this));
 }
diff --git a/xfa/fxfa/parser/cxfa_list.h b/xfa/fxfa/parser/cxfa_list.h
index de9406d..c114801 100644
--- a/xfa/fxfa/parser/cxfa_list.h
+++ b/xfa/fxfa/parser/cxfa_list.h
@@ -18,9 +18,9 @@
   ~CXFA_List() override;
 
   virtual size_t GetLength() = 0;
-  virtual bool Append(CXFA_Node* pNode) = 0;
+  virtual void Append(CXFA_Node* pNode) = 0;
   virtual bool Insert(CXFA_Node* pNewNode, CXFA_Node* pBeforeNode) = 0;
-  virtual bool Remove(CXFA_Node* pNode) = 0;
+  virtual void Remove(CXFA_Node* pNode) = 0;
   virtual CXFA_Node* Item(size_t iIndex) = 0;
 
  protected:
@@ -28,7 +28,6 @@
   CXFA_List(CXFA_Document* pDocument,
             XFA_ObjectType objectType,
             XFA_Element eType,
-            const WideStringView& elementName,
             std::unique_ptr<CJX_Object> obj);
 };
 
diff --git a/xfa/fxfa/parser/cxfa_locale.cpp b/xfa/fxfa/parser/cxfa_locale.cpp
index c601139..6c54fb8 100644
--- a/xfa/fxfa/parser/cxfa_locale.cpp
+++ b/xfa/fxfa/parser/cxfa_locale.cpp
@@ -6,21 +6,23 @@
 
 #include "xfa/fxfa/parser/cxfa_locale.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::PropertyData kPropertyData[] = {
+const CXFA_Node::PropertyData kLocalePropertyData[] = {
     {XFA_Element::DatePatterns, 1, 0},    {XFA_Element::CalendarSymbols, 1, 0},
     {XFA_Element::CurrencySymbols, 1, 0}, {XFA_Element::Typefaces, 1, 0},
     {XFA_Element::DateTimeSymbols, 1, 0}, {XFA_Element::NumberPatterns, 1, 0},
     {XFA_Element::NumberSymbols, 1, 0},   {XFA_Element::TimePatterns, 1, 0},
-    {XFA_Element::Unknown, 0, 0}};
-const CXFA_Node::AttributeData kAttributeData[] = {
+};
+
+const CXFA_Node::AttributeData kLocaleAttributeData[] = {
     {XFA_Attribute::Name, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Desc, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Lock, XFA_AttributeType::Integer, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"locale";
+};
 
 }  // namespace
 
@@ -30,8 +32,8 @@
                 (XFA_XDPPACKET_Config | XFA_XDPPACKET_LocaleSet),
                 XFA_ObjectType::Node,
                 XFA_Element::Locale,
-                kPropertyData,
-                kAttributeData,
-                kName) {}
+                kLocalePropertyData,
+                kLocaleAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_Locale::~CXFA_Locale() {}
+CXFA_Locale::~CXFA_Locale() = default;
diff --git a/xfa/fxfa/parser/cxfa_locale.h b/xfa/fxfa/parser/cxfa_locale.h
index 3a7e83d..67bee33 100644
--- a/xfa/fxfa/parser/cxfa_locale.h
+++ b/xfa/fxfa/parser/cxfa_locale.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Locale : public CXFA_Node {
+class CXFA_Locale final : public CXFA_Node {
  public:
   CXFA_Locale(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Locale() override;
diff --git a/xfa/fxfa/parser/cxfa_localemgr.cpp b/xfa/fxfa/parser/cxfa_localemgr.cpp
index bb769b6..b6c65a6 100644
--- a/xfa/fxfa/parser/cxfa_localemgr.cpp
+++ b/xfa/fxfa/parser/cxfa_localemgr.cpp
@@ -11,10 +11,8 @@
 #include <memory>
 #include <utility>
 
-#include "core/fpdfapi/cpdf_modulemgr.h"
-#include "core/fxcodec/codec/ccodec_flatemodule.h"
-#include "core/fxcodec/fx_codec.h"
-#include "core/fxcrt/xml/cxml_element.h"
+#include "core/fxcodec/flate/flatemodule.h"
+#include "core/fxcrt/fx_memory_wrappers.h"
 #include "fxjs/xfa/cjx_object.h"
 #include "third_party/base/ptr_util.h"
 #include "xfa/fxfa/parser/cxfa_acrobat.h"
@@ -42,6 +40,8 @@
 #define FX_LANG_es_LA 0x080a
 #define FX_LANG_es_ES 0x0c0a
 
+namespace {
+
 // These arrays are the hex encoded XML strings which define the locale.
 // <locale name="en_US" desc="English(America)">
 //   <calendarSymbols name="gregorian">
@@ -1065,26 +1065,22 @@
     0xB3, 0x85, 0xFA, 0x59, 0x2A, 0x7A, 0xFF, 0x3D, 0xC4, 0x3F, 0xDE, 0xCB,
     0x8B, 0xC4};
 
-static std::unique_ptr<IFX_Locale> XFA_GetLocaleFromBuffer(const uint8_t* pBuf,
-                                                           int nBufLen) {
-  if (!pBuf || nBufLen <= 0)
+std::unique_ptr<LocaleIface> GetLocaleFromBuffer(
+    pdfium::span<const uint8_t> src_span) {
+  if (src_span.empty())
     return nullptr;
 
-  uint8_t* pOut = nullptr;
+  std::unique_ptr<uint8_t, FxFreeDeleter> output;
   uint32_t dwSize;
-  CCodec_ModuleMgr* pCodecMgr = CPDF_ModuleMgr::Get()->GetCodecModule();
-  pCodecMgr->GetFlateModule()->FlateOrLZWDecode(false, pBuf, nBufLen, true, 0,
-                                                0, 0, 0, 0, &pOut, &dwSize);
-  if (!pOut)
+  FlateModule::FlateOrLZWDecode(false, src_span, true, 0, 0, 0, 0, 0, &output,
+                                &dwSize);
+  if (!output)
     return nullptr;
 
-  std::unique_ptr<CXML_Element> pLocale = CXML_Element::Parse(pOut, dwSize);
-  FX_Free(pOut);
-  return pLocale ? pdfium::MakeUnique<CXFA_XMLLocale>(std::move(pLocale))
-                 : nullptr;
+  return CXFA_XMLLocale::Create(pdfium::make_span(output.get(), dwSize));
 }
 
-static uint16_t XFA_GetLanguage(WideString wsLanguage) {
+uint16_t GetLanguage(WideString wsLanguage) {
   if (wsLanguage.GetLength() < 2)
     return FX_LANG_en_US;
 
@@ -1127,28 +1123,25 @@
   return FX_LANG_en_US;
 }
 
+}  // namespace
+
 CXFA_LocaleMgr::CXFA_LocaleMgr(CXFA_Node* pLocaleSet, WideString wsDeflcid)
-    : m_dwLocaleFlags(0x00) {
-  m_dwDeflcid = XFA_GetLanguage(wsDeflcid);
-  if (pLocaleSet) {
-    CXFA_Node* pNodeLocale = pLocaleSet->GetFirstChild();
-    while (pNodeLocale) {
-      m_LocaleArray.push_back(pdfium::MakeUnique<CXFA_NodeLocale>(pNodeLocale));
-      pNodeLocale = pNodeLocale->GetNextSibling();
-    }
+    : m_pDefLocale(GetLocaleByName(wsDeflcid)),
+      m_dwDeflcid(GetLanguage(wsDeflcid)) {
+  if (!pLocaleSet)
+    return;
+
+  for (CXFA_Node* pNodeLocale = pLocaleSet->GetFirstChild(); pNodeLocale;
+       pNodeLocale = pNodeLocale->GetNextSibling()) {
+    m_LocaleArray.push_back(pdfium::MakeUnique<CXFA_NodeLocale>(pNodeLocale));
   }
-  m_pDefLocale = GetLocaleByName(wsDeflcid);
 }
 
 CXFA_LocaleMgr::~CXFA_LocaleMgr() {}
 
-uint16_t CXFA_LocaleMgr::GetDefLocaleID() const {
-  return m_dwDeflcid;
-}
-
-IFX_Locale* CXFA_LocaleMgr::GetDefLocale() {
+LocaleIface* CXFA_LocaleMgr::GetDefLocale() {
   if (m_pDefLocale)
-    return m_pDefLocale;
+    return m_pDefLocale.Get();
 
   if (!m_LocaleArray.empty())
     return m_LocaleArray[0].get();
@@ -1156,100 +1149,101 @@
   if (!m_XMLLocaleArray.empty())
     return m_XMLLocaleArray[0].get();
 
-  std::unique_ptr<IFX_Locale> locale(GetLocale(m_dwDeflcid));
+  std::unique_ptr<LocaleIface> locale(GetLocale(m_dwDeflcid));
   m_pDefLocale = locale.get();
   if (locale)
     m_XMLLocaleArray.push_back(std::move(locale));
 
-  return m_pDefLocale;
+  return m_pDefLocale.Get();
 }
 
-std::unique_ptr<IFX_Locale> CXFA_LocaleMgr::GetLocale(uint16_t lcid) {
+std::unique_ptr<LocaleIface> CXFA_LocaleMgr::GetLocale(uint16_t lcid) {
   switch (lcid) {
     case FX_LANG_zh_CN:
-      return XFA_GetLocaleFromBuffer(g_zhCN_Locale, sizeof(g_zhCN_Locale));
+      return GetLocaleFromBuffer(g_zhCN_Locale);
     case FX_LANG_zh_TW:
-      return XFA_GetLocaleFromBuffer(g_zhTW_Locale, sizeof(g_zhTW_Locale));
+      return GetLocaleFromBuffer(g_zhTW_Locale);
     case FX_LANG_zh_HK:
-      return XFA_GetLocaleFromBuffer(g_zhHK_Locale, sizeof(g_zhHK_Locale));
+      return GetLocaleFromBuffer(g_zhHK_Locale);
     case FX_LANG_ja_JP:
-      return XFA_GetLocaleFromBuffer(g_jaJP_Locale, sizeof(g_jaJP_Locale));
+      return GetLocaleFromBuffer(g_jaJP_Locale);
     case FX_LANG_ko_KR:
-      return XFA_GetLocaleFromBuffer(g_koKR_Locale, sizeof(g_koKR_Locale));
+      return GetLocaleFromBuffer(g_koKR_Locale);
     case FX_LANG_en_GB:
-      return XFA_GetLocaleFromBuffer(g_enGB_Locale, sizeof(g_enGB_Locale));
+      return GetLocaleFromBuffer(g_enGB_Locale);
     case FX_LANG_es_LA:
-      return XFA_GetLocaleFromBuffer(g_esLA_Locale, sizeof(g_esLA_Locale));
+      return GetLocaleFromBuffer(g_esLA_Locale);
     case FX_LANG_es_ES:
-      return XFA_GetLocaleFromBuffer(g_esES_Locale, sizeof(g_esES_Locale));
+      return GetLocaleFromBuffer(g_esES_Locale);
     case FX_LANG_de_DE:
-      return XFA_GetLocaleFromBuffer(g_deDE_Loacale, sizeof(g_deDE_Loacale));
+      return GetLocaleFromBuffer(g_deDE_Loacale);
     case FX_LANG_fr_FR:
-      return XFA_GetLocaleFromBuffer(g_frFR_Locale, sizeof(g_frFR_Locale));
+      return GetLocaleFromBuffer(g_frFR_Locale);
     case FX_LANG_it_IT:
-      return XFA_GetLocaleFromBuffer(g_itIT_Locale, sizeof(g_itIT_Locale));
+      return GetLocaleFromBuffer(g_itIT_Locale);
     case FX_LANG_pt_BR:
-      return XFA_GetLocaleFromBuffer(g_ptBR_Locale, sizeof(g_ptBR_Locale));
+      return GetLocaleFromBuffer(g_ptBR_Locale);
     case FX_LANG_nl_NL:
-      return XFA_GetLocaleFromBuffer(g_nlNL_Locale, sizeof(g_nlNL_Locale));
+      return GetLocaleFromBuffer(g_nlNL_Locale);
     case FX_LANG_ru_RU:
-      return XFA_GetLocaleFromBuffer(g_ruRU_Locale, sizeof(g_ruRU_Locale));
+      return GetLocaleFromBuffer(g_ruRU_Locale);
     case FX_LANG_en_US:
     default:
-      return XFA_GetLocaleFromBuffer(g_enUS_Locale, sizeof(g_enUS_Locale));
+      return GetLocaleFromBuffer(g_enUS_Locale);
   }
 }
 
-IFX_Locale* CXFA_LocaleMgr::GetLocaleByName(const WideString& wsLocaleName) {
+LocaleIface* CXFA_LocaleMgr::GetLocaleByName(const WideString& wsLocaleName) {
   for (size_t i = 0; i < m_LocaleArray.size(); i++) {
-    IFX_Locale* pLocale = m_LocaleArray[i].get();
+    LocaleIface* pLocale = m_LocaleArray[i].get();
     if (pLocale->GetName() == wsLocaleName)
       return pLocale;
   }
   if (wsLocaleName.GetLength() < 2)
     return nullptr;
   for (size_t i = 0; i < m_XMLLocaleArray.size(); i++) {
-    IFX_Locale* pLocale = m_XMLLocaleArray[i].get();
+    LocaleIface* pLocale = m_XMLLocaleArray[i].get();
     if (pLocale->GetName() == wsLocaleName)
       return pLocale;
   }
 
-  std::unique_ptr<IFX_Locale> pLocale(GetLocale(XFA_GetLanguage(wsLocaleName)));
-  IFX_Locale* pRetLocale = pLocale.get();
+  std::unique_ptr<LocaleIface> pLocale(GetLocale(GetLanguage(wsLocaleName)));
+  LocaleIface* pRetLocale = pLocale.get();
   if (pLocale)
     m_XMLLocaleArray.push_back(std::move(pLocale));
   return pRetLocale;
 }
 
-void CXFA_LocaleMgr::SetDefLocale(IFX_Locale* pLocale) {
+void CXFA_LocaleMgr::SetDefLocale(LocaleIface* pLocale) {
   m_pDefLocale = pLocale;
 }
 
-WideStringView CXFA_LocaleMgr::GetConfigLocaleName(CXFA_Node* pConfig) {
-  if (!(m_dwLocaleFlags & 0x01)) {
-    m_wsConfigLocale.clear();
-    if (pConfig) {
-      CXFA_Node* pChildfConfig =
-          pConfig->GetFirstChildByClass<CXFA_Acrobat>(XFA_Element::Acrobat);
-      if (!pChildfConfig) {
-        pChildfConfig =
-            pConfig->GetFirstChildByClass<CXFA_Present>(XFA_Element::Present);
-      }
-      CXFA_Common* pCommon =
-          pChildfConfig ? pChildfConfig->GetFirstChildByClass<CXFA_Common>(
-                              XFA_Element::Common)
-                        : nullptr;
-      CXFA_Locale* pLocale =
-          pCommon
-              ? pCommon->GetFirstChildByClass<CXFA_Locale>(XFA_Element::Locale)
-              : nullptr;
-      if (pLocale) {
-        m_wsConfigLocale = pLocale->JSObject()
-                               ->TryCData(XFA_Attribute::Value, false)
-                               .value_or(WideString());
-      }
-    }
-    m_dwLocaleFlags |= 0x01;
+WideString CXFA_LocaleMgr::GetConfigLocaleName(CXFA_Node* pConfig) {
+  if (m_hasSetLocaleName)
+    return m_wsConfigLocale;
+
+  m_hasSetLocaleName = true;
+  m_wsConfigLocale.clear();
+  if (!pConfig)
+    return m_wsConfigLocale;
+
+  CXFA_Node* pChildfConfig =
+      pConfig->GetFirstChildByClass<CXFA_Acrobat>(XFA_Element::Acrobat);
+  if (!pChildfConfig) {
+    pChildfConfig =
+        pConfig->GetFirstChildByClass<CXFA_Present>(XFA_Element::Present);
   }
-  return m_wsConfigLocale.AsStringView();
+  CXFA_Common* pCommon = pChildfConfig
+                             ? pChildfConfig->GetFirstChildByClass<CXFA_Common>(
+                                   XFA_Element::Common)
+                             : nullptr;
+  CXFA_Locale* pLocale =
+      pCommon ? pCommon->GetFirstChildByClass<CXFA_Locale>(XFA_Element::Locale)
+              : nullptr;
+  if (pLocale) {
+    m_wsConfigLocale = pLocale->JSObject()
+                           ->TryCData(XFA_Attribute::Value, false)
+                           .value_or(WideString());
+  }
+  return m_wsConfigLocale;
 }
diff --git a/xfa/fxfa/parser/cxfa_localemgr.h b/xfa/fxfa/parser/cxfa_localemgr.h
index d77a94a..9370988 100644
--- a/xfa/fxfa/parser/cxfa_localemgr.h
+++ b/xfa/fxfa/parser/cxfa_localemgr.h
@@ -10,34 +10,36 @@
 #include <memory>
 #include <vector>
 
-#include "core/fxcrt/cfx_datetime.h"
-#include "core/fxcrt/ifx_locale.h"
-#include "xfa/fxfa/parser/cxfa_localemgr.h"
+#include "core/fxcrt/unowned_ptr.h"
+#include "core/fxcrt/widestring.h"
+#include "xfa/fgas/crt/locale_mgr_iface.h"
 
 class CXFA_Node;
-class IFX_Locale;
+class LocaleIface;
 
-class CXFA_LocaleMgr {
+class CXFA_LocaleMgr : public LocaleMgrIface {
  public:
   CXFA_LocaleMgr(CXFA_Node* pLocaleSet, WideString wsDeflcid);
-  ~CXFA_LocaleMgr();
+  ~CXFA_LocaleMgr() override;
 
-  uint16_t GetDefLocaleID() const;
-  IFX_Locale* GetDefLocale();
-  IFX_Locale* GetLocaleByName(const WideString& wsLocaleName);
+  LocaleIface* GetDefLocale() override;
+  LocaleIface* GetLocaleByName(const WideString& wsLocaleName) override;
 
-  void SetDefLocale(IFX_Locale* pLocale);
-  WideStringView GetConfigLocaleName(CXFA_Node* pConfig);
+  void SetDefLocale(LocaleIface* pLocale);
+  WideString GetConfigLocaleName(CXFA_Node* pConfig);
 
  private:
-  std::unique_ptr<IFX_Locale> GetLocale(uint16_t lcid);
+  std::unique_ptr<LocaleIface> GetLocale(uint16_t lcid);
 
-  std::vector<std::unique_ptr<IFX_Locale>> m_LocaleArray;
-  std::vector<std::unique_ptr<IFX_Locale>> m_XMLLocaleArray;
-  IFX_Locale* m_pDefLocale;  // owned by m_LocaleArray or m_XMLLocaleArray.
+  std::vector<std::unique_ptr<LocaleIface>> m_LocaleArray;
+  std::vector<std::unique_ptr<LocaleIface>> m_XMLLocaleArray;
+
+  // Owned by m_LocaleArray or m_XMLLocaleArray.
+  UnownedPtr<LocaleIface> m_pDefLocale;
+
   WideString m_wsConfigLocale;
   uint16_t m_dwDeflcid;
-  uint16_t m_dwLocaleFlags;
+  bool m_hasSetLocaleName = false;
 };
 
 #endif  // XFA_FXFA_PARSER_CXFA_LOCALEMGR_H_
diff --git a/xfa/fxfa/parser/cxfa_localeset.cpp b/xfa/fxfa/parser/cxfa_localeset.cpp
index b669e3b..527006c 100644
--- a/xfa/fxfa/parser/cxfa_localeset.cpp
+++ b/xfa/fxfa/parser/cxfa_localeset.cpp
@@ -6,14 +6,15 @@
 
 #include "xfa/fxfa/parser/cxfa_localeset.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kLocaleSetAttributeData[] = {
     {XFA_Attribute::Desc, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Lock, XFA_AttributeType::Integer, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"localeSet";
+};
 
 }  // namespace
 
@@ -23,8 +24,8 @@
                 (XFA_XDPPACKET_Config | XFA_XDPPACKET_LocaleSet),
                 XFA_ObjectType::ModelNode,
                 XFA_Element::LocaleSet,
-                nullptr,
-                kAttributeData,
-                kName) {}
+                {},
+                kLocaleSetAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_LocaleSet::~CXFA_LocaleSet() {}
+CXFA_LocaleSet::~CXFA_LocaleSet() = default;
diff --git a/xfa/fxfa/parser/cxfa_localeset.h b/xfa/fxfa/parser/cxfa_localeset.h
index 1d65ad1..dc6521a 100644
--- a/xfa/fxfa/parser/cxfa_localeset.h
+++ b/xfa/fxfa/parser/cxfa_localeset.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_LocaleSet : public CXFA_Node {
+class CXFA_LocaleSet final : public CXFA_Node {
  public:
   CXFA_LocaleSet(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_LocaleSet() override;
diff --git a/xfa/fxfa/parser/cxfa_localevalue.cpp b/xfa/fxfa/parser/cxfa_localevalue.cpp
index 09e3577..0663d38 100644
--- a/xfa/fxfa/parser/cxfa_localevalue.cpp
+++ b/xfa/fxfa/parser/cxfa_localevalue.cpp
@@ -6,12 +6,15 @@
 
 #include "xfa/fxfa/parser/cxfa_localevalue.h"
 
+#include <cwchar>
+#include <utility>
 #include <vector>
 
 #include "core/fxcrt/fx_extension.h"
 #include "third_party/base/ptr_util.h"
+#include "third_party/base/span.h"
 #include "third_party/base/stl_util.h"
-#include "xfa/fgas/crt/cfgas_formatstring.h"
+#include "xfa/fgas/crt/cfgas_stringformatter.h"
 #include "xfa/fxfa/parser/cxfa_document.h"
 #include "xfa/fxfa/parser/cxfa_localemgr.h"
 #include "xfa/fxfa/parser/xfa_utils.h"
@@ -44,8 +47,8 @@
 bool ValueSplitDateTime(const WideString& wsDateTime,
                         WideString& wsDate,
                         WideString& wsTime) {
-  wsDate = L"";
-  wsTime = L"";
+  wsDate.clear();
+  wsTime.clear();
   if (wsDateTime.IsEmpty())
     return false;
 
@@ -55,21 +58,38 @@
   if (!nSplitIndex.has_value())
     return false;
 
-  wsDate = wsDateTime.Left(nSplitIndex.value());
-  wsTime = wsDateTime.Right(wsDateTime.GetLength() - nSplitIndex.value() - 1);
+  wsDate = wsDateTime.First(nSplitIndex.value());
+  wsTime = wsDateTime.Last(wsDateTime.GetLength() - nSplitIndex.value() - 1);
   return true;
 }
 
+class ScopedLocale {
+ public:
+  ScopedLocale(CXFA_LocaleMgr* pLocaleMgr, LocaleIface* pNewLocale)
+      : m_pLocaleMgr(pLocaleMgr),
+        m_pNewLocale(pNewLocale),
+        m_pOrigLocale(pNewLocale ? m_pLocaleMgr->GetDefLocale() : nullptr) {
+    if (m_pNewLocale)
+      m_pLocaleMgr->SetDefLocale(pNewLocale);
+  }
+
+  ~ScopedLocale() {
+    if (m_pNewLocale)
+      m_pLocaleMgr->SetDefLocale(m_pOrigLocale);
+  }
+
+  ScopedLocale(const ScopedLocale& that) = delete;
+  ScopedLocale& operator=(const ScopedLocale& that) = delete;
+
+ private:
+  UnownedPtr<CXFA_LocaleMgr> const m_pLocaleMgr;
+  LocaleIface* const m_pNewLocale;
+  LocaleIface* const m_pOrigLocale;
+};
+
 }  // namespace
 
-CXFA_LocaleValue::CXFA_LocaleValue()
-    : m_pLocaleMgr(nullptr), m_dwType(XFA_VT_NULL), m_bValid(true) {}
-
-CXFA_LocaleValue::CXFA_LocaleValue(const CXFA_LocaleValue& value)
-    : m_pLocaleMgr(value.m_pLocaleMgr),
-      m_wsValue(value.m_wsValue),
-      m_dwType(value.m_dwType),
-      m_bValid(value.m_bValid) {}
+CXFA_LocaleValue::CXFA_LocaleValue() = default;
 
 CXFA_LocaleValue::CXFA_LocaleValue(uint32_t dwType, CXFA_LocaleMgr* pLocaleMgr)
     : m_pLocaleMgr(pLocaleMgr),
@@ -87,94 +107,88 @@
 CXFA_LocaleValue::CXFA_LocaleValue(uint32_t dwType,
                                    const WideString& wsValue,
                                    const WideString& wsFormat,
-                                   IFX_Locale* pLocale,
+                                   LocaleIface* pLocale,
                                    CXFA_LocaleMgr* pLocaleMgr)
     : m_pLocaleMgr(pLocaleMgr),
       m_dwType(dwType),
       m_bValid(ParsePatternValue(wsValue, wsFormat, pLocale)) {}
 
-CXFA_LocaleValue& CXFA_LocaleValue::operator=(const CXFA_LocaleValue& value) {
-  m_wsValue = value.m_wsValue;
-  m_dwType = value.m_dwType;
-  m_bValid = value.m_bValid;
-  m_pLocaleMgr = value.m_pLocaleMgr;
-  return *this;
-}
+CXFA_LocaleValue::CXFA_LocaleValue(const CXFA_LocaleValue& that) = default;
 
-CXFA_LocaleValue::~CXFA_LocaleValue() {}
+CXFA_LocaleValue& CXFA_LocaleValue::operator=(const CXFA_LocaleValue& that) =
+    default;
+
+CXFA_LocaleValue::~CXFA_LocaleValue() = default;
 
 bool CXFA_LocaleValue::ValidateValue(const WideString& wsValue,
                                      const WideString& wsPattern,
-                                     IFX_Locale* pLocale,
+                                     LocaleIface* pLocale,
                                      WideString* pMatchFormat) {
+  if (!m_pLocaleMgr)
+    return false;
+
+  ScopedLocale scoped_locale(m_pLocaleMgr.Get(), pLocale);
+  std::vector<WideString> wsPatterns =
+      CFGAS_StringFormatter::SplitOnBars(wsPattern);
+
   WideString wsOutput;
-  IFX_Locale* locale = m_pLocaleMgr->GetDefLocale();
-  if (pLocale)
-    m_pLocaleMgr->SetDefLocale(pLocale);
-
-  auto pFormat = pdfium::MakeUnique<CFGAS_FormatString>(m_pLocaleMgr);
-  std::vector<WideString> wsPatterns;
-  pFormat->SplitFormatString(wsPattern, &wsPatterns);
-
   bool bRet = false;
-  int32_t iCount = pdfium::CollectionSize<int32_t>(wsPatterns);
-  int32_t i = 0;
-  for (; i < iCount && !bRet; i++) {
-    WideString wsFormat = wsPatterns[i];
-    switch (ValueCategory(pFormat->GetCategory(wsFormat), m_dwType)) {
+  size_t i = 0;
+  for (; !bRet && i < wsPatterns.size(); i++) {
+    const WideString& wsFormat = wsPatterns[i];
+    auto pFormat =
+        pdfium::MakeUnique<CFGAS_StringFormatter>(m_pLocaleMgr.Get(), wsFormat);
+    switch (ValueCategory(pFormat->GetCategory(), m_dwType)) {
       case FX_LOCALECATEGORY_Null:
-        bRet = pFormat->ParseNull(wsValue, wsFormat);
+        bRet = pFormat->ParseNull(wsValue);
         if (!bRet)
           bRet = wsValue.IsEmpty();
         break;
       case FX_LOCALECATEGORY_Zero:
-        bRet = pFormat->ParseZero(wsValue, wsFormat);
+        bRet = pFormat->ParseZero(wsValue);
         if (!bRet)
-          bRet = wsValue == L"0";
+          bRet = wsValue.EqualsASCII("0");
         break;
       case FX_LOCALECATEGORY_Num: {
         WideString fNum;
-        bRet = pFormat->ParseNum(wsValue, wsFormat, &fNum);
+        bRet = pFormat->ParseNum(wsValue, &fNum);
         if (!bRet)
-          bRet = pFormat->FormatNum(wsValue, wsFormat, &wsOutput);
+          bRet = pFormat->FormatNum(wsValue, &wsOutput);
         break;
       }
       case FX_LOCALECATEGORY_Text:
-        bRet = pFormat->ParseText(wsValue, wsFormat, &wsOutput);
+        bRet = pFormat->ParseText(wsValue, &wsOutput);
         wsOutput.clear();
         if (!bRet)
-          bRet = pFormat->FormatText(wsValue, wsFormat, &wsOutput);
+          bRet = pFormat->FormatText(wsValue, &wsOutput);
         break;
       case FX_LOCALECATEGORY_Date: {
         CFX_DateTime dt;
         bRet = ValidateCanonicalDate(wsValue, &dt);
         if (!bRet) {
-          bRet = pFormat->ParseDateTime(wsValue, wsFormat, FX_DATETIMETYPE_Date,
-                                        &dt);
+          bRet = pFormat->ParseDateTime(wsValue, FX_DATETIMETYPE_Date, &dt);
           if (!bRet) {
-            bRet = pFormat->FormatDateTime(wsValue, wsFormat,
-                                           FX_DATETIMETYPE_Date, &wsOutput);
+            bRet = pFormat->FormatDateTime(wsValue, FX_DATETIMETYPE_Date,
+                                           &wsOutput);
           }
         }
         break;
       }
       case FX_LOCALECATEGORY_Time: {
         CFX_DateTime dt;
-        bRet = pFormat->ParseDateTime(wsValue, wsFormat, FX_DATETIMETYPE_Time,
-                                      &dt);
+        bRet = pFormat->ParseDateTime(wsValue, FX_DATETIMETYPE_Time, &dt);
         if (!bRet) {
-          bRet = pFormat->FormatDateTime(wsValue, wsFormat,
-                                         FX_DATETIMETYPE_Time, &wsOutput);
+          bRet =
+              pFormat->FormatDateTime(wsValue, FX_DATETIMETYPE_Time, &wsOutput);
         }
         break;
       }
       case FX_LOCALECATEGORY_DateTime: {
         CFX_DateTime dt;
-        bRet = pFormat->ParseDateTime(wsValue, wsFormat,
-                                      FX_DATETIMETYPE_DateTime, &dt);
+        bRet = pFormat->ParseDateTime(wsValue, FX_DATETIMETYPE_DateTime, &dt);
         if (!bRet) {
-          bRet = pFormat->FormatDateTime(wsValue, wsFormat,
-                                         FX_DATETIMETYPE_DateTime, &wsOutput);
+          bRet = pFormat->FormatDateTime(wsValue, FX_DATETIMETYPE_DateTime,
+                                         &wsOutput);
         }
         break;
       }
@@ -185,90 +199,16 @@
   }
   if (bRet && pMatchFormat)
     *pMatchFormat = wsPatterns[i - 1];
-  if (pLocale)
-    m_pLocaleMgr->SetDefLocale(locale);
-
   return bRet;
 }
 
 double CXFA_LocaleValue::GetDoubleNum() const {
-  if (m_bValid && (m_dwType == XFA_VT_BOOLEAN || m_dwType == XFA_VT_INTEGER ||
-                   m_dwType == XFA_VT_DECIMAL || m_dwType == XFA_VT_FLOAT)) {
-    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 = m_wsValue.c_str();
-    int len = m_wsValue.GetLength();
-    while (FXSYS_iswspace(str[cc]) && cc < len)
-      cc++;
-
-    if (cc >= len)
-      return 0;
-    if (str[0] == '+') {
-      cc++;
-    } else if (str[0] == '-') {
-      bNegative = true;
-      cc++;
-    }
-
-    int32_t nIntegralLen = 0;
-    while (cc < len) {
-      if (str[cc] == '.' || !FXSYS_isDecimalDigit(str[cc]) ||
-          nIntegralLen > 17) {
-        break;
-      }
-      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 (scale == XFA_GetMaxFractionalScale() ||
-            !FXSYS_isDecimalDigit(str[cc])) {
-          break;
-        }
-      }
-      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]))
-          break;
-
-        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;
+  if (!m_bValid || (m_dwType != XFA_VT_BOOLEAN && m_dwType != XFA_VT_INTEGER &&
+                    m_dwType != XFA_VT_DECIMAL && m_dwType != XFA_VT_FLOAT)) {
+    return 0;
   }
-  return 0;
+
+  return wcstod(m_wsValue.c_str(), nullptr);
 }
 
 CFX_DateTime CXFA_LocaleValue::GetDate() const {
@@ -276,7 +216,7 @@
     return CFX_DateTime();
 
   CFX_DateTime dt;
-  FX_DateFromCanonical(m_wsValue, &dt);
+  FX_DateFromCanonical(m_wsValue.span(), &dt);
   return dt;
 }
 
@@ -285,8 +225,7 @@
     return CFX_DateTime();
 
   CFX_DateTime dt;
-  FX_TimeFromCanonical(m_wsValue.AsStringView(), &dt,
-                       m_pLocaleMgr->GetDefLocale());
+  FX_TimeFromCanonical(m_pLocaleMgr->GetDefLocale(), m_wsValue.span(), &dt);
   return dt;
 }
 
@@ -318,15 +257,11 @@
 
 bool CXFA_LocaleValue::FormatPatterns(WideString& wsResult,
                                       const WideString& wsFormat,
-                                      IFX_Locale* pLocale,
+                                      LocaleIface* pLocale,
                                       XFA_VALUEPICTURE eValueType) const {
-  auto pFormat = pdfium::MakeUnique<CFGAS_FormatString>(m_pLocaleMgr);
-  std::vector<WideString> wsPatterns;
-  pFormat->SplitFormatString(wsFormat, &wsPatterns);
   wsResult.clear();
-  int32_t iCount = pdfium::CollectionSize<int32_t>(wsPatterns);
-  for (int32_t i = 0; i < iCount; i++) {
-    if (FormatSinglePattern(wsResult, wsPatterns[i], pLocale, eValueType))
+  for (const auto& pattern : CFGAS_StringFormatter::SplitOnBars(wsFormat)) {
+    if (FormatSinglePattern(wsResult, pattern, pLocale, eValueType))
       return true;
   }
   return false;
@@ -334,43 +269,44 @@
 
 bool CXFA_LocaleValue::FormatSinglePattern(WideString& wsResult,
                                            const WideString& wsFormat,
-                                           IFX_Locale* pLocale,
+                                           LocaleIface* pLocale,
                                            XFA_VALUEPICTURE eValueType) const {
-  IFX_Locale* locale = m_pLocaleMgr->GetDefLocale();
-  if (pLocale)
-    m_pLocaleMgr->SetDefLocale(pLocale);
+  if (!m_pLocaleMgr)
+    return false;
+
+  ScopedLocale scoped_locale(m_pLocaleMgr.Get(), pLocale);
 
   wsResult.clear();
   bool bRet = false;
-  auto pFormat = pdfium::MakeUnique<CFGAS_FormatString>(m_pLocaleMgr);
-  FX_LOCALECATEGORY eCategory =
-      ValueCategory(pFormat->GetCategory(wsFormat), m_dwType);
+  auto pFormat =
+      pdfium::MakeUnique<CFGAS_StringFormatter>(m_pLocaleMgr.Get(), wsFormat);
+  FX_LOCALECATEGORY eCategory = ValueCategory(pFormat->GetCategory(), m_dwType);
   switch (eCategory) {
     case FX_LOCALECATEGORY_Null:
       if (m_wsValue.IsEmpty())
-        bRet = pFormat->FormatNull(wsFormat, &wsResult);
+        bRet = pFormat->FormatNull(&wsResult);
       break;
     case FX_LOCALECATEGORY_Zero:
-      if (m_wsValue == L"0")
-        bRet = pFormat->FormatZero(wsFormat, &wsResult);
+      if (m_wsValue.EqualsASCII("0"))
+        bRet = pFormat->FormatZero(&wsResult);
       break;
     case FX_LOCALECATEGORY_Num:
-      bRet = pFormat->FormatNum(m_wsValue, wsFormat, &wsResult);
+      bRet = pFormat->FormatNum(m_wsValue, &wsResult);
       break;
     case FX_LOCALECATEGORY_Text:
-      bRet = pFormat->FormatText(m_wsValue, wsFormat, &wsResult);
+      bRet = pFormat->FormatText(m_wsValue, &wsResult);
       break;
     case FX_LOCALECATEGORY_Date:
-      bRet = pFormat->FormatDateTime(m_wsValue, wsFormat, FX_DATETIMETYPE_Date,
-                                     &wsResult);
+      bRet =
+          pFormat->FormatDateTime(m_wsValue, FX_DATETIMETYPE_Date, &wsResult);
       break;
     case FX_LOCALECATEGORY_Time:
-      bRet = pFormat->FormatDateTime(m_wsValue, wsFormat, FX_DATETIMETYPE_Time,
-                                     &wsResult);
+      bRet =
+          pFormat->FormatDateTime(m_wsValue, FX_DATETIMETYPE_Time, &wsResult);
       break;
     case FX_LOCALECATEGORY_DateTime:
-      bRet = pFormat->FormatDateTime(m_wsValue, wsFormat,
-                                     FX_DATETIMETYPE_DateTime, &wsResult);
+      bRet = pFormat->FormatDateTime(m_wsValue, FX_DATETIMETYPE_DateTime,
+                                     &wsResult);
       break;
     default:
       wsResult = m_wsValue;
@@ -380,8 +316,6 @@
                 eValueType != XFA_VALUEPICTURE_Display)) {
     wsResult = m_wsValue;
   }
-  if (pLocale)
-    m_pLocaleMgr->SetDefLocale(locale);
 
   return bRet;
 }
@@ -430,65 +364,67 @@
 
 bool CXFA_LocaleValue::ValidateCanonicalDate(const WideString& wsDate,
                                              CFX_DateTime* unDate) {
-  static const uint16_t LastDay[12] = {31, 28, 31, 30, 31, 30,
-                                       31, 31, 30, 31, 30, 31};
+  static const uint8_t LastDay[12] = {31, 28, 31, 30, 31, 30,
+                                      31, 31, 30, 31, 30, 31};
   static const uint16_t wCountY = 4;
   static const uint16_t wCountM = 2;
   static const uint16_t wCountD = 2;
-  int nLen = wsDate.GetLength();
-  if (nLen < wCountY || nLen > wCountY + wCountM + wCountD + 2)
+  pdfium::span<const wchar_t> spDate = wsDate.span();
+  if (spDate.size() < wCountY ||
+      spDate.size() > wCountY + wCountM + wCountD + 2) {
     return false;
-
+  }
   const bool bSymbol = wsDate.Contains(0x2D);
   uint16_t wYear = 0;
   uint16_t wMonth = 0;
   uint16_t wDay = 0;
-  const wchar_t* pDate = wsDate.c_str();
-  int nIndex = 0;
-  int nStart = 0;
-  while (pDate[nIndex] != '\0' && nIndex < wCountY) {
-    if (!FXSYS_isDecimalDigit(pDate[nIndex]))
+  size_t nIndex = 0;
+  size_t nStart = 0;
+  while (nIndex < wCountY && spDate[nIndex] != '\0') {
+    if (!FXSYS_IsDecimalDigit(spDate[nIndex]))
       return false;
 
-    wYear = (pDate[nIndex] - '0') + wYear * 10;
+    wYear = (spDate[nIndex] - '0') + wYear * 10;
     nIndex++;
   }
   if (bSymbol) {
-    if (pDate[nIndex] != 0x2D)
+    if (nIndex >= spDate.size() || spDate[nIndex] != 0x2D)
       return false;
     nIndex++;
   }
 
   nStart = nIndex;
-  while (pDate[nIndex] != '\0' && nIndex - nStart < wCountM && nIndex < nLen) {
-    if (!FXSYS_isDecimalDigit(pDate[nIndex]))
+  while (nIndex < spDate.size() && spDate[nIndex] != '\0' &&
+         nIndex - nStart < wCountM) {
+    if (!FXSYS_IsDecimalDigit(spDate[nIndex]))
       return false;
 
-    wMonth = (pDate[nIndex] - '0') + wMonth * 10;
+    wMonth = (spDate[nIndex] - '0') + wMonth * 10;
     nIndex++;
   }
   if (bSymbol) {
-    if (pDate[nIndex] != 0x2D)
+    if (nIndex >= spDate.size() || spDate[nIndex] != 0x2D)
       return false;
     nIndex++;
   }
 
   nStart = nIndex;
-  while (pDate[nIndex] != '\0' && nIndex - nStart < wCountD && nIndex < nLen) {
-    if (!FXSYS_isDecimalDigit(pDate[nIndex]))
+  while (nIndex < spDate.size() && spDate[nIndex] != '\0' &&
+         nIndex - nStart < wCountD) {
+    if (!FXSYS_IsDecimalDigit(spDate[nIndex]))
       return false;
 
-    wDay = (pDate[nIndex] - '0') + wDay * 10;
+    wDay = (spDate[nIndex] - '0') + wDay * 10;
     nIndex++;
   }
-  if (nIndex != nLen)
+  if (nIndex != spDate.size())
     return false;
   if (wYear < 1900 || wYear > 2029)
     return false;
   if (wMonth < 1 || wMonth > 12)
-    return wMonth == 0 && nLen == wCountY;
+    return wMonth == 0 && spDate.size() == wCountY;
   if (wDay < 1)
-    return wDay == 0 && (nLen == wCountY + wCountM);
+    return wDay == 0 && spDate.size() == wCountY + wCountM;
   if (wMonth == 2) {
     if (wYear % 400 == 0 || (wYear % 100 != 0 && wYear % 4 == 0)) {
       if (wDay > 29)
@@ -506,8 +442,8 @@
 }
 
 bool CXFA_LocaleValue::ValidateCanonicalTime(const WideString& wsTime) {
-  int nLen = wsTime.GetLength();
-  if (nLen < 2)
+  pdfium::span<const wchar_t> spTime = wsTime.span();
+  if (spTime.size() < 2)
     return false;
 
   const uint16_t wCountH = 2;
@@ -519,128 +455,132 @@
   uint16_t wMinute = 0;
   uint16_t wSecond = 0;
   uint16_t wFraction = 0;
-  const wchar_t* pTime = wsTime.c_str();
-  int nIndex = 0;
-  int nStart = 0;
-  while (nIndex - nStart < wCountH && pTime[nIndex]) {
-    if (!FXSYS_isDecimalDigit(pTime[nIndex]))
+  size_t nIndex = 0;
+  size_t nStart = 0;
+  while (nIndex - nStart < wCountH && spTime[nIndex]) {
+    if (!FXSYS_IsDecimalDigit(spTime[nIndex]))
       return false;
-    wHour = pTime[nIndex] - '0' + wHour * 10;
+    wHour = spTime[nIndex] - '0' + wHour * 10;
     nIndex++;
   }
   if (bSymbol) {
-    if (nIndex < nLen && pTime[nIndex] != ':')
+    if (nIndex < spTime.size() && spTime[nIndex] != ':')
       return false;
     nIndex++;
   }
 
   nStart = nIndex;
-  while (nIndex - nStart < wCountM && nIndex < nLen && pTime[nIndex]) {
-    if (!FXSYS_isDecimalDigit(pTime[nIndex]))
+  while (nIndex < spTime.size() && spTime[nIndex] != '\0' &&
+         nIndex - nStart < wCountM) {
+    if (!FXSYS_IsDecimalDigit(spTime[nIndex]))
       return false;
-    wMinute = pTime[nIndex] - '0' + wMinute * 10;
+    wMinute = spTime[nIndex] - '0' + wMinute * 10;
     nIndex++;
   }
   if (bSymbol) {
-    if (nIndex < nLen && pTime[nIndex] != ':')
+    if (nIndex >= spTime.size() || spTime[nIndex] != ':')
       return false;
     nIndex++;
   }
   nStart = nIndex;
-  while (nIndex - nStart < wCountS && nIndex < nLen && pTime[nIndex]) {
-    if (!FXSYS_isDecimalDigit(pTime[nIndex]))
+  while (nIndex < spTime.size() && spTime[nIndex] != '\0' &&
+         nIndex - nStart < wCountS) {
+    if (!FXSYS_IsDecimalDigit(spTime[nIndex]))
       return false;
-    wSecond = pTime[nIndex] - '0' + wSecond * 10;
+    wSecond = spTime[nIndex] - '0' + wSecond * 10;
     nIndex++;
   }
   auto pos = wsTime.Find('.');
   if (pos.has_value() && pos.value() != 0) {
-    if (pTime[nIndex] != '.')
+    if (nIndex >= spTime.size() || spTime[nIndex] != '.')
       return false;
     nIndex++;
     nStart = nIndex;
-    while (nIndex - nStart < wCountF && nIndex < nLen && pTime[nIndex]) {
-      if (!FXSYS_isDecimalDigit(pTime[nIndex]))
+    while (nIndex < spTime.size() && spTime[nIndex] != '\0' &&
+           nIndex - nStart < wCountF) {
+      if (!FXSYS_IsDecimalDigit(spTime[nIndex]))
         return false;
-      wFraction = pTime[nIndex] - '0' + wFraction * 10;
+      wFraction = spTime[nIndex] - '0' + wFraction * 10;
       nIndex++;
     }
   }
-  if (nIndex < nLen) {
-    if (pTime[nIndex] == 'Z') {
+  if (nIndex < spTime.size()) {
+    if (spTime[nIndex] == 'Z') {
       nIndex++;
-    } else if (pTime[nIndex] == '-' || pTime[nIndex] == '+') {
+    } else if (spTime[nIndex] == '-' || spTime[nIndex] == '+') {
       int16_t nOffsetH = 0;
       int16_t nOffsetM = 0;
       nIndex++;
       nStart = nIndex;
-      while (nIndex - nStart < wCountH && nIndex < nLen && pTime[nIndex]) {
-        if (!FXSYS_isDecimalDigit(pTime[nIndex]))
+      while (nIndex < spTime.size() && spTime[nIndex] != '\0' &&
+             nIndex - nStart < wCountH) {
+        if (!FXSYS_IsDecimalDigit(spTime[nIndex]))
           return false;
-        nOffsetH = pTime[nIndex] - '0' + nOffsetH * 10;
+        nOffsetH = spTime[nIndex] - '0' + nOffsetH * 10;
         nIndex++;
       }
       if (bSymbol) {
-        if (nIndex < nLen && pTime[nIndex] != ':')
+        if (nIndex >= spTime.size() || spTime[nIndex] != ':')
           return false;
         nIndex++;
       }
       nStart = nIndex;
-      while (nIndex - nStart < wCountM && nIndex < nLen && pTime[nIndex]) {
-        if (!FXSYS_isDecimalDigit(pTime[nIndex]))
+      while (nIndex < spTime.size() && spTime[nIndex] != '\0' &&
+             nIndex - nStart < wCountM) {
+        if (!FXSYS_IsDecimalDigit(spTime[nIndex]))
           return false;
-        nOffsetM = pTime[nIndex] - '0' + nOffsetM * 10;
+        nOffsetM = spTime[nIndex] - '0' + nOffsetM * 10;
         nIndex++;
       }
       if (nOffsetH > 12 || nOffsetM >= 60)
         return false;
     }
   }
-  return nIndex == nLen && wHour < 24 && wMinute < 60 && wSecond < 60 &&
-         wFraction <= 999;
+  return nIndex == spTime.size() && wHour < 24 && wMinute < 60 &&
+         wSecond < 60 && wFraction <= 999;
 }
 
 bool CXFA_LocaleValue::ParsePatternValue(const WideString& wsValue,
                                          const WideString& wsPattern,
-                                         IFX_Locale* pLocale) {
-  IFX_Locale* locale = m_pLocaleMgr->GetDefLocale();
-  if (pLocale)
-    m_pLocaleMgr->SetDefLocale(pLocale);
+                                         LocaleIface* pLocale) {
+  if (!m_pLocaleMgr)
+    return false;
 
-  auto pFormat = pdfium::MakeUnique<CFGAS_FormatString>(m_pLocaleMgr);
-  std::vector<WideString> wsPatterns;
-  pFormat->SplitFormatString(wsPattern, &wsPatterns);
+  std::vector<WideString> wsPatterns =
+      CFGAS_StringFormatter::SplitOnBars(wsPattern);
+
+  ScopedLocale scoped_locale(m_pLocaleMgr.Get(), pLocale);
   bool bRet = false;
-  int32_t iCount = pdfium::CollectionSize<int32_t>(wsPatterns);
-  for (int32_t i = 0; i < iCount && !bRet; i++) {
-    WideString wsFormat = wsPatterns[i];
-    switch (ValueCategory(pFormat->GetCategory(wsFormat), m_dwType)) {
+  for (size_t i = 0; !bRet && i < wsPatterns.size(); i++) {
+    const WideString& wsFormat = wsPatterns[i];
+    auto pFormat =
+        pdfium::MakeUnique<CFGAS_StringFormatter>(m_pLocaleMgr.Get(), wsFormat);
+    switch (ValueCategory(pFormat->GetCategory(), m_dwType)) {
       case FX_LOCALECATEGORY_Null:
-        bRet = pFormat->ParseNull(wsValue, wsFormat);
+        bRet = pFormat->ParseNull(wsValue);
         if (bRet)
           m_wsValue.clear();
         break;
       case FX_LOCALECATEGORY_Zero:
-        bRet = pFormat->ParseZero(wsValue, wsFormat);
+        bRet = pFormat->ParseZero(wsValue);
         if (bRet)
           m_wsValue = L"0";
         break;
       case FX_LOCALECATEGORY_Num: {
         WideString fNum;
-        bRet = pFormat->ParseNum(wsValue, wsFormat, &fNum);
+        bRet = pFormat->ParseNum(wsValue, &fNum);
         if (bRet)
-          m_wsValue = fNum;
+          m_wsValue = std::move(fNum);
         break;
       }
       case FX_LOCALECATEGORY_Text:
-        bRet = pFormat->ParseText(wsValue, wsFormat, &m_wsValue);
+        bRet = pFormat->ParseText(wsValue, &m_wsValue);
         break;
       case FX_LOCALECATEGORY_Date: {
         CFX_DateTime dt;
         bRet = ValidateCanonicalDate(wsValue, &dt);
         if (!bRet) {
-          bRet = pFormat->ParseDateTime(wsValue, wsFormat, FX_DATETIMETYPE_Date,
-                                        &dt);
+          bRet = pFormat->ParseDateTime(wsValue, FX_DATETIMETYPE_Date, &dt);
         }
         if (bRet)
           SetDate(dt);
@@ -648,16 +588,14 @@
       }
       case FX_LOCALECATEGORY_Time: {
         CFX_DateTime dt;
-        bRet = pFormat->ParseDateTime(wsValue, wsFormat, FX_DATETIMETYPE_Time,
-                                      &dt);
+        bRet = pFormat->ParseDateTime(wsValue, FX_DATETIMETYPE_Time, &dt);
         if (bRet)
           SetTime(dt);
         break;
       }
       case FX_LOCALECATEGORY_DateTime: {
         CFX_DateTime dt;
-        bRet = pFormat->ParseDateTime(wsValue, wsFormat,
-                                      FX_DATETIMETYPE_DateTime, &dt);
+        bRet = pFormat->ParseDateTime(wsValue, FX_DATETIMETYPE_DateTime, &dt);
         if (bRet)
           SetDateTime(dt);
         break;
@@ -671,9 +609,6 @@
   if (!bRet)
     m_wsValue = wsValue;
 
-  if (pLocale)
-    m_pLocaleMgr->SetDefLocale(locale);
-
   return bRet;
 }
 
@@ -681,33 +616,37 @@
                                         int32_t nIntLen,
                                         int32_t nDecLen) {
   ASSERT(wsFormat.IsEmpty());
-  ASSERT(nIntLen >= -1 && nDecLen >= -1);
+  ASSERT(nIntLen >= -1);
+  ASSERT(nDecLen >= -1);
 
   int32_t nTotalLen = (nIntLen >= 0 ? nIntLen : 2) + 1 +
                       (nDecLen >= 0 ? nDecLen : 2) + (nDecLen == 0 ? 0 : 1);
-  wchar_t* lpBuf = wsFormat.GetBuffer(nTotalLen);
-  int32_t nPos = 0;
-  lpBuf[nPos++] = L's';
+  {
+    // Span's lifetime must end before ReleaseBuffer() below.
+    pdfium::span<wchar_t> lpBuf = wsFormat.GetBuffer(nTotalLen);
+    int32_t nPos = 0;
+    lpBuf[nPos++] = L's';
 
-  if (nIntLen == -1) {
-    lpBuf[nPos++] = L'z';
-    lpBuf[nPos++] = L'*';
-  } else {
-    while (nIntLen) {
+    if (nIntLen == -1) {
       lpBuf[nPos++] = L'z';
-      nIntLen--;
+      lpBuf[nPos++] = L'*';
+    } else {
+      while (nIntLen) {
+        lpBuf[nPos++] = L'z';
+        nIntLen--;
+      }
     }
-  }
-  if (nDecLen != 0) {
-    lpBuf[nPos++] = L'.';
-  }
-  if (nDecLen == -1) {
-    lpBuf[nPos++] = L'z';
-    lpBuf[nPos++] = L'*';
-  } else {
-    while (nDecLen) {
+    if (nDecLen != 0) {
+      lpBuf[nPos++] = L'.';
+    }
+    if (nDecLen == -1) {
       lpBuf[nPos++] = L'z';
-      nDecLen--;
+      lpBuf[nPos++] = L'*';
+    } else {
+      while (nDecLen) {
+        lpBuf[nPos++] = L'z';
+        nDecLen--;
+      }
     }
   }
   wsFormat.ReleaseBuffer(nTotalLen);
@@ -715,16 +654,16 @@
 
 bool CXFA_LocaleValue::ValidateNumericTemp(const WideString& wsNumeric,
                                            const WideString& wsFormat,
-                                           IFX_Locale* pLocale) {
+                                           LocaleIface* pLocale) {
   if (wsFormat.IsEmpty() || wsNumeric.IsEmpty())
     return true;
 
-  const wchar_t* pNum = wsNumeric.c_str();
-  const wchar_t* pFmt = wsFormat.c_str();
+  pdfium::span<const wchar_t> spNum = wsNumeric.span();
+  pdfium::span<const wchar_t> spFmt = wsFormat.span();
   int32_t n = 0;
   int32_t nf = 0;
-  wchar_t c = pNum[n];
-  wchar_t cf = pFmt[nf];
+  wchar_t c = spNum[n];
+  wchar_t cf = spFmt[nf];
   if (cf == L's') {
     if (c == L'-' || c == L'+')
       ++n;
@@ -734,10 +673,10 @@
   bool bLimit = true;
   int32_t nCount = wsNumeric.GetLength();
   int32_t nCountFmt = wsFormat.GetLength();
-  while (n < nCount && (bLimit ? nf < nCountFmt : true) &&
-         FXSYS_isDecimalDigit(c = pNum[n])) {
-    if (bLimit == true) {
-      if ((cf = pFmt[nf]) == L'*')
+  while (n < nCount && (!bLimit || nf < nCountFmt) &&
+         FXSYS_IsDecimalDigit(c = spNum[n])) {
+    if (bLimit) {
+      if ((cf = spFmt[nf]) == L'*')
         bLimit = false;
       else if (cf == L'z')
         nf++;
@@ -751,18 +690,18 @@
   if (nf == nCountFmt)
     return false;
 
-  while (nf < nCountFmt && (cf = pFmt[nf]) != L'.') {
+  while (nf < nCountFmt && (cf = spFmt[nf]) != L'.') {
     ASSERT(cf == L'z' || cf == L'*');
     ++nf;
   }
 
   WideString wsDecimalSymbol;
   if (pLocale)
-    wsDecimalSymbol = pLocale->GetNumbericSymbol(FX_LOCALENUMSYMBOL_Decimal);
+    wsDecimalSymbol = pLocale->GetDecimalSymbol();
   else
     wsDecimalSymbol = WideString(L'.');
 
-  if (pFmt[nf] != L'.')
+  if (spFmt[nf] != L'.')
     return false;
   if (wsDecimalSymbol != WideStringView(c) && c != L'.')
     return false;
@@ -770,10 +709,10 @@
   ++nf;
   ++n;
   bLimit = true;
-  while (n < nCount && (bLimit ? nf < nCountFmt : true) &&
-         FXSYS_isDecimalDigit(c = pNum[n])) {
-    if (bLimit == true) {
-      if ((cf = pFmt[nf]) == L'*')
+  while (n < nCount && (!bLimit || nf < nCountFmt) &&
+         FXSYS_IsDecimalDigit(spNum[n])) {
+    if (bLimit) {
+      if ((cf = spFmt[nf]) == L'*')
         bLimit = false;
       else if (cf == L'z')
         nf++;
diff --git a/xfa/fxfa/parser/cxfa_localevalue.h b/xfa/fxfa/parser/cxfa_localevalue.h
index 60de601..2005905 100644
--- a/xfa/fxfa/parser/cxfa_localevalue.h
+++ b/xfa/fxfa/parser/cxfa_localevalue.h
@@ -9,9 +9,10 @@
 
 #include "core/fxcrt/fx_string.h"
 #include "core/fxcrt/fx_system.h"
-#include "xfa/fxfa/cxfa_widgetacc.h"
+#include "core/fxcrt/unowned_ptr.h"
+#include "xfa/fxfa/parser/cxfa_node.h"
 
-class IFX_Locale;
+class LocaleIface;
 class CFX_DateTime;
 class CXFA_LocaleMgr;
 
@@ -28,7 +29,6 @@
 class CXFA_LocaleValue {
  public:
   CXFA_LocaleValue();
-  CXFA_LocaleValue(const CXFA_LocaleValue& value);
   CXFA_LocaleValue(uint32_t dwType, CXFA_LocaleMgr* pLocaleMgr);
   CXFA_LocaleValue(uint32_t dwType,
                    const WideString& wsValue,
@@ -36,39 +36,40 @@
   CXFA_LocaleValue(uint32_t dwType,
                    const WideString& wsValue,
                    const WideString& wsFormat,
-                   IFX_Locale* pLocale,
+                   LocaleIface* pLocale,
                    CXFA_LocaleMgr* pLocaleMgr);
+  CXFA_LocaleValue(const CXFA_LocaleValue& that);
   ~CXFA_LocaleValue();
-  CXFA_LocaleValue& operator=(const CXFA_LocaleValue& value);
+
+  CXFA_LocaleValue& operator=(const CXFA_LocaleValue& that);
 
   bool ValidateValue(const WideString& wsValue,
                      const WideString& wsPattern,
-                     IFX_Locale* pLocale,
+                     LocaleIface* pLocale,
                      WideString* pMatchFormat);
 
   bool FormatPatterns(WideString& wsResult,
                       const WideString& wsFormat,
-                      IFX_Locale* pLocale,
+                      LocaleIface* pLocale,
                       XFA_VALUEPICTURE eValueType) const;
 
   void GetNumericFormat(WideString& wsFormat, int32_t nIntLen, int32_t nDecLen);
   bool ValidateNumericTemp(const WideString& wsNumeric,
                            const WideString& wsFormat,
-                           IFX_Locale* pLocale);
+                           LocaleIface* pLocale);
 
-  WideString GetValue() const { return m_wsValue; }
+  bool IsValid() const { return m_bValid; }
+  const WideString& GetValue() const { return m_wsValue; }
   uint32_t GetType() const { return m_dwType; }
   double GetDoubleNum() const;
   bool SetDate(const CFX_DateTime& d);
   CFX_DateTime GetDate() const;
   CFX_DateTime GetTime() const;
 
-  bool IsValid() const { return m_bValid; }
-
  private:
   bool FormatSinglePattern(WideString& wsResult,
                            const WideString& wsFormat,
-                           IFX_Locale* pLocale,
+                           LocaleIface* pLocale,
                            XFA_VALUEPICTURE eValueType) const;
   bool ValidateCanonicalValue(const WideString& wsValue, uint32_t dwVType);
   bool ValidateCanonicalDate(const WideString& wsDate, CFX_DateTime* unDate);
@@ -79,12 +80,12 @@
 
   bool ParsePatternValue(const WideString& wsValue,
                          const WideString& wsPattern,
-                         IFX_Locale* pLocale);
+                         LocaleIface* pLocale);
 
-  CXFA_LocaleMgr* m_pLocaleMgr;
+  UnownedPtr<CXFA_LocaleMgr> m_pLocaleMgr;
   WideString m_wsValue;
-  uint32_t m_dwType;
-  bool m_bValid;
+  uint32_t m_dwType = XFA_VT_NULL;
+  bool m_bValid = true;
 };
 
 #endif  // XFA_FXFA_PARSER_CXFA_LOCALEVALUE_H_
diff --git a/xfa/fxfa/parser/cxfa_localevalue_unittest.cpp b/xfa/fxfa/parser/cxfa_localevalue_unittest.cpp
new file mode 100644
index 0000000..e69b058
--- /dev/null
+++ b/xfa/fxfa/parser/cxfa_localevalue_unittest.cpp
@@ -0,0 +1,36 @@
+// Copyright 2018 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_localevalue.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+// We don't expect more precision than a float's worth from this code.
+float MakeDoubleNumAsFloat(const wchar_t* str) {
+  return static_cast<float>(
+      CXFA_LocaleValue(XFA_VT_FLOAT, str, nullptr).GetDoubleNum());
+}
+
+}  // namespace
+
+TEST(CXFALocaleValueTest, GetDoubleNum) {
+  EXPECT_EQ(0.0, MakeDoubleNumAsFloat(L""));
+  EXPECT_EQ(0.0, MakeDoubleNumAsFloat(L"0"));
+  EXPECT_EQ(0.0, MakeDoubleNumAsFloat(L"0."));
+  EXPECT_EQ(0.0, MakeDoubleNumAsFloat(L"0.0"));
+  EXPECT_EQ(0.0, MakeDoubleNumAsFloat(L"0.x"));
+  EXPECT_EQ(7.0, MakeDoubleNumAsFloat(L"7.x"));
+  EXPECT_FLOAT_EQ(0.54321f, MakeDoubleNumAsFloat(L".54321"));
+  EXPECT_FLOAT_EQ(0.54321f, MakeDoubleNumAsFloat(L"0.54321"));
+  EXPECT_FLOAT_EQ(0.54321f, MakeDoubleNumAsFloat(L"+0.54321"));
+  EXPECT_FLOAT_EQ(0.54321f, MakeDoubleNumAsFloat(L"   +0.54321"));
+  EXPECT_FLOAT_EQ(-0.54321f, MakeDoubleNumAsFloat(L"-.54321"));
+  EXPECT_FLOAT_EQ(-0.54321f, MakeDoubleNumAsFloat(L"-0.54321"));
+  EXPECT_FLOAT_EQ(-0.54321f, MakeDoubleNumAsFloat(L"  -0.54321"));
+  EXPECT_FLOAT_EQ(-0.054321f, MakeDoubleNumAsFloat(L"-0.54321e-1"));
+  EXPECT_FLOAT_EQ(-0.54321f, MakeDoubleNumAsFloat(L"-0.54321e0"));
+  EXPECT_FLOAT_EQ(-5.4321f, MakeDoubleNumAsFloat(L"-0.54321e1"));
+}
diff --git a/xfa/fxfa/parser/cxfa_lockdocument.cpp b/xfa/fxfa/parser/cxfa_lockdocument.cpp
index 7e65334..b6aa783 100644
--- a/xfa/fxfa/parser/cxfa_lockdocument.cpp
+++ b/xfa/fxfa/parser/cxfa_lockdocument.cpp
@@ -6,17 +6,18 @@
 
 #include "xfa/fxfa/parser/cxfa_lockdocument.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kLockDocumentAttributeData[] = {
     {XFA_Attribute::Id, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Use, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Type, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::Optional},
+     (void*)XFA_AttributeValue::Optional},
     {XFA_Attribute::Usehref, XFA_AttributeType::CData, nullptr},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"lockDocument";
+};
 
 }  // namespace
 
@@ -26,8 +27,8 @@
                 (XFA_XDPPACKET_Template | XFA_XDPPACKET_Form),
                 XFA_ObjectType::ContentNode,
                 XFA_Element::LockDocument,
-                nullptr,
-                kAttributeData,
-                kName) {}
+                {},
+                kLockDocumentAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_LockDocument::~CXFA_LockDocument() {}
+CXFA_LockDocument::~CXFA_LockDocument() = default;
diff --git a/xfa/fxfa/parser/cxfa_lockdocument.h b/xfa/fxfa/parser/cxfa_lockdocument.h
index 025031a..1328d34 100644
--- a/xfa/fxfa/parser/cxfa_lockdocument.h
+++ b/xfa/fxfa/parser/cxfa_lockdocument.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_LockDocument : public CXFA_Node {
+class CXFA_LockDocument final : public CXFA_Node {
  public:
   CXFA_LockDocument(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_LockDocument() override;
diff --git a/xfa/fxfa/parser/cxfa_log.cpp b/xfa/fxfa/parser/cxfa_log.cpp
index 38651cb..e3e6c91 100644
--- a/xfa/fxfa/parser/cxfa_log.cpp
+++ b/xfa/fxfa/parser/cxfa_log.cpp
@@ -6,19 +6,22 @@
 
 #include "xfa/fxfa/parser/cxfa_log.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::PropertyData kPropertyData[] = {{XFA_Element::To, 1, 0},
-                                                 {XFA_Element::Uri, 1, 0},
-                                                 {XFA_Element::Mode, 1, 0},
-                                                 {XFA_Element::Threshold, 1, 0},
-                                                 {XFA_Element::Unknown, 0, 0}};
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::PropertyData kLogPropertyData[] = {
+    {XFA_Element::To, 1, 0},
+    {XFA_Element::Uri, 1, 0},
+    {XFA_Element::Mode, 1, 0},
+    {XFA_Element::Threshold, 1, 0},
+};
+
+const CXFA_Node::AttributeData kLogAttributeData[] = {
     {XFA_Attribute::Desc, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Lock, XFA_AttributeType::Integer, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"log";
+};
 
 }  // namespace
 
@@ -28,8 +31,8 @@
                 XFA_XDPPACKET_Config,
                 XFA_ObjectType::Node,
                 XFA_Element::Log,
-                kPropertyData,
-                kAttributeData,
-                kName) {}
+                kLogPropertyData,
+                kLogAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_Log::~CXFA_Log() {}
+CXFA_Log::~CXFA_Log() = default;
diff --git a/xfa/fxfa/parser/cxfa_log.h b/xfa/fxfa/parser/cxfa_log.h
index 17fd290..27173cd 100644
--- a/xfa/fxfa/parser/cxfa_log.h
+++ b/xfa/fxfa/parser/cxfa_log.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Log : public CXFA_Node {
+class CXFA_Log final : public CXFA_Node {
  public:
   CXFA_Log(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Log() override;
diff --git a/xfa/fxfa/parser/cxfa_manifest.cpp b/xfa/fxfa/parser/cxfa_manifest.cpp
index 32ec795..071ba3f 100644
--- a/xfa/fxfa/parser/cxfa_manifest.cpp
+++ b/xfa/fxfa/parser/cxfa_manifest.cpp
@@ -11,18 +11,18 @@
 
 namespace {
 
-const CXFA_Node::PropertyData kPropertyData[] = {{XFA_Element::Extras, 1, 0},
-                                                 {XFA_Element::Unknown, 0, 0}};
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::PropertyData kManifestPropertyData[] = {
+    {XFA_Element::Extras, 1, 0},
+};
+
+const CXFA_Node::AttributeData kManifestAttributeData[] = {
     {XFA_Attribute::Id, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Name, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Use, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Action, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::Include},
+     (void*)XFA_AttributeValue::Include},
     {XFA_Attribute::Usehref, XFA_AttributeType::CData, nullptr},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"manifest";
+};
 
 }  // namespace
 
@@ -32,9 +32,8 @@
                 (XFA_XDPPACKET_Template | XFA_XDPPACKET_Form),
                 XFA_ObjectType::Node,
                 XFA_Element::Manifest,
-                kPropertyData,
-                kAttributeData,
-                kName,
+                kManifestPropertyData,
+                kManifestAttributeData,
                 pdfium::MakeUnique<CJX_Manifest>(this)) {}
 
-CXFA_Manifest::~CXFA_Manifest() {}
+CXFA_Manifest::~CXFA_Manifest() = default;
diff --git a/xfa/fxfa/parser/cxfa_manifest.h b/xfa/fxfa/parser/cxfa_manifest.h
index a13cdac..d5ca05f 100644
--- a/xfa/fxfa/parser/cxfa_manifest.h
+++ b/xfa/fxfa/parser/cxfa_manifest.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Manifest : public CXFA_Node {
+class CXFA_Manifest final : public CXFA_Node {
  public:
   CXFA_Manifest(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Manifest() override;
diff --git a/xfa/fxfa/parser/cxfa_map.cpp b/xfa/fxfa/parser/cxfa_map.cpp
index 3e0c041..782cbc5 100644
--- a/xfa/fxfa/parser/cxfa_map.cpp
+++ b/xfa/fxfa/parser/cxfa_map.cpp
@@ -6,12 +6,12 @@
 
 #include "xfa/fxfa/parser/cxfa_map.h"
 
-#include "fxjs/xfa/cjx_map.h"
+#include "fxjs/xfa/cjx_node.h"
 #include "third_party/base/ptr_util.h"
 
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kMapAttributeData[] = {
     {XFA_Attribute::Id, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Name, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Use, XFA_AttributeType::CData, nullptr},
@@ -20,9 +20,7 @@
     {XFA_Attribute::Desc, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::From, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Lock, XFA_AttributeType::Integer, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"map";
+};
 
 }  // namespace
 
@@ -32,9 +30,8 @@
                 (XFA_XDPPACKET_Config | XFA_XDPPACKET_SourceSet),
                 XFA_ObjectType::Node,
                 XFA_Element::Map,
-                nullptr,
-                kAttributeData,
-                kName,
-                pdfium::MakeUnique<CJX_Map>(this)) {}
+                {},
+                kMapAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_Map::~CXFA_Map() {}
+CXFA_Map::~CXFA_Map() = default;
diff --git a/xfa/fxfa/parser/cxfa_map.h b/xfa/fxfa/parser/cxfa_map.h
index c49568f..f8e0797 100644
--- a/xfa/fxfa/parser/cxfa_map.h
+++ b/xfa/fxfa/parser/cxfa_map.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Map : public CXFA_Node {
+class CXFA_Map final : public CXFA_Node {
  public:
   CXFA_Map(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Map() override;
diff --git a/xfa/fxfa/parser/cxfa_margin.cpp b/xfa/fxfa/parser/cxfa_margin.cpp
index 265d7e9..5e58a88 100644
--- a/xfa/fxfa/parser/cxfa_margin.cpp
+++ b/xfa/fxfa/parser/cxfa_margin.cpp
@@ -6,14 +6,16 @@
 
 #include "xfa/fxfa/parser/cxfa_margin.h"
 
-#include "fxjs/xfa/cjx_margin.h"
+#include "fxjs/xfa/cjx_node.h"
 #include "third_party/base/ptr_util.h"
 
 namespace {
 
-const CXFA_Node::PropertyData kPropertyData[] = {{XFA_Element::Extras, 1, 0},
-                                                 {XFA_Element::Unknown, 0, 0}};
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::PropertyData kMarginPropertyData[] = {
+    {XFA_Element::Extras, 1, 0},
+};
+
+const CXFA_Node::AttributeData kMarginAttributeData[] = {
     {XFA_Attribute::Id, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Use, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::LeftInset, XFA_AttributeType::Measure, (void*)L"0in"},
@@ -21,9 +23,7 @@
     {XFA_Attribute::TopInset, XFA_AttributeType::Measure, (void*)L"0in"},
     {XFA_Attribute::RightInset, XFA_AttributeType::Measure, (void*)L"0in"},
     {XFA_Attribute::Usehref, XFA_AttributeType::CData, nullptr},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"margin";
+};
 
 }  // namespace
 
@@ -33,12 +33,11 @@
                 (XFA_XDPPACKET_Template | XFA_XDPPACKET_Form),
                 XFA_ObjectType::Node,
                 XFA_Element::Margin,
-                kPropertyData,
-                kAttributeData,
-                kName,
-                pdfium::MakeUnique<CJX_Margin>(this)) {}
+                kMarginPropertyData,
+                kMarginAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_Margin::~CXFA_Margin() {}
+CXFA_Margin::~CXFA_Margin() = default;
 
 float CXFA_Margin::GetLeftInset() const {
   return TryLeftInset().value_or(0);
diff --git a/xfa/fxfa/parser/cxfa_margin.h b/xfa/fxfa/parser/cxfa_margin.h
index e7f95b6..813bdfe 100644
--- a/xfa/fxfa/parser/cxfa_margin.h
+++ b/xfa/fxfa/parser/cxfa_margin.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Margin : public CXFA_Node {
+class CXFA_Margin final : public CXFA_Node {
  public:
   CXFA_Margin(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Margin() override;
diff --git a/xfa/fxfa/parser/cxfa_mdp.cpp b/xfa/fxfa/parser/cxfa_mdp.cpp
index b8fa1cd..3917bb6 100644
--- a/xfa/fxfa/parser/cxfa_mdp.cpp
+++ b/xfa/fxfa/parser/cxfa_mdp.cpp
@@ -6,21 +6,19 @@
 
 #include "xfa/fxfa/parser/cxfa_mdp.h"
 
-#include "fxjs/xfa/cjx_mdp.h"
+#include "fxjs/xfa/cjx_node.h"
 #include "third_party/base/ptr_util.h"
 
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kMdpAttributeData[] = {
     {XFA_Attribute::Id, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Use, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::SignatureType, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::Filter},
+     (void*)XFA_AttributeValue::Filter},
     {XFA_Attribute::Usehref, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Permissions, XFA_AttributeType::Integer, (void*)2},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"mdp";
+};
 
 }  // namespace
 
@@ -30,9 +28,8 @@
                 (XFA_XDPPACKET_Template | XFA_XDPPACKET_Form),
                 XFA_ObjectType::Node,
                 XFA_Element::Mdp,
-                nullptr,
-                kAttributeData,
-                kName,
-                pdfium::MakeUnique<CJX_Mdp>(this)) {}
+                {},
+                kMdpAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_Mdp::~CXFA_Mdp() {}
+CXFA_Mdp::~CXFA_Mdp() = default;
diff --git a/xfa/fxfa/parser/cxfa_mdp.h b/xfa/fxfa/parser/cxfa_mdp.h
index 0ae626d..79b1480 100644
--- a/xfa/fxfa/parser/cxfa_mdp.h
+++ b/xfa/fxfa/parser/cxfa_mdp.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Mdp : public CXFA_Node {
+class CXFA_Mdp final : public CXFA_Node {
  public:
   CXFA_Mdp(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Mdp() override;
diff --git a/xfa/fxfa/parser/cxfa_measurement.cpp b/xfa/fxfa/parser/cxfa_measurement.cpp
index d0534c9..3ce13e6 100644
--- a/xfa/fxfa/parser/cxfa_measurement.cpp
+++ b/xfa/fxfa/parser/cxfa_measurement.cpp
@@ -6,6 +6,8 @@
 
 #include "xfa/fxfa/parser/cxfa_measurement.h"
 
+#include <cmath>
+
 #include "core/fxcrt/fx_extension.h"
 
 namespace {
@@ -18,7 +20,7 @@
 
 }  // namespace
 
-CXFA_Measurement::CXFA_Measurement(const WideStringView& wsMeasure) {
+CXFA_Measurement::CXFA_Measurement(WideStringView wsMeasure) {
   SetString(wsMeasure);
 }
 
@@ -30,20 +32,23 @@
   Set(fValue, eUnit);
 }
 
-void CXFA_Measurement::SetString(const WideStringView& wsMeasure) {
+void CXFA_Measurement::SetString(WideStringView wsMeasure) {
   if (wsMeasure.IsEmpty()) {
-    m_fValue = 0;
-    m_eUnit = XFA_Unit::Unknown;
+    Set(0, XFA_Unit::Unknown);
     return;
   }
 
+  if (wsMeasure[0] == L'=')
+    wsMeasure = wsMeasure.Last(wsMeasure.GetLength() - 1);
+
   int32_t iUsedLen = 0;
-  int32_t iOffset = (wsMeasure[0] == L'=') ? 1 : 0;
-  float fValue = FXSYS_wcstof(wsMeasure.unterminated_c_str() + iOffset,
-                              wsMeasure.GetLength() - iOffset, &iUsedLen);
-  XFA_Unit eUnit = GetUnitFromString(
-      wsMeasure.Right(wsMeasure.GetLength() - (iOffset + iUsedLen)));
-  Set(fValue, eUnit);
+  float fValue = FXSYS_wcstof(wsMeasure.unterminated_c_str(),
+                              wsMeasure.GetLength(), &iUsedLen);
+  if (!std::isfinite(fValue))
+    fValue = 0.0f;
+
+  wsMeasure = wsMeasure.Last(wsMeasure.GetLength() - iUsedLen);
+  Set(fValue, GetUnitFromString(wsMeasure));
 }
 
 WideString CXFA_Measurement::ToString() const {
@@ -128,22 +133,22 @@
 }
 
 // static
-XFA_Unit CXFA_Measurement::GetUnitFromString(const WideStringView& wsUnit) {
-  if (wsUnit == L"mm")
+XFA_Unit CXFA_Measurement::GetUnitFromString(WideStringView wsUnit) {
+  if (wsUnit.EqualsASCII("mm"))
     return XFA_Unit::Mm;
-  if (wsUnit == L"pt")
+  if (wsUnit.EqualsASCII("pt"))
     return XFA_Unit::Pt;
-  if (wsUnit == L"in")
+  if (wsUnit.EqualsASCII("in"))
     return XFA_Unit::In;
-  if (wsUnit == L"cm")
+  if (wsUnit.EqualsASCII("cm"))
     return XFA_Unit::Cm;
-  if (wsUnit == L"pc")
+  if (wsUnit.EqualsASCII("pc"))
     return XFA_Unit::Pc;
-  if (wsUnit == L"mp")
+  if (wsUnit.EqualsASCII("mp"))
     return XFA_Unit::Mp;
-  if (wsUnit == L"em")
+  if (wsUnit.EqualsASCII("em"))
     return XFA_Unit::Em;
-  if (wsUnit == L"%")
+  if (wsUnit.EqualsASCII("%"))
     return XFA_Unit::Percent;
   return XFA_Unit::Unknown;
 }
diff --git a/xfa/fxfa/parser/cxfa_measurement.h b/xfa/fxfa/parser/cxfa_measurement.h
index d83af24..b2cf2d5 100644
--- a/xfa/fxfa/parser/cxfa_measurement.h
+++ b/xfa/fxfa/parser/cxfa_measurement.h
@@ -13,11 +13,11 @@
 
 class CXFA_Measurement {
  public:
-  explicit CXFA_Measurement(const WideStringView& wsMeasure);
+  explicit CXFA_Measurement(WideStringView wsMeasure);
   CXFA_Measurement();
   CXFA_Measurement(float fValue, XFA_Unit eUnit);
 
-  static XFA_Unit GetUnitFromString(const WideStringView& wsUnit);
+  static XFA_Unit GetUnitFromString(WideStringView wsUnit);
 
   void Set(float fValue, XFA_Unit eUnit) {
     m_fValue = fValue;
@@ -31,7 +31,7 @@
   float ToUnit(XFA_Unit eUnit) const;
 
  private:
-  void SetString(const WideStringView& wsMeasure);
+  void SetString(WideStringView wsMeasure);
   bool ToUnitInternal(XFA_Unit eUnit, float* fValue) const;
 
   float m_fValue;
diff --git a/xfa/fxfa/parser/cxfa_measurement_unittest.cpp b/xfa/fxfa/parser/cxfa_measurement_unittest.cpp
new file mode 100644
index 0000000..7a84eb1
--- /dev/null
+++ b/xfa/fxfa/parser/cxfa_measurement_unittest.cpp
@@ -0,0 +1,46 @@
+// Copyright 2019 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_measurement.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+TEST(CXFAMeasurementTest, ToString) {
+  CXFA_Measurement measurement;
+
+  measurement.Set(0.1f, XFA_Unit::Percent);
+  EXPECT_STREQ(L"0.1%", measurement.ToString().c_str());
+  measurement.Set(1.0f, XFA_Unit::Em);
+  EXPECT_STREQ(L"1em", measurement.ToString().c_str());
+  measurement.Set(1.1f, XFA_Unit::Pt);
+  EXPECT_STREQ(L"1.1pt", measurement.ToString().c_str());
+  measurement.Set(1.0000001f, XFA_Unit::In);
+  EXPECT_STREQ(L"1.0000001in", measurement.ToString().c_str());
+  measurement.Set(1234.0f, XFA_Unit::Pc);
+  EXPECT_STREQ(L"1234pc", measurement.ToString().c_str());
+  measurement.Set(987654321.0123456789f, XFA_Unit::Cm);
+  EXPECT_STREQ(L"9.8765434e+08cm", measurement.ToString().c_str());
+  measurement.Set(0.0f, XFA_Unit::Mm);
+  EXPECT_STREQ(L"0mm", measurement.ToString().c_str());
+  measurement.Set(-2.0f, XFA_Unit::Mp);
+  EXPECT_STREQ(L"-2mp", measurement.ToString().c_str());
+}
+
+TEST(CXFAMeasurementTest, GetUnitFromString) {
+  EXPECT_EQ(XFA_Unit::Percent, CXFA_Measurement::GetUnitFromString(L"%"));
+  EXPECT_EQ(XFA_Unit::Em, CXFA_Measurement::GetUnitFromString(L"em"));
+  EXPECT_EQ(XFA_Unit::Pt, CXFA_Measurement::GetUnitFromString(L"pt"));
+  EXPECT_EQ(XFA_Unit::In, CXFA_Measurement::GetUnitFromString(L"in"));
+  EXPECT_EQ(XFA_Unit::Pc, CXFA_Measurement::GetUnitFromString(L"pc"));
+  EXPECT_EQ(XFA_Unit::Cm, CXFA_Measurement::GetUnitFromString(L"cm"));
+  EXPECT_EQ(XFA_Unit::Mm, CXFA_Measurement::GetUnitFromString(L"mm"));
+  EXPECT_EQ(XFA_Unit::Mp, CXFA_Measurement::GetUnitFromString(L"mp"));
+
+  EXPECT_EQ(XFA_Unit::Unknown, CXFA_Measurement::GetUnitFromString(L""));
+  EXPECT_EQ(XFA_Unit::Unknown, CXFA_Measurement::GetUnitFromString(L"foo"));
+  EXPECT_EQ(XFA_Unit::Unknown, CXFA_Measurement::GetUnitFromString(L"!"));
+  EXPECT_EQ(XFA_Unit::Unknown, CXFA_Measurement::GetUnitFromString(L"CM"));
+  EXPECT_EQ(XFA_Unit::Unknown, CXFA_Measurement::GetUnitFromString(L"Cm"));
+  EXPECT_EQ(XFA_Unit::Unknown, CXFA_Measurement::GetUnitFromString(L"cM"));
+}
diff --git a/xfa/fxfa/parser/cxfa_medium.cpp b/xfa/fxfa/parser/cxfa_medium.cpp
index 3fa494a..47dee1b 100644
--- a/xfa/fxfa/parser/cxfa_medium.cpp
+++ b/xfa/fxfa/parser/cxfa_medium.cpp
@@ -6,28 +6,26 @@
 
 #include "xfa/fxfa/parser/cxfa_medium.h"
 
-#include "fxjs/xfa/cjx_medium.h"
+#include "fxjs/xfa/cjx_node.h"
 #include "third_party/base/ptr_util.h"
 
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kMediumAttributeData[] = {
     {XFA_Attribute::Id, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::TrayOut, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::Auto},
+     (void*)XFA_AttributeValue::Auto},
     {XFA_Attribute::Use, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Orientation, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::Portrait},
+     (void*)XFA_AttributeValue::Portrait},
     {XFA_Attribute::ImagingBBox, XFA_AttributeType::CData, (void*)L"none"},
     {XFA_Attribute::Short, XFA_AttributeType::Measure, (void*)L"0in"},
     {XFA_Attribute::TrayIn, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::Auto},
+     (void*)XFA_AttributeValue::Auto},
     {XFA_Attribute::Usehref, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Stock, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Long, XFA_AttributeType::Measure, (void*)L"0in"},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"medium";
+};
 
 }  // namespace
 
@@ -37,9 +35,8 @@
                 (XFA_XDPPACKET_Template | XFA_XDPPACKET_Form),
                 XFA_ObjectType::Node,
                 XFA_Element::Medium,
-                nullptr,
-                kAttributeData,
-                kName,
-                pdfium::MakeUnique<CJX_Medium>(this)) {}
+                {},
+                kMediumAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_Medium::~CXFA_Medium() {}
+CXFA_Medium::~CXFA_Medium() = default;
diff --git a/xfa/fxfa/parser/cxfa_medium.h b/xfa/fxfa/parser/cxfa_medium.h
index b9b9c5d..49be83f 100644
--- a/xfa/fxfa/parser/cxfa_medium.h
+++ b/xfa/fxfa/parser/cxfa_medium.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Medium : public CXFA_Node {
+class CXFA_Medium final : public CXFA_Node {
  public:
   CXFA_Medium(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Medium() override;
diff --git a/xfa/fxfa/parser/cxfa_mediuminfo.cpp b/xfa/fxfa/parser/cxfa_mediuminfo.cpp
index 9a41f1d..cc17657 100644
--- a/xfa/fxfa/parser/cxfa_mediuminfo.cpp
+++ b/xfa/fxfa/parser/cxfa_mediuminfo.cpp
@@ -6,16 +6,19 @@
 
 #include "xfa/fxfa/parser/cxfa_mediuminfo.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::PropertyData kPropertyData[] = {{XFA_Element::Map, 1, 0},
-                                                 {XFA_Element::Unknown, 0, 0}};
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::PropertyData kMediumInfoPropertyData[] = {
+    {XFA_Element::Map, 1, 0},
+};
+
+const CXFA_Node::AttributeData kMediumInfoAttributeData[] = {
     {XFA_Attribute::Desc, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Lock, XFA_AttributeType::Integer, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"mediumInfo";
+};
 
 }  // namespace
 
@@ -25,8 +28,8 @@
                 XFA_XDPPACKET_Config,
                 XFA_ObjectType::Node,
                 XFA_Element::MediumInfo,
-                kPropertyData,
-                kAttributeData,
-                kName) {}
+                kMediumInfoPropertyData,
+                kMediumInfoAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_MediumInfo::~CXFA_MediumInfo() {}
+CXFA_MediumInfo::~CXFA_MediumInfo() = default;
diff --git a/xfa/fxfa/parser/cxfa_mediuminfo.h b/xfa/fxfa/parser/cxfa_mediuminfo.h
index da100ea..65e58df 100644
--- a/xfa/fxfa/parser/cxfa_mediuminfo.h
+++ b/xfa/fxfa/parser/cxfa_mediuminfo.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_MediumInfo : public CXFA_Node {
+class CXFA_MediumInfo final : public CXFA_Node {
  public:
   CXFA_MediumInfo(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_MediumInfo() override;
diff --git a/xfa/fxfa/parser/cxfa_meridiem.cpp b/xfa/fxfa/parser/cxfa_meridiem.cpp
index 357ce2c..e250f2d 100644
--- a/xfa/fxfa/parser/cxfa_meridiem.cpp
+++ b/xfa/fxfa/parser/cxfa_meridiem.cpp
@@ -6,11 +6,8 @@
 
 #include "xfa/fxfa/parser/cxfa_meridiem.h"
 
-namespace {
-
-constexpr wchar_t kName[] = L"meridiem";
-
-}  // namespace
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
 
 CXFA_Meridiem::CXFA_Meridiem(CXFA_Document* doc, XFA_PacketType packet)
     : CXFA_Node(doc,
@@ -18,8 +15,8 @@
                 XFA_XDPPACKET_LocaleSet,
                 XFA_ObjectType::ContentNode,
                 XFA_Element::Meridiem,
-                nullptr,
-                nullptr,
-                kName) {}
+                {},
+                {},
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_Meridiem::~CXFA_Meridiem() {}
+CXFA_Meridiem::~CXFA_Meridiem() = default;
diff --git a/xfa/fxfa/parser/cxfa_meridiem.h b/xfa/fxfa/parser/cxfa_meridiem.h
index 30bd4b0..40c956c 100644
--- a/xfa/fxfa/parser/cxfa_meridiem.h
+++ b/xfa/fxfa/parser/cxfa_meridiem.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Meridiem : public CXFA_Node {
+class CXFA_Meridiem final : public CXFA_Node {
  public:
   CXFA_Meridiem(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Meridiem() override;
diff --git a/xfa/fxfa/parser/cxfa_meridiemnames.cpp b/xfa/fxfa/parser/cxfa_meridiemnames.cpp
index dfb603e..70ede73 100644
--- a/xfa/fxfa/parser/cxfa_meridiemnames.cpp
+++ b/xfa/fxfa/parser/cxfa_meridiemnames.cpp
@@ -6,12 +6,14 @@
 
 #include "xfa/fxfa/parser/cxfa_meridiemnames.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::PropertyData kPropertyData[] = {{XFA_Element::Meridiem, 2, 0},
-                                                 {XFA_Element::Unknown, 0, 0}};
-
-constexpr wchar_t kName[] = L"meridiemNames";
+const CXFA_Node::PropertyData kMeridiemNamesPropertyData[] = {
+    {XFA_Element::Meridiem, 2, 0},
+};
 
 }  // namespace
 
@@ -22,8 +24,8 @@
                 XFA_XDPPACKET_LocaleSet,
                 XFA_ObjectType::Node,
                 XFA_Element::MeridiemNames,
-                kPropertyData,
-                nullptr,
-                kName) {}
+                kMeridiemNamesPropertyData,
+                {},
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_MeridiemNames::~CXFA_MeridiemNames() {}
+CXFA_MeridiemNames::~CXFA_MeridiemNames() = default;
diff --git a/xfa/fxfa/parser/cxfa_meridiemnames.h b/xfa/fxfa/parser/cxfa_meridiemnames.h
index 8cade21..00fbbb7 100644
--- a/xfa/fxfa/parser/cxfa_meridiemnames.h
+++ b/xfa/fxfa/parser/cxfa_meridiemnames.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_MeridiemNames : public CXFA_Node {
+class CXFA_MeridiemNames final : public CXFA_Node {
  public:
   CXFA_MeridiemNames(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_MeridiemNames() override;
diff --git a/xfa/fxfa/parser/cxfa_message.cpp b/xfa/fxfa/parser/cxfa_message.cpp
index fa16efd..809a1db 100644
--- a/xfa/fxfa/parser/cxfa_message.cpp
+++ b/xfa/fxfa/parser/cxfa_message.cpp
@@ -6,23 +6,23 @@
 
 #include "xfa/fxfa/parser/cxfa_message.h"
 
-#include "fxjs/xfa/cjx_message.h"
+#include "fxjs/xfa/cjx_node.h"
 #include "third_party/base/ptr_util.h"
 
 namespace {
 
-const CXFA_Node::PropertyData kPropertyData[] = {{XFA_Element::MsgId, 1, 0},
-                                                 {XFA_Element::Severity, 1, 0},
-                                                 {XFA_Element::Unknown, 0, 0}};
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::PropertyData kMessagePropertyData[] = {
+    {XFA_Element::MsgId, 1, 0},
+    {XFA_Element::Severity, 1, 0},
+};
+
+const CXFA_Node::AttributeData kMessageAttributeData[] = {
     {XFA_Attribute::Id, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Use, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Usehref, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Desc, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Lock, XFA_AttributeType::Integer, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"message";
+};
 
 }  // namespace
 
@@ -33,9 +33,8 @@
           (XFA_XDPPACKET_Config | XFA_XDPPACKET_Template | XFA_XDPPACKET_Form),
           XFA_ObjectType::Node,
           XFA_Element::Message,
-          kPropertyData,
-          kAttributeData,
-          kName,
-          pdfium::MakeUnique<CJX_Message>(this)) {}
+          kMessagePropertyData,
+          kMessageAttributeData,
+          pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_Message::~CXFA_Message() {}
+CXFA_Message::~CXFA_Message() = default;
diff --git a/xfa/fxfa/parser/cxfa_message.h b/xfa/fxfa/parser/cxfa_message.h
index f172e06..81cb751 100644
--- a/xfa/fxfa/parser/cxfa_message.h
+++ b/xfa/fxfa/parser/cxfa_message.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Message : public CXFA_Node {
+class CXFA_Message final : public CXFA_Node {
  public:
   CXFA_Message(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Message() override;
diff --git a/xfa/fxfa/parser/cxfa_messaging.cpp b/xfa/fxfa/parser/cxfa_messaging.cpp
index 8ad77a4..4bb2b88 100644
--- a/xfa/fxfa/parser/cxfa_messaging.cpp
+++ b/xfa/fxfa/parser/cxfa_messaging.cpp
@@ -6,14 +6,15 @@
 
 #include "xfa/fxfa/parser/cxfa_messaging.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kMessagingAttributeData[] = {
     {XFA_Attribute::Desc, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Lock, XFA_AttributeType::Integer, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"messaging";
+};
 
 }  // namespace
 
@@ -23,8 +24,8 @@
                 XFA_XDPPACKET_Config,
                 XFA_ObjectType::Node,
                 XFA_Element::Messaging,
-                nullptr,
-                kAttributeData,
-                kName) {}
+                {},
+                kMessagingAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_Messaging::~CXFA_Messaging() {}
+CXFA_Messaging::~CXFA_Messaging() = default;
diff --git a/xfa/fxfa/parser/cxfa_messaging.h b/xfa/fxfa/parser/cxfa_messaging.h
index 48d16b3..86e16f3 100644
--- a/xfa/fxfa/parser/cxfa_messaging.h
+++ b/xfa/fxfa/parser/cxfa_messaging.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Messaging : public CXFA_Node {
+class CXFA_Messaging final : public CXFA_Node {
  public:
   CXFA_Messaging(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Messaging() override;
diff --git a/xfa/fxfa/parser/cxfa_mode.cpp b/xfa/fxfa/parser/cxfa_mode.cpp
index 6195f08..4e8e09e 100644
--- a/xfa/fxfa/parser/cxfa_mode.cpp
+++ b/xfa/fxfa/parser/cxfa_mode.cpp
@@ -6,14 +6,15 @@
 
 #include "xfa/fxfa/parser/cxfa_mode.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kModeAttributeData[] = {
     {XFA_Attribute::Desc, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Lock, XFA_AttributeType::Integer, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"mode";
+};
 
 }  // namespace
 
@@ -23,8 +24,8 @@
                 XFA_XDPPACKET_Config,
                 XFA_ObjectType::ContentNode,
                 XFA_Element::Mode,
-                nullptr,
-                kAttributeData,
-                kName) {}
+                {},
+                kModeAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_Mode::~CXFA_Mode() {}
+CXFA_Mode::~CXFA_Mode() = default;
diff --git a/xfa/fxfa/parser/cxfa_mode.h b/xfa/fxfa/parser/cxfa_mode.h
index 1dfd426..46675db 100644
--- a/xfa/fxfa/parser/cxfa_mode.h
+++ b/xfa/fxfa/parser/cxfa_mode.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Mode : public CXFA_Node {
+class CXFA_Mode final : public CXFA_Node {
  public:
   CXFA_Mode(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Mode() override;
diff --git a/xfa/fxfa/parser/cxfa_modifyannots.cpp b/xfa/fxfa/parser/cxfa_modifyannots.cpp
index e349dbf..6ec1293 100644
--- a/xfa/fxfa/parser/cxfa_modifyannots.cpp
+++ b/xfa/fxfa/parser/cxfa_modifyannots.cpp
@@ -6,14 +6,15 @@
 
 #include "xfa/fxfa/parser/cxfa_modifyannots.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kModifyAnnotsAttributeData[] = {
     {XFA_Attribute::Desc, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Lock, XFA_AttributeType::Integer, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"modifyAnnots";
+};
 
 }  // namespace
 
@@ -23,8 +24,8 @@
                 XFA_XDPPACKET_Config,
                 XFA_ObjectType::ContentNode,
                 XFA_Element::ModifyAnnots,
-                nullptr,
-                kAttributeData,
-                kName) {}
+                {},
+                kModifyAnnotsAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_ModifyAnnots::~CXFA_ModifyAnnots() {}
+CXFA_ModifyAnnots::~CXFA_ModifyAnnots() = default;
diff --git a/xfa/fxfa/parser/cxfa_modifyannots.h b/xfa/fxfa/parser/cxfa_modifyannots.h
index 4e10921..c92b05b 100644
--- a/xfa/fxfa/parser/cxfa_modifyannots.h
+++ b/xfa/fxfa/parser/cxfa_modifyannots.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_ModifyAnnots : public CXFA_Node {
+class CXFA_ModifyAnnots final : public CXFA_Node {
  public:
   CXFA_ModifyAnnots(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_ModifyAnnots() override;
diff --git a/xfa/fxfa/parser/cxfa_month.cpp b/xfa/fxfa/parser/cxfa_month.cpp
index 687ef4a..8cc4481 100644
--- a/xfa/fxfa/parser/cxfa_month.cpp
+++ b/xfa/fxfa/parser/cxfa_month.cpp
@@ -6,11 +6,8 @@
 
 #include "xfa/fxfa/parser/cxfa_month.h"
 
-namespace {
-
-constexpr wchar_t kName[] = L"month";
-
-}  // namespace
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
 
 CXFA_Month::CXFA_Month(CXFA_Document* doc, XFA_PacketType packet)
     : CXFA_Node(doc,
@@ -18,8 +15,8 @@
                 XFA_XDPPACKET_LocaleSet,
                 XFA_ObjectType::ContentNode,
                 XFA_Element::Month,
-                nullptr,
-                nullptr,
-                kName) {}
+                {},
+                {},
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_Month::~CXFA_Month() {}
+CXFA_Month::~CXFA_Month() = default;
diff --git a/xfa/fxfa/parser/cxfa_month.h b/xfa/fxfa/parser/cxfa_month.h
index 69361f5..f63095d 100644
--- a/xfa/fxfa/parser/cxfa_month.h
+++ b/xfa/fxfa/parser/cxfa_month.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Month : public CXFA_Node {
+class CXFA_Month final : public CXFA_Node {
  public:
   CXFA_Month(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Month() override;
diff --git a/xfa/fxfa/parser/cxfa_monthnames.cpp b/xfa/fxfa/parser/cxfa_monthnames.cpp
index 1b05b0d..dfb68d5 100644
--- a/xfa/fxfa/parser/cxfa_monthnames.cpp
+++ b/xfa/fxfa/parser/cxfa_monthnames.cpp
@@ -6,15 +6,18 @@
 
 #include "xfa/fxfa/parser/cxfa_monthnames.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::PropertyData kPropertyData[] = {{XFA_Element::Month, 12, 0},
-                                                 {XFA_Element::Unknown, 0, 0}};
-const CXFA_Node::AttributeData kAttributeData[] = {
-    {XFA_Attribute::Abbr, XFA_AttributeType::Boolean, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
+const CXFA_Node::PropertyData kMonthNamesPropertyData[] = {
+    {XFA_Element::Month, 12, 0},
+};
 
-constexpr wchar_t kName[] = L"monthNames";
+const CXFA_Node::AttributeData kMonthNamesAttributeData[] = {
+    {XFA_Attribute::Abbr, XFA_AttributeType::Boolean, (void*)0},
+};
 
 }  // namespace
 
@@ -24,8 +27,8 @@
                 XFA_XDPPACKET_LocaleSet,
                 XFA_ObjectType::Node,
                 XFA_Element::MonthNames,
-                kPropertyData,
-                kAttributeData,
-                kName) {}
+                kMonthNamesPropertyData,
+                kMonthNamesAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_MonthNames::~CXFA_MonthNames() {}
+CXFA_MonthNames::~CXFA_MonthNames() = default;
diff --git a/xfa/fxfa/parser/cxfa_monthnames.h b/xfa/fxfa/parser/cxfa_monthnames.h
index f95512b..cf0c331 100644
--- a/xfa/fxfa/parser/cxfa_monthnames.h
+++ b/xfa/fxfa/parser/cxfa_monthnames.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_MonthNames : public CXFA_Node {
+class CXFA_MonthNames final : public CXFA_Node {
  public:
   CXFA_MonthNames(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_MonthNames() override;
diff --git a/xfa/fxfa/parser/cxfa_msgid.cpp b/xfa/fxfa/parser/cxfa_msgid.cpp
index 626833b..107f635 100644
--- a/xfa/fxfa/parser/cxfa_msgid.cpp
+++ b/xfa/fxfa/parser/cxfa_msgid.cpp
@@ -6,14 +6,15 @@
 
 #include "xfa/fxfa/parser/cxfa_msgid.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kMsgIdAttributeData[] = {
     {XFA_Attribute::Desc, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Lock, XFA_AttributeType::Integer, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"msgId";
+};
 
 }  // namespace
 
@@ -23,8 +24,8 @@
                 XFA_XDPPACKET_Config,
                 XFA_ObjectType::NodeV,
                 XFA_Element::MsgId,
-                nullptr,
-                kAttributeData,
-                kName) {}
+                {},
+                kMsgIdAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_MsgId::~CXFA_MsgId() {}
+CXFA_MsgId::~CXFA_MsgId() = default;
diff --git a/xfa/fxfa/parser/cxfa_msgid.h b/xfa/fxfa/parser/cxfa_msgid.h
index 333085a..4c166d7 100644
--- a/xfa/fxfa/parser/cxfa_msgid.h
+++ b/xfa/fxfa/parser/cxfa_msgid.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_MsgId : public CXFA_Node {
+class CXFA_MsgId final : public CXFA_Node {
  public:
   CXFA_MsgId(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_MsgId() override;
diff --git a/xfa/fxfa/parser/cxfa_nameattr.cpp b/xfa/fxfa/parser/cxfa_nameattr.cpp
index dd42694..d29353f 100644
--- a/xfa/fxfa/parser/cxfa_nameattr.cpp
+++ b/xfa/fxfa/parser/cxfa_nameattr.cpp
@@ -6,14 +6,15 @@
 
 #include "xfa/fxfa/parser/cxfa_nameattr.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kNameAttrAttributeData[] = {
     {XFA_Attribute::Desc, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Lock, XFA_AttributeType::Integer, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"nameAttr";
+};
 
 }  // namespace
 
@@ -23,8 +24,8 @@
                 XFA_XDPPACKET_Config,
                 XFA_ObjectType::NodeV,
                 XFA_Element::NameAttr,
-                nullptr,
-                kAttributeData,
-                kName) {}
+                {},
+                kNameAttrAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_NameAttr::~CXFA_NameAttr() {}
+CXFA_NameAttr::~CXFA_NameAttr() = default;
diff --git a/xfa/fxfa/parser/cxfa_nameattr.h b/xfa/fxfa/parser/cxfa_nameattr.h
index 05514c0..f346bf6 100644
--- a/xfa/fxfa/parser/cxfa_nameattr.h
+++ b/xfa/fxfa/parser/cxfa_nameattr.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_NameAttr : public CXFA_Node {
+class CXFA_NameAttr final : public CXFA_Node {
  public:
   CXFA_NameAttr(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_NameAttr() override;
diff --git a/xfa/fxfa/parser/cxfa_neverembed.cpp b/xfa/fxfa/parser/cxfa_neverembed.cpp
index 7ba64a7..18af282 100644
--- a/xfa/fxfa/parser/cxfa_neverembed.cpp
+++ b/xfa/fxfa/parser/cxfa_neverembed.cpp
@@ -6,14 +6,15 @@
 
 #include "xfa/fxfa/parser/cxfa_neverembed.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kNeverEmbedAttributeData[] = {
     {XFA_Attribute::Desc, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Lock, XFA_AttributeType::Integer, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"neverEmbed";
+};
 
 }  // namespace
 
@@ -23,8 +24,8 @@
                 XFA_XDPPACKET_Config,
                 XFA_ObjectType::NodeV,
                 XFA_Element::NeverEmbed,
-                nullptr,
-                kAttributeData,
-                kName) {}
+                {},
+                kNeverEmbedAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_NeverEmbed::~CXFA_NeverEmbed() {}
+CXFA_NeverEmbed::~CXFA_NeverEmbed() = default;
diff --git a/xfa/fxfa/parser/cxfa_neverembed.h b/xfa/fxfa/parser/cxfa_neverembed.h
index 11ec928..70f90a3 100644
--- a/xfa/fxfa/parser/cxfa_neverembed.h
+++ b/xfa/fxfa/parser/cxfa_neverembed.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_NeverEmbed : public CXFA_Node {
+class CXFA_NeverEmbed final : public CXFA_Node {
  public:
   CXFA_NeverEmbed(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_NeverEmbed() override;
diff --git a/xfa/fxfa/parser/cxfa_node.cpp b/xfa/fxfa/parser/cxfa_node.cpp
index ec70271..05c6061 100644
--- a/xfa/fxfa/parser/cxfa_node.cpp
+++ b/xfa/fxfa/parser/cxfa_node.cpp
@@ -6,6 +6,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
+#include <algorithm>
 #include <map>
 #include <memory>
 #include <set>
@@ -13,53 +14,534 @@
 #include <vector>
 
 #include "core/fxcrt/autorestorer.h"
-#include "core/fxcrt/cfx_decimal.h"
-#include "core/fxcrt/cfx_memorystream.h"
+#include "core/fxcrt/cfx_readonlymemorystream.h"
 #include "core/fxcrt/fx_codepage.h"
 #include "core/fxcrt/fx_extension.h"
+#include "core/fxcrt/xml/cfx_xmldocument.h"
 #include "core/fxcrt/xml/cfx_xmlelement.h"
 #include "core/fxcrt/xml/cfx_xmlnode.h"
 #include "core/fxcrt/xml/cfx_xmltext.h"
-#include "fxjs/cfxjse_engine.h"
-#include "fxjs/cfxjse_value.h"
+#include "core/fxge/dib/cfx_dibitmap.h"
+#include "core/fxge/fx_font.h"
+#include "fxjs/xfa/cfxjse_engine.h"
+#include "fxjs/xfa/cfxjse_value.h"
 #include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/compiler_specific.h"
 #include "third_party/base/logging.h"
 #include "third_party/base/ptr_util.h"
+#include "third_party/base/span.h"
 #include "third_party/base/stl_util.h"
+#include "xfa/fde/cfde_textout.h"
+#include "xfa/fgas/crt/cfgas_decimal.h"
+#include "xfa/fgas/crt/locale_iface.h"
+#include "xfa/fgas/font/cfgas_fontmgr.h"
+#include "xfa/fgas/font/cfgas_gefont.h"
 #include "xfa/fxfa/cxfa_eventparam.h"
 #include "xfa/fxfa/cxfa_ffapp.h"
 #include "xfa/fxfa/cxfa_ffdocview.h"
 #include "xfa/fxfa/cxfa_ffnotify.h"
-#include "xfa/fxfa/cxfa_ffwidget.h"
+#include "xfa/fxfa/cxfa_fontmgr.h"
+#include "xfa/fxfa/cxfa_textprovider.h"
+#include "xfa/fxfa/parser/cxfa_accessiblecontent.h"
+#include "xfa/fxfa/parser/cxfa_acrobat.h"
+#include "xfa/fxfa/parser/cxfa_acrobat7.h"
+#include "xfa/fxfa/parser/cxfa_adbe_jsconsole.h"
+#include "xfa/fxfa/parser/cxfa_adbe_jsdebugger.h"
+#include "xfa/fxfa/parser/cxfa_addsilentprint.h"
+#include "xfa/fxfa/parser/cxfa_addviewerpreferences.h"
+#include "xfa/fxfa/parser/cxfa_adjustdata.h"
+#include "xfa/fxfa/parser/cxfa_adobeextensionlevel.h"
+#include "xfa/fxfa/parser/cxfa_agent.h"
+#include "xfa/fxfa/parser/cxfa_alwaysembed.h"
+#include "xfa/fxfa/parser/cxfa_amd.h"
+#include "xfa/fxfa/parser/cxfa_appearancefilter.h"
+#include "xfa/fxfa/parser/cxfa_arc.h"
+#include "xfa/fxfa/parser/cxfa_area.h"
 #include "xfa/fxfa/parser/cxfa_arraynodelist.h"
+#include "xfa/fxfa/parser/cxfa_assist.h"
 #include "xfa/fxfa/parser/cxfa_attachnodelist.h"
+#include "xfa/fxfa/parser/cxfa_attributes.h"
+#include "xfa/fxfa/parser/cxfa_autosave.h"
+#include "xfa/fxfa/parser/cxfa_barcode.h"
+#include "xfa/fxfa/parser/cxfa_base.h"
+#include "xfa/fxfa/parser/cxfa_batchoutput.h"
+#include "xfa/fxfa/parser/cxfa_behavioroverride.h"
 #include "xfa/fxfa/parser/cxfa_bind.h"
+#include "xfa/fxfa/parser/cxfa_binditems.h"
+#include "xfa/fxfa/parser/cxfa_bookend.h"
+#include "xfa/fxfa/parser/cxfa_boolean.h"
 #include "xfa/fxfa/parser/cxfa_border.h"
+#include "xfa/fxfa/parser/cxfa_break.h"
+#include "xfa/fxfa/parser/cxfa_breakafter.h"
+#include "xfa/fxfa/parser/cxfa_breakbefore.h"
+#include "xfa/fxfa/parser/cxfa_button.h"
+#include "xfa/fxfa/parser/cxfa_cache.h"
 #include "xfa/fxfa/parser/cxfa_calculate.h"
+#include "xfa/fxfa/parser/cxfa_calendarsymbols.h"
 #include "xfa/fxfa/parser/cxfa_caption.h"
+#include "xfa/fxfa/parser/cxfa_certificate.h"
+#include "xfa/fxfa/parser/cxfa_certificates.h"
+#include "xfa/fxfa/parser/cxfa_change.h"
+#include "xfa/fxfa/parser/cxfa_checkbutton.h"
+#include "xfa/fxfa/parser/cxfa_choicelist.h"
+#include "xfa/fxfa/parser/cxfa_color.h"
+#include "xfa/fxfa/parser/cxfa_comb.h"
+#include "xfa/fxfa/parser/cxfa_command.h"
+#include "xfa/fxfa/parser/cxfa_common.h"
+#include "xfa/fxfa/parser/cxfa_compress.h"
+#include "xfa/fxfa/parser/cxfa_compression.h"
+#include "xfa/fxfa/parser/cxfa_compresslogicalstructure.h"
+#include "xfa/fxfa/parser/cxfa_compressobjectstream.h"
+#include "xfa/fxfa/parser/cxfa_config.h"
+#include "xfa/fxfa/parser/cxfa_conformance.h"
+#include "xfa/fxfa/parser/cxfa_connect.h"
+#include "xfa/fxfa/parser/cxfa_connectionset.h"
+#include "xfa/fxfa/parser/cxfa_connectstring.h"
+#include "xfa/fxfa/parser/cxfa_contentarea.h"
+#include "xfa/fxfa/parser/cxfa_contentcopy.h"
+#include "xfa/fxfa/parser/cxfa_copies.h"
+#include "xfa/fxfa/parser/cxfa_corner.h"
+#include "xfa/fxfa/parser/cxfa_creator.h"
+#include "xfa/fxfa/parser/cxfa_currencysymbol.h"
+#include "xfa/fxfa/parser/cxfa_currencysymbols.h"
+#include "xfa/fxfa/parser/cxfa_currentpage.h"
+#include "xfa/fxfa/parser/cxfa_data.h"
+#include "xfa/fxfa/parser/cxfa_datagroup.h"
+#include "xfa/fxfa/parser/cxfa_datamodel.h"
+#include "xfa/fxfa/parser/cxfa_datavalue.h"
+#include "xfa/fxfa/parser/cxfa_date.h"
+#include "xfa/fxfa/parser/cxfa_datepattern.h"
+#include "xfa/fxfa/parser/cxfa_datepatterns.h"
+#include "xfa/fxfa/parser/cxfa_datetime.h"
+#include "xfa/fxfa/parser/cxfa_datetimeedit.h"
+#include "xfa/fxfa/parser/cxfa_datetimesymbols.h"
+#include "xfa/fxfa/parser/cxfa_day.h"
+#include "xfa/fxfa/parser/cxfa_daynames.h"
+#include "xfa/fxfa/parser/cxfa_debug.h"
+#include "xfa/fxfa/parser/cxfa_decimal.h"
+#include "xfa/fxfa/parser/cxfa_defaulttypeface.h"
+#include "xfa/fxfa/parser/cxfa_defaultui.h"
+#include "xfa/fxfa/parser/cxfa_delete.h"
+#include "xfa/fxfa/parser/cxfa_delta.h"
+#include "xfa/fxfa/parser/cxfa_deltas.h"
+#include "xfa/fxfa/parser/cxfa_desc.h"
+#include "xfa/fxfa/parser/cxfa_destination.h"
+#include "xfa/fxfa/parser/cxfa_digestmethod.h"
+#include "xfa/fxfa/parser/cxfa_digestmethods.h"
 #include "xfa/fxfa/parser/cxfa_document.h"
+#include "xfa/fxfa/parser/cxfa_document_parser.h"
+#include "xfa/fxfa/parser/cxfa_documentassembly.h"
+#include "xfa/fxfa/parser/cxfa_draw.h"
+#include "xfa/fxfa/parser/cxfa_driver.h"
+#include "xfa/fxfa/parser/cxfa_dsigdata.h"
+#include "xfa/fxfa/parser/cxfa_duplexoption.h"
+#include "xfa/fxfa/parser/cxfa_dynamicrender.h"
+#include "xfa/fxfa/parser/cxfa_edge.h"
+#include "xfa/fxfa/parser/cxfa_effectiveinputpolicy.h"
+#include "xfa/fxfa/parser/cxfa_effectiveoutputpolicy.h"
+#include "xfa/fxfa/parser/cxfa_embed.h"
+#include "xfa/fxfa/parser/cxfa_encoding.h"
+#include "xfa/fxfa/parser/cxfa_encodings.h"
+#include "xfa/fxfa/parser/cxfa_encrypt.h"
+#include "xfa/fxfa/parser/cxfa_encryption.h"
+#include "xfa/fxfa/parser/cxfa_encryptionlevel.h"
+#include "xfa/fxfa/parser/cxfa_encryptionmethod.h"
+#include "xfa/fxfa/parser/cxfa_encryptionmethods.h"
+#include "xfa/fxfa/parser/cxfa_enforce.h"
+#include "xfa/fxfa/parser/cxfa_equate.h"
+#include "xfa/fxfa/parser/cxfa_equaterange.h"
+#include "xfa/fxfa/parser/cxfa_era.h"
+#include "xfa/fxfa/parser/cxfa_eranames.h"
 #include "xfa/fxfa/parser/cxfa_event.h"
+#include "xfa/fxfa/parser/cxfa_exclgroup.h"
+#include "xfa/fxfa/parser/cxfa_exclude.h"
+#include "xfa/fxfa/parser/cxfa_excludens.h"
+#include "xfa/fxfa/parser/cxfa_exdata.h"
+#include "xfa/fxfa/parser/cxfa_execute.h"
+#include "xfa/fxfa/parser/cxfa_exobject.h"
+#include "xfa/fxfa/parser/cxfa_extras.h"
+#include "xfa/fxfa/parser/cxfa_field.h"
+#include "xfa/fxfa/parser/cxfa_fill.h"
+#include "xfa/fxfa/parser/cxfa_filter.h"
+#include "xfa/fxfa/parser/cxfa_fliplabel.h"
+#include "xfa/fxfa/parser/cxfa_float.h"
 #include "xfa/fxfa/parser/cxfa_font.h"
+#include "xfa/fxfa/parser/cxfa_fontinfo.h"
+#include "xfa/fxfa/parser/cxfa_form.h"
+#include "xfa/fxfa/parser/cxfa_format.h"
+#include "xfa/fxfa/parser/cxfa_formfieldfilling.h"
+#include "xfa/fxfa/parser/cxfa_groupparent.h"
+#include "xfa/fxfa/parser/cxfa_handler.h"
+#include "xfa/fxfa/parser/cxfa_hyphenation.h"
+#include "xfa/fxfa/parser/cxfa_ifempty.h"
+#include "xfa/fxfa/parser/cxfa_image.h"
+#include "xfa/fxfa/parser/cxfa_imageedit.h"
+#include "xfa/fxfa/parser/cxfa_includexdpcontent.h"
+#include "xfa/fxfa/parser/cxfa_incrementalload.h"
+#include "xfa/fxfa/parser/cxfa_incrementalmerge.h"
+#include "xfa/fxfa/parser/cxfa_insert.h"
+#include "xfa/fxfa/parser/cxfa_instancemanager.h"
+#include "xfa/fxfa/parser/cxfa_integer.h"
+#include "xfa/fxfa/parser/cxfa_interactive.h"
+#include "xfa/fxfa/parser/cxfa_issuers.h"
+#include "xfa/fxfa/parser/cxfa_items.h"
+#include "xfa/fxfa/parser/cxfa_jog.h"
 #include "xfa/fxfa/parser/cxfa_keep.h"
-#include "xfa/fxfa/parser/cxfa_layoutprocessor.h"
+#include "xfa/fxfa/parser/cxfa_keyusage.h"
+#include "xfa/fxfa/parser/cxfa_labelprinter.h"
+#include "xfa/fxfa/parser/cxfa_layout.h"
+#include "xfa/fxfa/parser/cxfa_level.h"
+#include "xfa/fxfa/parser/cxfa_line.h"
+#include "xfa/fxfa/parser/cxfa_linear.h"
+#include "xfa/fxfa/parser/cxfa_linearized.h"
+#include "xfa/fxfa/parser/cxfa_locale.h"
+#include "xfa/fxfa/parser/cxfa_localeset.h"
 #include "xfa/fxfa/parser/cxfa_localevalue.h"
+#include "xfa/fxfa/parser/cxfa_lockdocument.h"
+#include "xfa/fxfa/parser/cxfa_log.h"
+#include "xfa/fxfa/parser/cxfa_manifest.h"
+#include "xfa/fxfa/parser/cxfa_map.h"
 #include "xfa/fxfa/parser/cxfa_margin.h"
+#include "xfa/fxfa/parser/cxfa_mdp.h"
 #include "xfa/fxfa/parser/cxfa_measurement.h"
+#include "xfa/fxfa/parser/cxfa_medium.h"
+#include "xfa/fxfa/parser/cxfa_mediuminfo.h"
+#include "xfa/fxfa/parser/cxfa_meridiem.h"
+#include "xfa/fxfa/parser/cxfa_meridiemnames.h"
+#include "xfa/fxfa/parser/cxfa_message.h"
+#include "xfa/fxfa/parser/cxfa_messaging.h"
+#include "xfa/fxfa/parser/cxfa_mode.h"
+#include "xfa/fxfa/parser/cxfa_modifyannots.h"
+#include "xfa/fxfa/parser/cxfa_month.h"
+#include "xfa/fxfa/parser/cxfa_monthnames.h"
+#include "xfa/fxfa/parser/cxfa_msgid.h"
+#include "xfa/fxfa/parser/cxfa_nameattr.h"
+#include "xfa/fxfa/parser/cxfa_neverembed.h"
 #include "xfa/fxfa/parser/cxfa_nodeiteratortemplate.h"
+#include "xfa/fxfa/parser/cxfa_numberofcopies.h"
+#include "xfa/fxfa/parser/cxfa_numberpattern.h"
+#include "xfa/fxfa/parser/cxfa_numberpatterns.h"
+#include "xfa/fxfa/parser/cxfa_numbersymbol.h"
+#include "xfa/fxfa/parser/cxfa_numbersymbols.h"
+#include "xfa/fxfa/parser/cxfa_numericedit.h"
 #include "xfa/fxfa/parser/cxfa_occur.h"
+#include "xfa/fxfa/parser/cxfa_oid.h"
+#include "xfa/fxfa/parser/cxfa_oids.h"
+#include "xfa/fxfa/parser/cxfa_openaction.h"
+#include "xfa/fxfa/parser/cxfa_operation.h"
+#include "xfa/fxfa/parser/cxfa_output.h"
+#include "xfa/fxfa/parser/cxfa_outputbin.h"
+#include "xfa/fxfa/parser/cxfa_outputxsl.h"
+#include "xfa/fxfa/parser/cxfa_overflow.h"
+#include "xfa/fxfa/parser/cxfa_overprint.h"
+#include "xfa/fxfa/parser/cxfa_packet.h"
+#include "xfa/fxfa/parser/cxfa_packets.h"
+#include "xfa/fxfa/parser/cxfa_pagearea.h"
+#include "xfa/fxfa/parser/cxfa_pageoffset.h"
+#include "xfa/fxfa/parser/cxfa_pagerange.h"
+#include "xfa/fxfa/parser/cxfa_pageset.h"
+#include "xfa/fxfa/parser/cxfa_pagination.h"
+#include "xfa/fxfa/parser/cxfa_paginationoverride.h"
 #include "xfa/fxfa/parser/cxfa_para.h"
-#include "xfa/fxfa/parser/cxfa_simple_parser.h"
+#include "xfa/fxfa/parser/cxfa_part.h"
+#include "xfa/fxfa/parser/cxfa_password.h"
+#include "xfa/fxfa/parser/cxfa_passwordedit.h"
+#include "xfa/fxfa/parser/cxfa_pattern.h"
+#include "xfa/fxfa/parser/cxfa_pcl.h"
+#include "xfa/fxfa/parser/cxfa_pdf.h"
+#include "xfa/fxfa/parser/cxfa_pdfa.h"
+#include "xfa/fxfa/parser/cxfa_permissions.h"
+#include "xfa/fxfa/parser/cxfa_picktraybypdfsize.h"
+#include "xfa/fxfa/parser/cxfa_picture.h"
+#include "xfa/fxfa/parser/cxfa_plaintextmetadata.h"
+#include "xfa/fxfa/parser/cxfa_presence.h"
+#include "xfa/fxfa/parser/cxfa_present.h"
+#include "xfa/fxfa/parser/cxfa_print.h"
+#include "xfa/fxfa/parser/cxfa_printername.h"
+#include "xfa/fxfa/parser/cxfa_printhighquality.h"
+#include "xfa/fxfa/parser/cxfa_printscaling.h"
+#include "xfa/fxfa/parser/cxfa_producer.h"
+#include "xfa/fxfa/parser/cxfa_proto.h"
+#include "xfa/fxfa/parser/cxfa_ps.h"
+#include "xfa/fxfa/parser/cxfa_psmap.h"
+#include "xfa/fxfa/parser/cxfa_query.h"
+#include "xfa/fxfa/parser/cxfa_radial.h"
+#include "xfa/fxfa/parser/cxfa_range.h"
+#include "xfa/fxfa/parser/cxfa_reason.h"
+#include "xfa/fxfa/parser/cxfa_reasons.h"
+#include "xfa/fxfa/parser/cxfa_record.h"
+#include "xfa/fxfa/parser/cxfa_recordset.h"
+#include "xfa/fxfa/parser/cxfa_rectangle.h"
+#include "xfa/fxfa/parser/cxfa_ref.h"
+#include "xfa/fxfa/parser/cxfa_relevant.h"
+#include "xfa/fxfa/parser/cxfa_rename.h"
+#include "xfa/fxfa/parser/cxfa_renderpolicy.h"
+#include "xfa/fxfa/parser/cxfa_rootelement.h"
+#include "xfa/fxfa/parser/cxfa_runscripts.h"
+#include "xfa/fxfa/parser/cxfa_script.h"
+#include "xfa/fxfa/parser/cxfa_scriptmodel.h"
+#include "xfa/fxfa/parser/cxfa_select.h"
+#include "xfa/fxfa/parser/cxfa_setproperty.h"
+#include "xfa/fxfa/parser/cxfa_severity.h"
+#include "xfa/fxfa/parser/cxfa_sharptext.h"
+#include "xfa/fxfa/parser/cxfa_sharpxhtml.h"
+#include "xfa/fxfa/parser/cxfa_sharpxml.h"
+#include "xfa/fxfa/parser/cxfa_signature.h"
+#include "xfa/fxfa/parser/cxfa_signatureproperties.h"
+#include "xfa/fxfa/parser/cxfa_signdata.h"
+#include "xfa/fxfa/parser/cxfa_signing.h"
+#include "xfa/fxfa/parser/cxfa_silentprint.h"
+#include "xfa/fxfa/parser/cxfa_soapaction.h"
+#include "xfa/fxfa/parser/cxfa_soapaddress.h"
+#include "xfa/fxfa/parser/cxfa_solid.h"
+#include "xfa/fxfa/parser/cxfa_source.h"
+#include "xfa/fxfa/parser/cxfa_sourceset.h"
+#include "xfa/fxfa/parser/cxfa_speak.h"
+#include "xfa/fxfa/parser/cxfa_staple.h"
+#include "xfa/fxfa/parser/cxfa_startnode.h"
+#include "xfa/fxfa/parser/cxfa_startpage.h"
+#include "xfa/fxfa/parser/cxfa_stipple.h"
+#include "xfa/fxfa/parser/cxfa_stroke.h"
 #include "xfa/fxfa/parser/cxfa_subform.h"
+#include "xfa/fxfa/parser/cxfa_subformset.h"
+#include "xfa/fxfa/parser/cxfa_subjectdn.h"
+#include "xfa/fxfa/parser/cxfa_subjectdns.h"
+#include "xfa/fxfa/parser/cxfa_submit.h"
+#include "xfa/fxfa/parser/cxfa_submitformat.h"
+#include "xfa/fxfa/parser/cxfa_submiturl.h"
+#include "xfa/fxfa/parser/cxfa_subsetbelow.h"
+#include "xfa/fxfa/parser/cxfa_suppressbanner.h"
+#include "xfa/fxfa/parser/cxfa_tagged.h"
+#include "xfa/fxfa/parser/cxfa_template.h"
+#include "xfa/fxfa/parser/cxfa_templatecache.h"
+#include "xfa/fxfa/parser/cxfa_text.h"
+#include "xfa/fxfa/parser/cxfa_textedit.h"
+#include "xfa/fxfa/parser/cxfa_threshold.h"
+#include "xfa/fxfa/parser/cxfa_time.h"
+#include "xfa/fxfa/parser/cxfa_timepattern.h"
+#include "xfa/fxfa/parser/cxfa_timepatterns.h"
+#include "xfa/fxfa/parser/cxfa_timestamp.h"
+#include "xfa/fxfa/parser/cxfa_to.h"
+#include "xfa/fxfa/parser/cxfa_tooltip.h"
+#include "xfa/fxfa/parser/cxfa_trace.h"
+#include "xfa/fxfa/parser/cxfa_transform.h"
+#include "xfa/fxfa/parser/cxfa_traversal.h"
+#include "xfa/fxfa/parser/cxfa_traverse.h"
 #include "xfa/fxfa/parser/cxfa_traversestrategy_xfacontainernode.h"
+#include "xfa/fxfa/parser/cxfa_traversestrategy_xfanode.h"
+#include "xfa/fxfa/parser/cxfa_type.h"
+#include "xfa/fxfa/parser/cxfa_typeface.h"
+#include "xfa/fxfa/parser/cxfa_typefaces.h"
+#include "xfa/fxfa/parser/cxfa_ui.h"
+#include "xfa/fxfa/parser/cxfa_update.h"
+#include "xfa/fxfa/parser/cxfa_uri.h"
+#include "xfa/fxfa/parser/cxfa_user.h"
 #include "xfa/fxfa/parser/cxfa_validate.h"
+#include "xfa/fxfa/parser/cxfa_validateapprovalsignatures.h"
+#include "xfa/fxfa/parser/cxfa_validationmessaging.h"
 #include "xfa/fxfa/parser/cxfa_value.h"
+#include "xfa/fxfa/parser/cxfa_variables.h"
+#include "xfa/fxfa/parser/cxfa_version.h"
+#include "xfa/fxfa/parser/cxfa_versioncontrol.h"
+#include "xfa/fxfa/parser/cxfa_viewerpreferences.h"
+#include "xfa/fxfa/parser/cxfa_webclient.h"
+#include "xfa/fxfa/parser/cxfa_whitespace.h"
+#include "xfa/fxfa/parser/cxfa_window.h"
+#include "xfa/fxfa/parser/cxfa_wsdladdress.h"
+#include "xfa/fxfa/parser/cxfa_wsdlconnection.h"
+#include "xfa/fxfa/parser/cxfa_xdc.h"
+#include "xfa/fxfa/parser/cxfa_xdp.h"
+#include "xfa/fxfa/parser/cxfa_xfa.h"
+#include "xfa/fxfa/parser/cxfa_xmlconnection.h"
+#include "xfa/fxfa/parser/cxfa_xsdconnection.h"
+#include "xfa/fxfa/parser/cxfa_xsl.h"
+#include "xfa/fxfa/parser/cxfa_zpl.h"
 #include "xfa/fxfa/parser/xfa_basic_data.h"
 #include "xfa/fxfa/parser/xfa_utils.h"
 
+class CXFA_FieldLayoutData;
+class CXFA_ImageEditData;
+class CXFA_ImageLayoutData;
+class CXFA_TextEditData;
+class CXFA_TextLayoutData;
+
 namespace {
 
 constexpr uint8_t kMaxExecuteRecursion = 2;
 
+constexpr uint8_t g_inv_base64[128] = {
+    255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+    255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+    255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 62,  255,
+    255, 255, 63,  52,  53,  54,  55,  56,  57,  58,  59,  60,  61,  255, 255,
+    255, 255, 255, 255, 255, 0,   1,   2,   3,   4,   5,   6,   7,   8,   9,
+    10,  11,  12,  13,  14,  15,  16,  17,  18,  19,  20,  21,  22,  23,  24,
+    25,  255, 255, 255, 255, 255, 255, 26,  27,  28,  29,  30,  31,  32,  33,
+    34,  35,  36,  37,  38,  39,  40,  41,  42,  43,  44,  45,  46,  47,  48,
+    49,  50,  51,  255, 255, 255, 255, 255,
+};
+
+inline uint8_t GetInvBase64(uint8_t x) {
+  return (x & 128) == 0 ? g_inv_base64[x] : 255;
+}
+
+std::vector<uint8_t> XFA_RemoveBase64Whitespace(
+    pdfium::span<const uint8_t> spStr) {
+  std::vector<uint8_t> result;
+  result.reserve(spStr.size());
+  for (uint8_t ch : spStr) {
+    if (GetInvBase64(ch) != 255 || ch == '=')
+      result.push_back(ch);
+  }
+  return result;
+}
+
+std::vector<uint8_t> XFA_Base64Decode(const ByteString& bsStr) {
+  std::vector<uint8_t> result;
+  if (bsStr.IsEmpty())
+    return result;
+
+  std::vector<uint8_t> buffer = XFA_RemoveBase64Whitespace(bsStr.raw_span());
+  result.reserve(3 * (buffer.size() / 4));
+
+  uint32_t dwLimb = 0;
+  for (size_t i = 0; i + 3 < buffer.size(); i += 4) {
+    if (buffer[i] == '=' || buffer[i + 1] == '=' || buffer[i + 2] == '=' ||
+        buffer[i + 3] == '=') {
+      if (buffer[i] == '=' || buffer[i + 1] == '=') {
+        break;
+      }
+      if (buffer[i + 2] == '=') {
+        dwLimb = ((uint32_t)g_inv_base64[buffer[i]] << 6) |
+                 ((uint32_t)g_inv_base64[buffer[i + 1]]);
+        result.push_back((uint8_t)(dwLimb >> 4) & 0xFF);
+      } else {
+        dwLimb = ((uint32_t)g_inv_base64[buffer[i]] << 12) |
+                 ((uint32_t)g_inv_base64[buffer[i + 1]] << 6) |
+                 ((uint32_t)g_inv_base64[buffer[i + 2]]);
+        result.push_back((uint8_t)(dwLimb >> 10) & 0xFF);
+        result.push_back((uint8_t)(dwLimb >> 2) & 0xFF);
+      }
+    } else {
+      dwLimb = ((uint32_t)g_inv_base64[buffer[i]] << 18) |
+               ((uint32_t)g_inv_base64[buffer[i + 1]] << 12) |
+               ((uint32_t)g_inv_base64[buffer[i + 2]] << 6) |
+               ((uint32_t)g_inv_base64[buffer[i + 3]]);
+      result.push_back((uint8_t)(dwLimb >> 16) & 0xff);
+      result.push_back((uint8_t)(dwLimb >> 8) & 0xff);
+      result.push_back((uint8_t)(dwLimb)&0xff);
+    }
+  }
+  return result;
+}
+
+FXCODEC_IMAGE_TYPE XFA_GetImageType(const WideString& wsType) {
+  WideString wsContentType(wsType);
+  if (wsContentType.EqualsASCIINoCase("image/jpg"))
+    return FXCODEC_IMAGE_JPG;
+
+#ifdef PDF_ENABLE_XFA_BMP
+  if (wsContentType.EqualsASCIINoCase("image/bmp"))
+    return FXCODEC_IMAGE_BMP;
+#endif  // PDF_ENABLE_XFA_BMP
+
+#ifdef PDF_ENABLE_XFA_GIF
+  if (wsContentType.EqualsASCIINoCase("image/gif"))
+    return FXCODEC_IMAGE_GIF;
+#endif  // PDF_ENABLE_XFA_GIF
+
+#ifdef PDF_ENABLE_XFA_PNG
+  if (wsContentType.EqualsASCIINoCase("image/png"))
+    return FXCODEC_IMAGE_PNG;
+#endif  // PDF_ENABLE_XFA_PNG
+
+#ifdef PDF_ENABLE_XFA_TIFF
+  if (wsContentType.EqualsASCII("image/tif"))
+    return FXCODEC_IMAGE_TIFF;
+#endif  // PDF_ENABLE_XFA_TIFF
+
+  return FXCODEC_IMAGE_UNKNOWN;
+}
+
+RetainPtr<CFX_DIBitmap> XFA_LoadImageData(CXFA_FFDoc* pDoc,
+                                          CXFA_Image* pImage,
+                                          bool& bNameImage,
+                                          int32_t& iImageXDpi,
+                                          int32_t& iImageYDpi) {
+  WideString wsHref = pImage->GetHref();
+  WideString wsImage = pImage->GetContent();
+  if (wsHref.IsEmpty() && wsImage.IsEmpty())
+    return nullptr;
+
+  FXCODEC_IMAGE_TYPE type = XFA_GetImageType(pImage->GetContentType());
+  ByteString bsData;  // Must outlive |pImageFileRead|.
+  std::vector<uint8_t> buffer;  // Must outlive |pImageFileRead|.
+  RetainPtr<IFX_SeekableReadStream> pImageFileRead;
+  if (wsImage.GetLength() > 0) {
+    XFA_AttributeValue iEncoding = pImage->GetTransferEncoding();
+    if (iEncoding == XFA_AttributeValue::Base64) {
+      bsData = wsImage.ToUTF8();
+      buffer = XFA_Base64Decode(bsData);
+      if (!buffer.empty())
+        pImageFileRead = pdfium::MakeRetain<CFX_ReadOnlyMemoryStream>(buffer);
+    } else {
+      bsData = wsImage.ToDefANSI();
+      pImageFileRead =
+          pdfium::MakeRetain<CFX_ReadOnlyMemoryStream>(bsData.raw_span());
+    }
+  } else {
+    WideString wsURL = wsHref;
+    if (!(wsURL.First(7).EqualsASCII("http://") ||
+          wsURL.First(6).EqualsASCII("ftp://"))) {
+      RetainPtr<CFX_DIBitmap> pBitmap =
+          pDoc->GetPDFNamedImage(wsURL.AsStringView(), iImageXDpi, iImageYDpi);
+      if (pBitmap) {
+        bNameImage = true;
+        return pBitmap;
+      }
+    }
+    pImageFileRead = pDoc->GetDocEnvironment()->OpenLinkedFile(pDoc, wsURL);
+  }
+  if (!pImageFileRead)
+    return nullptr;
+
+  bNameImage = false;
+  RetainPtr<CFX_DIBitmap> pBitmap =
+      XFA_LoadImageFromBuffer(pImageFileRead, type, iImageXDpi, iImageYDpi);
+  return pBitmap;
+}
+
+bool SplitDateTime(const WideString& wsDateTime,
+                   WideString& wsDate,
+                   WideString& wsTime) {
+  wsDate.clear();
+  wsTime.clear();
+  if (wsDateTime.IsEmpty())
+    return false;
+
+  auto nSplitIndex = wsDateTime.Find('T');
+  if (!nSplitIndex.has_value())
+    nSplitIndex = wsDateTime.Find(' ');
+  if (!nSplitIndex.has_value())
+    return false;
+
+  wsDate = wsDateTime.First(nSplitIndex.value());
+  if (!wsDate.IsEmpty()) {
+    if (!std::any_of(wsDate.begin(), wsDate.end(),
+                     [](wchar_t c) { return FXSYS_IsDecimalDigit(c); })) {
+      return false;
+    }
+  }
+  wsTime = wsDateTime.Last(wsDateTime.GetLength() - nSplitIndex.value() - 1);
+  if (!wsTime.IsEmpty()) {
+    if (!std::any_of(wsTime.begin(), wsTime.end(),
+                     [](wchar_t c) { return FXSYS_IsDecimalDigit(c); })) {
+      return false;
+    }
+  }
+  return true;
+}
+
 std::vector<CXFA_Node*> NodesSortedByDocumentIdx(
     const std::set<CXFA_Node*>& rgNodeSet) {
   if (rgNodeSet.empty())
@@ -141,8 +623,8 @@
           pBeforeNode = pLastNode->GetNextSibling();
         }
         for (auto* pCurNode : rgNodeArray1) {
-          pParentNode->RemoveChild(pCurNode, true);
-          pParentNode->InsertChild(pCurNode, pBeforeNode);
+          pParentNode->RemoveChildAndNotify(pCurNode, true);
+          pParentNode->InsertChildAndNotify(pCurNode, pBeforeNode);
         }
       }
     }
@@ -150,84 +632,336 @@
   }
 }
 
+float GetEdgeThickness(const std::vector<CXFA_Stroke*>& strokes,
+                       bool b3DStyle,
+                       int32_t nIndex) {
+  float fThickness = 0.0f;
+  CXFA_Stroke* stroke = strokes[nIndex * 2 + 1];
+  if (stroke->IsVisible()) {
+    if (nIndex == 0)
+      fThickness += 2.5f;
+
+    fThickness += stroke->GetThickness() * (b3DStyle ? 4 : 2);
+  }
+  return fThickness;
+}
+
+WideString FormatNumStr(const WideString& wsValue, LocaleIface* pLocale) {
+  if (wsValue.IsEmpty())
+    return WideString();
+
+  WideString wsSrcNum = wsValue;
+  WideString wsGroupSymbol = pLocale->GetGroupingSymbol();
+  bool bNeg = false;
+  if (wsSrcNum[0] == '-') {
+    bNeg = true;
+    wsSrcNum.Delete(0, 1);
+  }
+
+  auto dot_index = wsSrcNum.Find('.');
+  dot_index = !dot_index.has_value() ? wsSrcNum.GetLength() : dot_index;
+
+  if (dot_index.value() < 1)
+    return WideString();
+
+  size_t nPos = dot_index.value() % 3;
+  WideString wsOutput;
+  for (size_t i = 0; i < dot_index.value(); i++) {
+    if (i % 3 == nPos && i != 0)
+      wsOutput += wsGroupSymbol;
+
+    wsOutput += wsSrcNum[i];
+  }
+  if (dot_index.value() < wsSrcNum.GetLength()) {
+    wsOutput += pLocale->GetDecimalSymbol();
+    wsOutput += wsSrcNum.Last(wsSrcNum.GetLength() - dot_index.value() - 1);
+  }
+  if (bNeg)
+    return pLocale->GetMinusSymbol() + wsOutput;
+
+  return wsOutput;
+}
+
+CXFA_Node* FindFirstSiblingNamedInList(CXFA_Node* parent,
+                                       uint32_t dwNameHash,
+                                       uint32_t dwFilter);
+CXFA_Node* FindFirstSiblingOfClassInList(CXFA_Node* parent,
+                                         XFA_Element element,
+                                         uint32_t dwFilter);
+
+CXFA_Node* FindFirstSiblingNamed(CXFA_Node* parent, uint32_t dwNameHash) {
+  CXFA_Node* result = FindFirstSiblingNamedInList(parent, dwNameHash,
+                                                  XFA_NODEFILTER_Properties);
+  if (result)
+    return result;
+
+  return FindFirstSiblingNamedInList(parent, dwNameHash,
+                                     XFA_NODEFILTER_Children);
+}
+
+CXFA_Node* FindFirstSiblingNamedInList(CXFA_Node* parent,
+                                       uint32_t dwNameHash,
+                                       uint32_t dwFilter) {
+  for (CXFA_Node* child : parent->GetNodeListWithFilter(dwFilter)) {
+    if (child->GetNameHash() == dwNameHash)
+      return child;
+
+    CXFA_Node* result = FindFirstSiblingNamed(child, dwNameHash);
+    if (result)
+      return result;
+  }
+  return nullptr;
+}
+
+CXFA_Node* FindFirstSiblingOfClass(CXFA_Node* parent, XFA_Element element) {
+  CXFA_Node* result =
+      FindFirstSiblingOfClassInList(parent, element, XFA_NODEFILTER_Properties);
+  if (result)
+    return result;
+
+  return FindFirstSiblingOfClassInList(parent, element,
+                                       XFA_NODEFILTER_Children);
+}
+
+CXFA_Node* FindFirstSiblingOfClassInList(CXFA_Node* parent,
+                                         XFA_Element element,
+                                         uint32_t dwFilter) {
+  for (CXFA_Node* child : parent->GetNodeListWithFilter(dwFilter)) {
+    if (child->GetElementType() == element)
+      return child;
+
+    CXFA_Node* result = FindFirstSiblingOfClass(child, element);
+    if (result)
+      return result;
+  }
+  return nullptr;
+}
+
+WideString GetNameExpressionSinglePath(CXFA_Node* pNode) {
+  const bool bIsProperty = pNode->IsProperty();
+  const bool bIsClassIndex =
+      pNode->IsUnnamed() ||
+      (bIsProperty && pNode->GetElementType() != XFA_Element::PageSet);
+  const wchar_t* pszFormat;
+  WideString ws;
+  if (bIsClassIndex) {
+    pszFormat = L"#%ls[%zu]";
+    ws = WideString::FromASCII(pNode->GetClassName());
+  } else {
+    pszFormat = L"%ls[%zu]";
+    ws = pNode->JSObject()->GetCData(XFA_Attribute::Name);
+    ws.Replace(L".", L"\\.");
+  }
+
+  return WideString::Format(pszFormat, ws.c_str(),
+                            pNode->GetIndex(bIsProperty, bIsClassIndex));
+}
+
+void TraverseSiblings(CXFA_Node* parent,
+                      uint32_t dwNameHash,
+                      std::vector<CXFA_Node*>* pSiblings,
+                      bool bIsClassName,
+                      bool bIsFindProperty) {
+  ASSERT(parent);
+  ASSERT(pSiblings);
+
+  if (bIsFindProperty) {
+    for (CXFA_Node* child :
+         parent->GetNodeListWithFilter(XFA_NODEFILTER_Properties)) {
+      if (bIsClassName) {
+        if (child->GetClassHashCode() == dwNameHash)
+          pSiblings->push_back(child);
+      } else {
+        if (child->GetNameHash() == dwNameHash) {
+          if (child->GetElementType() != XFA_Element::PageSet &&
+              child->GetElementType() != XFA_Element::Extras &&
+              child->GetElementType() != XFA_Element::Items) {
+            pSiblings->push_back(child);
+          }
+        }
+      }
+      if (child->IsUnnamed() &&
+          child->GetElementType() == XFA_Element::PageSet) {
+        TraverseSiblings(child, dwNameHash, pSiblings, bIsClassName, false);
+      }
+    }
+    if (!pSiblings->empty())
+      return;
+  }
+  for (CXFA_Node* child :
+       parent->GetNodeListWithFilter(XFA_NODEFILTER_Children)) {
+    if (child->GetElementType() == XFA_Element::Variables)
+      continue;
+
+    if (bIsClassName) {
+      if (child->GetClassHashCode() == dwNameHash)
+        pSiblings->push_back(child);
+    } else {
+      if (child->GetNameHash() == dwNameHash)
+        pSiblings->push_back(child);
+    }
+
+    if (child->IsTransparent() &&
+        child->GetElementType() != XFA_Element::PageSet) {
+      TraverseSiblings(child, dwNameHash, pSiblings, bIsClassName, false);
+    }
+  }
+}
+
 }  // namespace
 
-// static
-WideString CXFA_Node::AttributeEnumToName(XFA_AttributeEnum item) {
-  return g_XFAEnumData[static_cast<int32_t>(item)].pName;
-}
+class CXFA_WidgetLayoutData {
+ public:
+  CXFA_WidgetLayoutData() = default;
+  virtual ~CXFA_WidgetLayoutData() = default;
 
-// static
-Optional<XFA_AttributeEnum> CXFA_Node::NameToAttributeEnum(
-    const WideStringView& name) {
-  if (name.IsEmpty())
-    return {};
+  virtual CXFA_FieldLayoutData* AsFieldLayoutData() { return nullptr; }
+  virtual CXFA_ImageLayoutData* AsImageLayoutData() { return nullptr; }
+  virtual CXFA_TextLayoutData* AsTextLayoutData() { return nullptr; }
 
-  auto* it = std::lower_bound(g_XFAEnumData, g_XFAEnumData + g_iXFAEnumCount,
-                              FX_HashCode_GetW(name, false),
-                              [](const XFA_AttributeEnumInfo& arg,
-                                 uint32_t hash) { return arg.uHash < hash; });
-  if (it != g_XFAEnumData + g_iXFAEnumCount && name == it->pName)
-    return {it->eName};
-  return {};
-}
+  float m_fWidgetHeight = -1.0f;
+};
+
+class CXFA_TextLayoutData final : public CXFA_WidgetLayoutData {
+ public:
+  CXFA_TextLayoutData() = default;
+  ~CXFA_TextLayoutData() override = default;
+
+  CXFA_TextLayoutData* AsTextLayoutData() override { return this; }
+
+  CXFA_TextLayout* GetTextLayout() const { return m_pTextLayout.get(); }
+  CXFA_TextProvider* GetTextProvider() const { return m_pTextProvider.get(); }
+
+  void LoadText(CXFA_FFDoc* doc, CXFA_Node* pNode) {
+    if (m_pTextLayout)
+      return;
+
+    m_pTextProvider =
+        pdfium::MakeUnique<CXFA_TextProvider>(pNode, XFA_TEXTPROVIDERTYPE_Text);
+    m_pTextLayout =
+        pdfium::MakeUnique<CXFA_TextLayout>(doc, m_pTextProvider.get());
+  }
+
+ private:
+  std::unique_ptr<CXFA_TextLayout> m_pTextLayout;
+  std::unique_ptr<CXFA_TextProvider> m_pTextProvider;
+};
+
+class CXFA_ImageLayoutData final : public CXFA_WidgetLayoutData {
+ public:
+  CXFA_ImageLayoutData() = default;
+  ~CXFA_ImageLayoutData() override = default;
+
+  CXFA_ImageLayoutData* AsImageLayoutData() override { return this; }
+
+  bool LoadImageData(CXFA_FFDoc* doc, CXFA_Node* pNode) {
+    if (m_pDIBitmap)
+      return true;
+
+    CXFA_Value* value = pNode->GetFormValueIfExists();
+    if (!value)
+      return false;
+
+    CXFA_Image* image = value->GetImageIfExists();
+    if (!image)
+      return false;
+
+    pNode->SetImageImage(XFA_LoadImageData(doc, image, m_bNamedImage,
+                                           m_iImageXDpi, m_iImageYDpi));
+    return !!m_pDIBitmap;
+  }
+
+  bool m_bNamedImage = false;
+  int32_t m_iImageXDpi = 0;
+  int32_t m_iImageYDpi = 0;
+  RetainPtr<CFX_DIBitmap> m_pDIBitmap;
+};
+
+class CXFA_FieldLayoutData : public CXFA_WidgetLayoutData {
+ public:
+  CXFA_FieldLayoutData() = default;
+  ~CXFA_FieldLayoutData() override = default;
+
+  CXFA_FieldLayoutData* AsFieldLayoutData() override { return this; }
+
+  virtual CXFA_ImageEditData* AsImageEditData() { return nullptr; }
+  virtual CXFA_TextEditData* AsTextEditData() { return nullptr; }
+
+  bool LoadCaption(CXFA_FFDoc* doc, CXFA_Node* pNode) {
+    if (m_pCapTextLayout)
+      return true;
+    CXFA_Caption* caption = pNode->GetCaptionIfExists();
+    if (!caption || caption->IsHidden())
+      return false;
+
+    m_pCapTextProvider = pdfium::MakeUnique<CXFA_TextProvider>(
+        pNode, XFA_TEXTPROVIDERTYPE_Caption);
+    m_pCapTextLayout =
+        pdfium::MakeUnique<CXFA_TextLayout>(doc, m_pCapTextProvider.get());
+    return true;
+  }
+
+  std::unique_ptr<CXFA_TextLayout> m_pCapTextLayout;
+  std::unique_ptr<CXFA_TextProvider> m_pCapTextProvider;
+  std::unique_ptr<CFDE_TextOut> m_pTextOut;
+  std::vector<float> m_FieldSplitArray;
+};
+
+class CXFA_TextEditData final : public CXFA_FieldLayoutData {
+ public:
+  CXFA_TextEditData() = default;
+  ~CXFA_TextEditData() override = default;
+
+  CXFA_TextEditData* AsTextEditData() override { return this; }
+};
+
+class CXFA_ImageEditData final : public CXFA_FieldLayoutData {
+ public:
+  CXFA_ImageEditData() = default;
+  ~CXFA_ImageEditData() override = default;
+
+  CXFA_ImageEditData* AsImageEditData() override { return this; }
+
+  bool LoadImageData(CXFA_FFDoc* doc, CXFA_Node* pNode) {
+    if (m_pDIBitmap)
+      return true;
+
+    CXFA_Value* value = pNode->GetFormValueIfExists();
+    if (!value)
+      return false;
+
+    CXFA_Image* image = value->GetImageIfExists();
+    if (!image)
+      return false;
+
+    pNode->SetImageEditImage(XFA_LoadImageData(doc, image, m_bNamedImage,
+                                               m_iImageXDpi, m_iImageYDpi));
+    return !!m_pDIBitmap;
+  }
+
+  bool m_bNamedImage = false;
+  int32_t m_iImageXDpi = 0;
+  int32_t m_iImageYDpi = 0;
+  RetainPtr<CFX_DIBitmap> m_pDIBitmap;
+};
 
 CXFA_Node::CXFA_Node(CXFA_Document* pDoc,
                      XFA_PacketType ePacket,
                      uint32_t validPackets,
                      XFA_ObjectType oType,
                      XFA_Element eType,
-                     const PropertyData* properties,
-                     const AttributeData* attributes,
-                     const WideStringView& elementName,
-                     std::unique_ptr<CJX_Object> js_node)
-    : CXFA_Object(pDoc, oType, eType, elementName, std::move(js_node)),
+                     pdfium::span<const PropertyData> properties,
+                     pdfium::span<const AttributeData> attributes,
+                     std::unique_ptr<CJX_Object> js_object)
+    : CXFA_Object(pDoc, oType, eType, std::move(js_object)),
       m_Properties(properties),
       m_Attributes(attributes),
       m_ValidPackets(validPackets),
-      m_pNext(nullptr),
-      m_pChild(nullptr),
-      m_pLastChild(nullptr),
-      m_pParent(nullptr),
-      m_pXMLNode(nullptr),
-      m_ePacket(ePacket),
-      m_uNodeFlags(XFA_NodeFlag_None),
-      m_dwNameHash(0),
-      m_pAuxNode(nullptr) {
+      m_ePacket(ePacket) {
   ASSERT(m_pDocument);
 }
 
-CXFA_Node::CXFA_Node(CXFA_Document* pDoc,
-                     XFA_PacketType ePacket,
-                     uint32_t validPackets,
-                     XFA_ObjectType oType,
-                     XFA_Element eType,
-                     const PropertyData* properties,
-                     const AttributeData* attributes,
-                     const WideStringView& elementName)
-    : CXFA_Node(pDoc,
-                ePacket,
-                validPackets,
-                oType,
-                eType,
-                properties,
-                attributes,
-                elementName,
-                pdfium::MakeUnique<CJX_Node>(this)) {}
-
-CXFA_Node::~CXFA_Node() {
-  ASSERT(!m_pParent);
-
-  CXFA_Node* pNode = m_pChild;
-  while (pNode) {
-    CXFA_Node* pNext = pNode->m_pNext;
-    pNode->m_pParent = nullptr;
-    delete pNode;
-    pNode = pNext;
-  }
-  if (m_pXMLNode && IsOwnXMLNode())
-    delete m_pXMLNode;
-}
+CXFA_Node::~CXFA_Node() = default;
 
 CXFA_Node* CXFA_Node::Clone(bool bRecursive) {
   CXFA_Node* pClone = m_pDocument->CreateNode(m_ePacket, m_elementType);
@@ -237,80 +971,69 @@
   JSObject()->MergeAllData(pClone);
   pClone->UpdateNameHash();
   if (IsNeedSavingXMLNode()) {
-    std::unique_ptr<CFX_XMLNode> pCloneXML;
+    CFX_XMLNode* pCloneXML;
     if (IsAttributeInXML()) {
       WideString wsName = JSObject()
                               ->TryAttribute(XFA_Attribute::Name, false)
                               .value_or(WideString());
-      auto pCloneXMLElement = pdfium::MakeUnique<CFX_XMLElement>(wsName);
-      WideString wsValue = JSObject()->GetCData(XFA_Attribute::Value);
-      if (!wsValue.IsEmpty())
-        pCloneXMLElement->SetTextData(WideString(wsValue));
+      auto* pCloneXMLElement =
+          GetXMLDocument()->CreateNode<CFX_XMLElement>(wsName);
 
-      pCloneXML.reset(pCloneXMLElement.release());
+      WideString wsValue = JSObject()->GetCData(XFA_Attribute::Value);
+      if (!wsValue.IsEmpty()) {
+        auto* text = GetXMLDocument()->CreateNode<CFX_XMLText>(wsValue);
+        pCloneXMLElement->AppendLastChild(text);
+      }
+
+      pCloneXML = pCloneXMLElement;
       pClone->JSObject()->SetEnum(XFA_Attribute::Contains,
-                                  XFA_AttributeEnum::Unknown, false);
+                                  XFA_AttributeValue::Unknown, false);
     } else {
-      pCloneXML = m_pXMLNode->Clone();
+      pCloneXML = xml_node_->Clone(GetXMLDocument());
     }
-    pClone->SetXMLMappingNode(pCloneXML.release());
-    pClone->SetFlag(XFA_NodeFlag_OwnXMLNode, false);
+    pClone->SetXMLMappingNode(pCloneXML);
   }
   if (bRecursive) {
     for (CXFA_Node* pChild = GetFirstChild(); pChild;
          pChild = pChild->GetNextSibling()) {
-      pClone->InsertChild(pChild->Clone(bRecursive), nullptr);
+      pClone->InsertChildAndNotify(pChild->Clone(bRecursive), nullptr);
     }
   }
-  pClone->SetFlag(XFA_NodeFlag_Initialized, true);
+  pClone->SetFlagAndNotify(XFA_NodeFlag_Initialized);
   pClone->SetBindingNode(nullptr);
   return pClone;
 }
 
-CXFA_Node* CXFA_Node::GetPrevSibling() const {
-  if (!m_pParent || m_pParent->m_pChild == this)
-    return nullptr;
-
-  for (CXFA_Node* pNode = m_pParent->m_pChild; pNode; pNode = pNode->m_pNext) {
-    if (pNode->m_pNext == this)
+CXFA_Node* CXFA_Node::GetNextContainerSibling() const {
+  for (auto* pNode = GetNextSibling(); pNode; pNode = pNode->GetNextSibling()) {
+    if (pNode->GetObjectType() == XFA_ObjectType::ContainerNode)
       return pNode;
   }
   return nullptr;
 }
 
-CXFA_Node* CXFA_Node::GetNextContainerSibling() const {
-  CXFA_Node* pNode = m_pNext;
-  while (pNode && pNode->GetObjectType() != XFA_ObjectType::ContainerNode)
-    pNode = pNode->m_pNext;
-  return pNode;
-}
-
 CXFA_Node* CXFA_Node::GetPrevContainerSibling() const {
-  if (!m_pParent || m_pParent->m_pChild == this)
-    return nullptr;
-
-  CXFA_Node* container = nullptr;
-  for (CXFA_Node* pNode = m_pParent->m_pChild; pNode; pNode = pNode->m_pNext) {
+  for (auto* pNode = GetPrevSibling(); pNode; pNode = pNode->GetPrevSibling()) {
     if (pNode->GetObjectType() == XFA_ObjectType::ContainerNode)
-      container = pNode;
-    if (pNode->m_pNext == this)
-      return container;
+      return pNode;
   }
   return nullptr;
 }
 
 CXFA_Node* CXFA_Node::GetFirstContainerChild() const {
-  CXFA_Node* pNode = m_pChild;
-  while (pNode && pNode->GetObjectType() != XFA_ObjectType::ContainerNode)
-    pNode = pNode->m_pNext;
-  return pNode;
+  for (auto* pNode = GetFirstChild(); pNode; pNode = pNode->GetNextSibling()) {
+    if (pNode->GetObjectType() == XFA_ObjectType::ContainerNode)
+      return pNode;
+  }
+  return nullptr;
 }
 
 CXFA_Node* CXFA_Node::GetContainerParent() const {
-  CXFA_Node* pNode = m_pParent;
-  while (pNode && pNode->GetObjectType() != XFA_ObjectType::ContainerNode)
-    pNode = pNode->m_pParent;
-  return pNode;
+  for (auto* pNode = GetParent(); pNode; pNode = pNode->GetParent()) {
+    if (pNode->GetObjectType() == XFA_ObjectType::ContainerNode)
+      return pNode;
+  }
+  return nullptr;
 }
 
 bool CXFA_Node::IsValidInPacket(XFA_PacketType packet) const {
@@ -319,15 +1042,10 @@
 
 const CXFA_Node::PropertyData* CXFA_Node::GetPropertyData(
     XFA_Element property) const {
-  if (m_Properties == nullptr)
-    return nullptr;
-
-  for (size_t i = 0;; ++i) {
-    const PropertyData* data = m_Properties + i;
-    if (data->property == XFA_Element::Unknown)
-      break;
-    if (data->property == property)
-      return data;
+  ASSERT(property != XFA_Element::Unknown);
+  for (const auto& prop : m_Properties) {
+    if (prop.property == property)
+      return &prop;
   }
   return nullptr;
 }
@@ -346,31 +1064,70 @@
   return data ? data->occurance_count : 0;
 }
 
-Optional<XFA_Element> CXFA_Node::GetFirstPropertyWithFlag(uint8_t flag) {
-  if (m_Properties == nullptr)
-    return {};
+std::pair<CXFA_Node*, int32_t> CXFA_Node::GetProperty(
+    int32_t index,
+    XFA_Element eProperty) const {
+  if (index < 0 || index >= PropertyOccuranceCount(eProperty))
+    return {nullptr, 0};
 
-  for (size_t i = 0;; ++i) {
-    const PropertyData* data = m_Properties + i;
-    if (data->property == XFA_Element::Unknown)
-      break;
-    if (data->flags & flag)
-      return {data->property};
+  int32_t iCount = 0;
+  for (CXFA_Node* pNode = GetFirstChild(); pNode;
+       pNode = pNode->GetNextSibling()) {
+    if (pNode->GetElementType() == eProperty) {
+      iCount++;
+      if (iCount > index)
+        return {pNode, iCount};
+    }
+  }
+  return {nullptr, iCount};
+}
+
+CXFA_Node* CXFA_Node::GetOrCreateProperty(int32_t index,
+                                          XFA_Element eProperty) {
+  if (index < 0 || index >= PropertyOccuranceCount(eProperty))
+    return nullptr;
+
+  int32_t iCount = 0;
+  CXFA_Node* node;
+  std::tie(node, iCount) = GetProperty(index, eProperty);
+  if (node)
+    return node;
+
+  if (HasPropertyFlags(eProperty, XFA_PROPERTYFLAG_OneOf)) {
+    for (CXFA_Node* pNode = GetFirstChild(); pNode;
+         pNode = pNode->GetNextSibling()) {
+      if (HasPropertyFlags(pNode->GetElementType(), XFA_PROPERTYFLAG_OneOf)) {
+        return nullptr;
+      }
+    }
+  }
+
+  CXFA_Node* pNewNode = nullptr;
+  for (; iCount <= index; ++iCount) {
+    pNewNode = GetDocument()->CreateNode(GetPacketType(), eProperty);
+    if (!pNewNode)
+      return nullptr;
+
+    InsertChildAndNotify(pNewNode, nullptr);
+    pNewNode->SetFlagAndNotify(XFA_NodeFlag_Initialized);
+  }
+  return pNewNode;
+}
+
+Optional<XFA_Element> CXFA_Node::GetFirstPropertyWithFlag(uint8_t flag) const {
+  for (const auto& prop : m_Properties) {
+    if (prop.flags & flag)
+      return prop.property;
   }
   return {};
 }
 
 const CXFA_Node::AttributeData* CXFA_Node::GetAttributeData(
     XFA_Attribute attr) const {
-  if (m_Attributes == nullptr)
-    return nullptr;
-
-  for (size_t i = 0;; ++i) {
-    const AttributeData* cur_attr = &m_Attributes[i];
-    if (cur_attr->attribute == XFA_Attribute::Unknown)
-      break;
-    if (cur_attr->attribute == attr)
-      return cur_attr;
+  ASSERT(attr != XFA_Attribute::Unknown);
+  for (const auto& cur_attr : m_Attributes) {
+    if (cur_attr.attribute == attr)
+      return &cur_attr;
   }
   return nullptr;
 }
@@ -379,11 +1136,9 @@
   return !!GetAttributeData(attr);
 }
 
-// Note: This Method assumes that i is a valid index ....
 XFA_Attribute CXFA_Node::GetAttribute(size_t i) const {
-  if (m_Attributes == nullptr)
-    return XFA_Attribute::Unknown;
-  return m_Attributes[i].attribute;
+  return i < m_Attributes.size() ? m_Attributes[i].attribute
+                                 : XFA_Attribute::Unknown;
 }
 
 XFA_AttributeType CXFA_Node::GetAttributeType(XFA_Attribute type) const {
@@ -391,33 +1146,35 @@
   return data ? data->type : XFA_AttributeType::CData;
 }
 
-std::vector<CXFA_Node*> CXFA_Node::GetNodeList(uint32_t dwTypeFilter,
-                                               XFA_Element eTypeFilter) {
-  if (eTypeFilter != XFA_Element::Unknown) {
-    std::vector<CXFA_Node*> nodes;
-    for (CXFA_Node* pChild = m_pChild; pChild; pChild = pChild->m_pNext) {
-      if (pChild->GetElementType() == eTypeFilter)
-        nodes.push_back(pChild);
-    }
-    return nodes;
+std::vector<CXFA_Node*> CXFA_Node::GetNodeListForType(XFA_Element eTypeFilter) {
+  std::vector<CXFA_Node*> nodes;
+  for (CXFA_Node* pChild = GetFirstChild(); pChild;
+       pChild = pChild->GetNextSibling()) {
+    if (pChild->GetElementType() == eTypeFilter)
+      nodes.push_back(pChild);
   }
+  return nodes;
+}
 
+std::vector<CXFA_Node*> CXFA_Node::GetNodeListWithFilter(
+    uint32_t dwTypeFilter) {
+  std::vector<CXFA_Node*> nodes;
   if (dwTypeFilter == (XFA_NODEFILTER_Children | XFA_NODEFILTER_Properties)) {
-    std::vector<CXFA_Node*> nodes;
-    for (CXFA_Node* pChild = m_pChild; pChild; pChild = pChild->m_pNext)
+    for (CXFA_Node* pChild = GetFirstChild(); pChild;
+         pChild = pChild->GetNextSibling())
       nodes.push_back(pChild);
     return nodes;
   }
 
   if (dwTypeFilter == 0)
-    return std::vector<CXFA_Node*>();
+    return nodes;
 
   bool bFilterChildren = !!(dwTypeFilter & XFA_NODEFILTER_Children);
   bool bFilterProperties = !!(dwTypeFilter & XFA_NODEFILTER_Properties);
   bool bFilterOneOfProperties = !!(dwTypeFilter & XFA_NODEFILTER_OneOfProperty);
-  std::vector<CXFA_Node*> nodes;
-  for (CXFA_Node* pChild = m_pChild; pChild; pChild = pChild->m_pNext) {
-    if (!HasProperty(pChild->GetElementType())) {
+  for (CXFA_Node* pChild = GetFirstChild(); pChild;
+       pChild = pChild->GetNextSibling()) {
+    if (HasProperty(pChild->GetElementType())) {
       if (bFilterProperties) {
         nodes.push_back(pChild);
       } else if (bFilterOneOfProperties &&
@@ -436,18 +1193,17 @@
 
   if (!bFilterOneOfProperties || !nodes.empty())
     return nodes;
-  if (m_Properties == nullptr)
-    return nodes;
 
   Optional<XFA_Element> property =
       GetFirstPropertyWithFlag(XFA_PROPERTYFLAG_DefaultOneOf);
-  if (!property)
+  if (!property.has_value())
     return nodes;
 
-  CXFA_Node* pNewNode = m_pDocument->CreateNode(GetPacketType(), *property);
+  CXFA_Node* pNewNode =
+      m_pDocument->CreateNode(GetPacketType(), property.value());
   if (pNewNode) {
-    InsertChild(pNewNode, nullptr);
-    pNewNode->SetFlag(XFA_NodeFlag_Initialized, true);
+    InsertChildAndNotify(pNewNode, nullptr);
+    pNewNode->SetFlagAndNotify(XFA_NodeFlag_Initialized);
     nodes.push_back(pNewNode);
   }
   return nodes;
@@ -455,7 +1211,10 @@
 
 CXFA_Node* CXFA_Node::CreateSamePacketNode(XFA_Element eType) {
   CXFA_Node* pNode = m_pDocument->CreateNode(m_ePacket, eType);
-  pNode->SetFlag(XFA_NodeFlag_Initialized, true);
+  if (!pNode)
+    return nullptr;
+
+  pNode->SetFlagAndNotify(XFA_NodeFlag_Initialized);
   return pNode;
 }
 
@@ -472,10 +1231,11 @@
   if (bRecursive) {
     for (CXFA_Node* pChild = GetFirstChild(); pChild;
          pChild = pChild->GetNextSibling()) {
-      pClone->InsertChild(pChild->CloneTemplateToForm(bRecursive), nullptr);
+      pClone->InsertChildAndNotify(pChild->CloneTemplateToForm(bRecursive),
+                                   nullptr);
     }
   }
-  pClone->SetFlag(XFA_NodeFlag_Initialized, true);
+  pClone->SetFlagAndNotify(XFA_NodeFlag_Initialized);
   return pClone;
 }
 
@@ -492,17 +1252,13 @@
   return GetBindingNode();
 }
 
-std::vector<UnownedPtr<CXFA_Node>>* CXFA_Node::GetBindItems() {
-  return GetBindingNodes();
-}
-
 int32_t CXFA_Node::AddBindItem(CXFA_Node* pFormNode) {
   ASSERT(pFormNode);
 
   if (BindsFormItems()) {
     bool found = false;
-    for (auto& v : binding_nodes_) {
-      if (v.Get() == pFormNode) {
+    for (auto* v : binding_nodes_) {
+      if (v == pFormNode) {
         found = true;
         break;
       }
@@ -520,10 +1276,10 @@
   if (pOldFormItem == pFormNode)
     return 1;
 
-  std::vector<UnownedPtr<CXFA_Node>> items;
-  items.emplace_back(pOldFormItem);
-  items.emplace_back(pFormNode);
-  SetBindingNodes(std::move(items));
+  std::vector<CXFA_Node*> items;
+  items.push_back(pOldFormItem);
+  items.push_back(pFormNode);
+  binding_nodes_ = std::move(items);
 
   m_uNodeFlags |= XFA_NodeFlag_BindFormItems;
   return 2;
@@ -531,10 +1287,8 @@
 
 int32_t CXFA_Node::RemoveBindItem(CXFA_Node* pFormNode) {
   if (BindsFormItems()) {
-    auto it = std::find_if(binding_nodes_.begin(), binding_nodes_.end(),
-                           [&pFormNode](const UnownedPtr<CXFA_Node>& node) {
-                             return node.Get() == pFormNode;
-                           });
+    auto it =
+        std::find(binding_nodes_.begin(), binding_nodes_.end(), pFormNode);
     if (it != binding_nodes_.end())
       binding_nodes_.erase(it);
 
@@ -553,11 +1307,11 @@
   return 0;
 }
 
-bool CXFA_Node::HasBindItem() {
+bool CXFA_Node::HasBindItem() const {
   return GetPacketType() == XFA_PacketType::Datasets && GetBindingNode();
 }
 
-CXFA_WidgetAcc* CXFA_Node::GetContainerWidgetAcc() {
+CXFA_Node* CXFA_Node::GetContainerNode() {
   if (GetPacketType() != XFA_PacketType::Form)
     return nullptr;
   XFA_Element eType = GetElementType();
@@ -568,34 +1322,30 @@
     return nullptr;
 
   if (eType == XFA_Element::Field) {
-    CXFA_WidgetAcc* pFieldWidgetAcc = GetWidgetAcc();
-    if (pFieldWidgetAcc && pFieldWidgetAcc->IsChoiceListMultiSelect())
+    if (IsChoiceListMultiSelect())
       return nullptr;
 
-    WideString wsPicture;
-    if (pFieldWidgetAcc) {
-      wsPicture = pFieldWidgetAcc->GetPictureContent(XFA_VALUEPICTURE_DataBind);
-    }
+    WideString wsPicture = GetPictureContent(XFA_VALUEPICTURE_DataBind);
     if (!wsPicture.IsEmpty())
-      return pFieldWidgetAcc;
+      return this;
 
     CXFA_Node* pDataNode = GetBindData();
     if (!pDataNode)
       return nullptr;
-    pFieldWidgetAcc = nullptr;
-    for (const auto& pFormNode : *(pDataNode->GetBindItems())) {
+
+    CXFA_Node* pFieldNode = nullptr;
+    for (auto* pFormNode : pDataNode->GetBindItemsCopy()) {
       if (!pFormNode || pFormNode->HasRemovedChildren())
         continue;
-      pFieldWidgetAcc = pFormNode->GetWidgetAcc();
-      if (pFieldWidgetAcc) {
-        wsPicture =
-            pFieldWidgetAcc->GetPictureContent(XFA_VALUEPICTURE_DataBind);
-      }
+      pFieldNode = pFormNode->IsWidgetReady() ? pFormNode : nullptr;
+      if (pFieldNode)
+        wsPicture = pFieldNode->GetPictureContent(XFA_VALUEPICTURE_DataBind);
       if (!wsPicture.IsEmpty())
         break;
-      pFieldWidgetAcc = nullptr;
+
+      pFieldNode = nullptr;
     }
-    return pFieldWidgetAcc;
+    return pFieldNode;
   }
 
   CXFA_Node* pGrandNode = pParentNode ? pParentNode->GetParent() : nullptr;
@@ -611,24 +1361,27 @@
   }
   CXFA_Node* pParentOfValueNode =
       pValueNode ? pValueNode->GetParent() : nullptr;
-  return pParentOfValueNode ? pParentOfValueNode->GetContainerWidgetAcc()
-                            : nullptr;
+  return pParentOfValueNode ? pParentOfValueNode->GetContainerNode() : nullptr;
 }
 
-IFX_Locale* CXFA_Node::GetLocale() {
+LocaleIface* CXFA_Node::GetLocale() {
   Optional<WideString> localeName = GetLocaleName();
-  if (!localeName)
+  if (!localeName.has_value())
     return nullptr;
-  if (localeName.value() == L"ambient")
-    return GetDocument()->GetLocalMgr()->GetDefLocale();
-  return GetDocument()->GetLocalMgr()->GetLocaleByName(localeName.value());
+  if (localeName.value().EqualsASCII("ambient"))
+    return GetDocument()->GetLocaleMgr()->GetDefLocale();
+  return GetDocument()->GetLocaleMgr()->GetLocaleByName(localeName.value());
 }
 
 Optional<WideString> CXFA_Node::GetLocaleName() {
-  CXFA_Node* pForm = GetDocument()->GetXFAObject(XFA_HASHCODE_Form)->AsNode();
+  CXFA_Node* pForm = ToNode(GetDocument()->GetXFAObject(XFA_HASHCODE_Form));
+  if (!pForm)
+    return {};
+
   CXFA_Subform* pTopSubform =
       pForm->GetFirstChildByClass<CXFA_Subform>(XFA_Element::Subform);
-  ASSERT(pTopSubform);
+  if (!pTopSubform)
+    return {};
 
   CXFA_Node* pLocaleNode = this;
   do {
@@ -641,104 +1394,90 @@
   } while (pLocaleNode && pLocaleNode != pTopSubform);
 
   CXFA_Node* pConfig = ToNode(GetDocument()->GetXFAObject(XFA_HASHCODE_Config));
-  Optional<WideString> localeName = {
-      WideString(GetDocument()->GetLocalMgr()->GetConfigLocaleName(pConfig))};
-  if (localeName && !localeName->IsEmpty())
-    return localeName;
+  WideString wsLocaleName =
+      GetDocument()->GetLocaleMgr()->GetConfigLocaleName(pConfig);
+  if (!wsLocaleName.IsEmpty())
+    return wsLocaleName;
 
   if (pTopSubform) {
-    localeName =
+    Optional<WideString> localeName =
         pTopSubform->JSObject()->TryCData(XFA_Attribute::Locale, false);
     if (localeName)
       return localeName;
   }
 
-  IFX_Locale* pLocale = GetDocument()->GetLocalMgr()->GetDefLocale();
+  LocaleIface* pLocale = GetDocument()->GetLocaleMgr()->GetDefLocale();
   if (!pLocale)
     return {};
 
-  return {pLocale->GetName()};
+  return pLocale->GetName();
 }
 
-XFA_AttributeEnum CXFA_Node::GetIntact() {
+XFA_AttributeValue CXFA_Node::GetIntact() {
   CXFA_Keep* pKeep = GetFirstChildByClass<CXFA_Keep>(XFA_Element::Keep);
-  XFA_AttributeEnum eLayoutType = JSObject()
-                                      ->TryEnum(XFA_Attribute::Layout, true)
-                                      .value_or(XFA_AttributeEnum::Position);
+  auto layout = JSObject()->TryEnum(XFA_Attribute::Layout, true);
+  XFA_AttributeValue eLayoutType =
+      layout.value_or(XFA_AttributeValue::Position);
   if (pKeep) {
-    Optional<XFA_AttributeEnum> intact =
-        pKeep->JSObject()->TryEnum(XFA_Attribute::Intact, false);
-    if (intact) {
-      if (*intact == XFA_AttributeEnum::None &&
-          eLayoutType == XFA_AttributeEnum::Row &&
-          m_pDocument->GetCurVersionMode() < XFA_VERSION_208) {
-        CXFA_Node* pPreviewRow = GetPrevContainerSibling();
-        if (pPreviewRow &&
-            pPreviewRow->JSObject()->GetEnum(XFA_Attribute::Layout) ==
-                XFA_AttributeEnum::Row) {
-          Optional<XFA_AttributeEnum> value =
-              pKeep->JSObject()->TryEnum(XFA_Attribute::Previous, false);
-          if (value && (*value == XFA_AttributeEnum::ContentArea ||
-                        *value == XFA_AttributeEnum::PageArea)) {
-            return XFA_AttributeEnum::ContentArea;
-          }
-
-          CXFA_Keep* pNode =
-              pPreviewRow->GetFirstChildByClass<CXFA_Keep>(XFA_Element::Keep);
-          Optional<XFA_AttributeEnum> ret;
-          if (pNode)
-            ret = pNode->JSObject()->TryEnum(XFA_Attribute::Next, false);
-          if (ret && (*ret == XFA_AttributeEnum::ContentArea ||
-                      *ret == XFA_AttributeEnum::PageArea)) {
-            return XFA_AttributeEnum::ContentArea;
-          }
-        }
-      }
+    Optional<XFA_AttributeValue> intact = GetIntactFromKeep(pKeep, eLayoutType);
+    if (intact)
       return *intact;
-    }
   }
 
   switch (GetElementType()) {
     case XFA_Element::Subform:
       switch (eLayoutType) {
-        case XFA_AttributeEnum::Position:
-        case XFA_AttributeEnum::Row:
-          return XFA_AttributeEnum::ContentArea;
+        case XFA_AttributeValue::Position:
+        case XFA_AttributeValue::Row:
+          return XFA_AttributeValue::ContentArea;
         default:
-          return XFA_AttributeEnum::None;
+          return XFA_AttributeValue::None;
       }
     case XFA_Element::Field: {
       CXFA_Node* parent = GetParent();
       if (!parent || parent->GetElementType() == XFA_Element::PageArea)
-        return XFA_AttributeEnum::ContentArea;
-      if (parent->GetIntact() != XFA_AttributeEnum::None)
-        return XFA_AttributeEnum::ContentArea;
+        return XFA_AttributeValue::ContentArea;
+      if (parent->GetIntact() != XFA_AttributeValue::None)
+        return XFA_AttributeValue::ContentArea;
 
-      XFA_AttributeEnum eParLayout = parent->JSObject()
-                                         ->TryEnum(XFA_Attribute::Layout, true)
-                                         .value_or(XFA_AttributeEnum::Position);
-      if (eParLayout == XFA_AttributeEnum::Position ||
-          eParLayout == XFA_AttributeEnum::Row ||
-          eParLayout == XFA_AttributeEnum::Table) {
-        return XFA_AttributeEnum::None;
+      auto value = parent->JSObject()->TryEnum(XFA_Attribute::Layout, true);
+      XFA_AttributeValue eParLayout =
+          value.value_or(XFA_AttributeValue::Position);
+      if (eParLayout == XFA_AttributeValue::Position ||
+          eParLayout == XFA_AttributeValue::Row ||
+          eParLayout == XFA_AttributeValue::Table) {
+        return XFA_AttributeValue::None;
       }
 
       XFA_VERSION version = m_pDocument->GetCurVersionMode();
-      if (eParLayout == XFA_AttributeEnum::Tb && version < XFA_VERSION_208) {
+      if (eParLayout == XFA_AttributeValue::Tb && version < XFA_VERSION_208) {
         Optional<CXFA_Measurement> measureH =
             JSObject()->TryMeasure(XFA_Attribute::H, false);
         if (measureH)
-          return XFA_AttributeEnum::ContentArea;
+          return XFA_AttributeValue::ContentArea;
       }
-      return XFA_AttributeEnum::None;
+      return XFA_AttributeValue::None;
     }
     case XFA_Element::Draw:
-      return XFA_AttributeEnum::ContentArea;
+      return XFA_AttributeValue::ContentArea;
     default:
-      return XFA_AttributeEnum::None;
+      return XFA_AttributeValue::None;
   }
 }
 
+WideString CXFA_Node::GetNameExpression() {
+  WideString wsName = GetNameExpressionSinglePath(this);
+  CXFA_Node* parent = GetParent();
+  while (parent) {
+    WideString wsParent = GetNameExpressionSinglePath(parent);
+    wsParent += L".";
+    wsParent += wsName;
+    wsName = std::move(wsParent);
+    parent = parent->GetParent();
+  }
+  return wsName;
+}
+
 CXFA_Node* CXFA_Node::GetDataDescriptionNode() {
   if (m_ePacket == XFA_PacketType::Datasets)
     return m_pAuxNode;
@@ -777,7 +1516,8 @@
 
 size_t CXFA_Node::CountChildren(XFA_Element eType, bool bOnlyChild) {
   size_t count = 0;
-  for (CXFA_Node* pNode = m_pChild; pNode; pNode = pNode->GetNextSibling()) {
+  for (CXFA_Node* pNode = GetFirstChild(); pNode;
+       pNode = pNode->GetNextSibling()) {
     if (pNode->GetElementType() != eType && eType != XFA_Element::Unknown)
       continue;
     if (bOnlyChild && HasProperty(pNode->GetElementType()))
@@ -789,9 +1529,10 @@
 
 CXFA_Node* CXFA_Node::GetChildInternal(size_t index,
                                        XFA_Element eType,
-                                       bool bOnlyChild) {
+                                       bool bOnlyChild) const {
   size_t count = 0;
-  for (CXFA_Node* pNode = m_pChild; pNode; pNode = pNode->GetNextSibling()) {
+  for (CXFA_Node* pNode = GetFirstChild(); pNode;
+       pNode = pNode->GetNextSibling()) {
     if (pNode->GetElementType() != eType && eType != XFA_Element::Unknown)
       continue;
     if (bOnlyChild && HasProperty(pNode->GetElementType()))
@@ -804,179 +1545,77 @@
   return nullptr;
 }
 
-int32_t CXFA_Node::InsertChild(int32_t index, CXFA_Node* pNode) {
-  ASSERT(!pNode->m_pNext);
-  pNode->m_pParent = this;
-  bool ret = m_pDocument->RemovePurgeNode(pNode);
-  ASSERT(ret);
-  (void)ret;  // Avoid unused variable warning.
+void CXFA_Node::InsertChildAndNotify(int32_t index, CXFA_Node* pNode) {
+  InsertChildAndNotify(pNode, GetNthChild(index));
+}
 
-  if (!m_pChild || index == 0) {
-    if (index > 0) {
-      return -1;
-    }
-    pNode->m_pNext = m_pChild;
-    m_pChild = pNode;
-    index = 0;
-  } else if (index < 0) {
-    m_pLastChild->m_pNext = pNode;
-  } else {
-    CXFA_Node* pPrev = m_pChild;
-    int32_t iCount = 0;
-    while (++iCount != index && pPrev->m_pNext) {
-      pPrev = pPrev->m_pNext;
-    }
-    if (index > 0 && index != iCount) {
-      return -1;
-    }
-    pNode->m_pNext = pPrev->m_pNext;
-    pPrev->m_pNext = pNode;
-    index = iCount;
-  }
-  if (!pNode->m_pNext) {
-    m_pLastChild = pNode;
-  }
-  ASSERT(m_pLastChild);
-  ASSERT(!m_pLastChild->m_pNext);
+void CXFA_Node::InsertChildAndNotify(CXFA_Node* pNode, CXFA_Node* pBeforeNode) {
+  CHECK(!pNode->GetParent());
+  CHECK(!pBeforeNode || pBeforeNode->GetParent() == this);
   pNode->ClearFlag(XFA_NodeFlag_HasRemovedChildren);
+  InsertBefore(pNode, pBeforeNode);
+
   CXFA_FFNotify* pNotify = m_pDocument->GetNotify();
   if (pNotify)
     pNotify->OnChildAdded(this);
 
-  if (IsNeedSavingXMLNode() && pNode->m_pXMLNode) {
-    ASSERT(!pNode->m_pXMLNode->GetNodeItem(CFX_XMLNode::Parent));
-    m_pXMLNode->InsertChildNode(pNode->m_pXMLNode, index);
-    pNode->ClearFlag(XFA_NodeFlag_OwnXMLNode);
-  }
-  return index;
+  if (!IsNeedSavingXMLNode() || !pNode->xml_node_)
+    return;
+
+  ASSERT(!pNode->xml_node_->GetParent());
+  xml_node_->InsertBefore(pNode->xml_node_.Get(),
+                          pBeforeNode ? pBeforeNode->xml_node_.Get() : nullptr);
 }
 
-bool CXFA_Node::InsertChild(CXFA_Node* pNode, CXFA_Node* pBeforeNode) {
-  if (!pNode || pNode->m_pParent ||
-      (pBeforeNode && pBeforeNode->m_pParent != this)) {
-    NOTREACHED();
-    return false;
-  }
-  bool ret = m_pDocument->RemovePurgeNode(pNode);
-  ASSERT(ret);
-  (void)ret;  // Avoid unused variable warning.
+void CXFA_Node::RemoveChildAndNotify(CXFA_Node* pNode, bool bNotify) {
+  CHECK(pNode);
+  if (pNode->GetParent() != this)
+    return;
 
-  int32_t nIndex = -1;
-  pNode->m_pParent = this;
-  if (!m_pChild || pBeforeNode == m_pChild) {
-    pNode->m_pNext = m_pChild;
-    m_pChild = pNode;
-    nIndex = 0;
-  } else if (!pBeforeNode) {
-    pNode->m_pNext = m_pLastChild->m_pNext;
-    m_pLastChild->m_pNext = pNode;
-  } else {
-    nIndex = 1;
-    CXFA_Node* pPrev = m_pChild;
-    while (pPrev->m_pNext != pBeforeNode) {
-      pPrev = pPrev->m_pNext;
-      nIndex++;
-    }
-    pNode->m_pNext = pPrev->m_pNext;
-    pPrev->m_pNext = pNode;
-  }
-  if (!pNode->m_pNext) {
-    m_pLastChild = pNode;
-  }
-  ASSERT(m_pLastChild);
-  ASSERT(!m_pLastChild->m_pNext);
-  pNode->ClearFlag(XFA_NodeFlag_HasRemovedChildren);
-  CXFA_FFNotify* pNotify = m_pDocument->GetNotify();
-  if (pNotify)
-    pNotify->OnChildAdded(this);
-
-  if (IsNeedSavingXMLNode() && pNode->m_pXMLNode) {
-    ASSERT(!pNode->m_pXMLNode->GetNodeItem(CFX_XMLNode::Parent));
-    m_pXMLNode->InsertChildNode(pNode->m_pXMLNode, nIndex);
-    pNode->ClearFlag(XFA_NodeFlag_OwnXMLNode);
-  }
-  return true;
-}
-
-CXFA_Node* CXFA_Node::Deprecated_GetPrevSibling() {
-  if (!m_pParent) {
-    return nullptr;
-  }
-  for (CXFA_Node* pSibling = m_pParent->m_pChild; pSibling;
-       pSibling = pSibling->m_pNext) {
-    if (pSibling->m_pNext == this) {
-      return pSibling;
-    }
-  }
-  return nullptr;
-}
-
-bool CXFA_Node::RemoveChild(CXFA_Node* pNode, bool bNotify) {
-  if (!pNode || pNode->m_pParent != this) {
-    NOTREACHED();
-    return false;
-  }
-  if (m_pChild == pNode) {
-    m_pChild = pNode->m_pNext;
-    if (m_pLastChild == pNode) {
-      m_pLastChild = pNode->m_pNext;
-    }
-    pNode->m_pNext = nullptr;
-    pNode->m_pParent = nullptr;
-  } else {
-    CXFA_Node* pPrev = pNode->Deprecated_GetPrevSibling();
-    pPrev->m_pNext = pNode->m_pNext;
-    if (m_pLastChild == pNode) {
-      m_pLastChild = pNode->m_pNext ? pNode->m_pNext : pPrev;
-    }
-    pNode->m_pNext = nullptr;
-    pNode->m_pParent = nullptr;
-  }
-  ASSERT(!m_pLastChild || !m_pLastChild->m_pNext);
+  pNode->SetFlag(XFA_NodeFlag_HasRemovedChildren);
+  TreeNode<CXFA_Node>::RemoveChild(pNode);
   OnRemoved(bNotify);
-  pNode->SetFlag(XFA_NodeFlag_HasRemovedChildren, true);
-  m_pDocument->AddPurgeNode(pNode);
-  if (IsNeedSavingXMLNode() && pNode->m_pXMLNode) {
-    if (pNode->IsAttributeInXML()) {
-      ASSERT(pNode->m_pXMLNode == m_pXMLNode &&
-             m_pXMLNode->GetType() == FX_XMLNODE_Element);
-      if (pNode->m_pXMLNode->GetType() == FX_XMLNODE_Element) {
-        CFX_XMLElement* pXMLElement =
-            static_cast<CFX_XMLElement*>(pNode->m_pXMLNode);
-        WideString wsAttributeName =
-            pNode->JSObject()->GetCData(XFA_Attribute::QualifiedName);
-        pXMLElement->RemoveAttribute(wsAttributeName.c_str());
-      }
 
-      WideString wsName = pNode->JSObject()
-                              ->TryAttribute(XFA_Attribute::Name, false)
-                              .value_or(WideString());
-      CFX_XMLElement* pNewXMLElement = new CFX_XMLElement(wsName);
-      WideString wsValue = JSObject()->GetCData(XFA_Attribute::Value);
-      if (!wsValue.IsEmpty())
-        pNewXMLElement->SetTextData(WideString(wsValue));
+  if (!IsNeedSavingXMLNode() || !pNode->xml_node_)
+    return;
 
-      pNode->m_pXMLNode = pNewXMLElement;
-      pNode->JSObject()->SetEnum(XFA_Attribute::Contains,
-                                 XFA_AttributeEnum::Unknown, false);
-    } else {
-      m_pXMLNode->RemoveChildNode(pNode->m_pXMLNode);
-    }
-    pNode->SetFlag(XFA_NodeFlag_OwnXMLNode, false);
+  if (!pNode->IsAttributeInXML()) {
+    xml_node_->RemoveChild(pNode->xml_node_.Get());
+    return;
   }
-  return true;
+
+  ASSERT(pNode->xml_node_ == xml_node_);
+  CFX_XMLElement* pXMLElement = ToXMLElement(pNode->xml_node_.Get());
+  if (pXMLElement) {
+    WideString wsAttributeName =
+        pNode->JSObject()->GetCData(XFA_Attribute::QualifiedName);
+    pXMLElement->RemoveAttribute(wsAttributeName);
+  }
+
+  WideString wsName = pNode->JSObject()
+                          ->TryAttribute(XFA_Attribute::Name, false)
+                          .value_or(WideString());
+
+  auto* pNewXMLElement = GetXMLDocument()->CreateNode<CFX_XMLElement>(wsName);
+  WideString wsValue = JSObject()->GetCData(XFA_Attribute::Value);
+  if (!wsValue.IsEmpty()) {
+    auto* text = GetXMLDocument()->CreateNode<CFX_XMLText>(wsValue);
+    pNewXMLElement->AppendLastChild(text);
+  }
+  pNode->xml_node_ = pNewXMLElement;
+  pNode->JSObject()->SetEnum(XFA_Attribute::Contains,
+                             XFA_AttributeValue::Unknown, false);
 }
 
-CXFA_Node* CXFA_Node::GetFirstChildByName(const WideStringView& wsName) const {
+CXFA_Node* CXFA_Node::GetFirstChildByName(WideStringView wsName) const {
   return GetFirstChildByName(FX_HashCode_GetW(wsName, false));
 }
 
 CXFA_Node* CXFA_Node::GetFirstChildByName(uint32_t dwNameHash) const {
   for (CXFA_Node* pNode = GetFirstChild(); pNode;
        pNode = pNode->GetNextSibling()) {
-    if (pNode->GetNameHash() == dwNameHash) {
+    if (pNode->GetNameHash() == dwNameHash)
       return pNode;
-    }
   }
   return nullptr;
 }
@@ -984,9 +1623,8 @@
 CXFA_Node* CXFA_Node::GetFirstChildByClassInternal(XFA_Element eType) const {
   for (CXFA_Node* pNode = GetFirstChild(); pNode;
        pNode = pNode->GetNextSibling()) {
-    if (pNode->GetElementType() == eType) {
+    if (pNode->GetElementType() == eType)
       return pNode;
-    }
   }
   return nullptr;
 }
@@ -994,51 +1632,89 @@
 CXFA_Node* CXFA_Node::GetNextSameNameSibling(uint32_t dwNameHash) const {
   for (CXFA_Node* pNode = GetNextSibling(); pNode;
        pNode = pNode->GetNextSibling()) {
-    if (pNode->GetNameHash() == dwNameHash) {
+    if (pNode->GetNameHash() == dwNameHash)
       return pNode;
-    }
   }
   return nullptr;
 }
 
 CXFA_Node* CXFA_Node::GetNextSameNameSiblingInternal(
-    const WideStringView& wsNodeName) const {
+    WideStringView wsNodeName) const {
   return GetNextSameNameSibling(FX_HashCode_GetW(wsNodeName, false));
 }
 
 CXFA_Node* CXFA_Node::GetNextSameClassSiblingInternal(XFA_Element eType) const {
   for (CXFA_Node* pNode = GetNextSibling(); pNode;
        pNode = pNode->GetNextSibling()) {
-    if (pNode->GetElementType() == eType) {
+    if (pNode->GetElementType() == eType)
       return pNode;
-    }
   }
   return nullptr;
 }
 
-int32_t CXFA_Node::GetNodeSameNameIndex() const {
-  CFXJSE_Engine* pScriptContext = m_pDocument->GetScriptContext();
-  if (!pScriptContext) {
-    return -1;
-  }
-  return pScriptContext->GetIndexByName(const_cast<CXFA_Node*>(this));
+CXFA_Node* CXFA_Node::GetOneChildNamed(WideStringView wsName) {
+  return FindFirstSiblingNamed(this, FX_HashCode_GetW(wsName, false));
 }
 
-int32_t CXFA_Node::GetNodeSameClassIndex() const {
-  CFXJSE_Engine* pScriptContext = m_pDocument->GetScriptContext();
-  if (!pScriptContext) {
-    return -1;
+CXFA_Node* CXFA_Node::GetOneChildOfClass(WideStringView wsClass) {
+  XFA_Element element = XFA_GetElementByName(wsClass);
+  if (element == XFA_Element::Unknown)
+    return nullptr;
+
+  return FindFirstSiblingOfClass(this, element);
+}
+
+std::vector<CXFA_Node*> CXFA_Node::GetSiblings(bool bIsClassName) {
+  std::vector<CXFA_Node*> siblings;
+  CXFA_Node* parent = GetParent();
+  if (!parent)
+    return siblings;
+  if (!parent->HasProperty(GetElementType())) {
+    parent = GetTransparentParent();
+    if (!parent)
+      return siblings;
   }
-  return pScriptContext->GetIndexByClassName(const_cast<CXFA_Node*>(this));
+
+  uint32_t dwNameHash = bIsClassName ? GetClassHashCode() : GetNameHash();
+  TraverseSiblings(parent, dwNameHash, &siblings, bIsClassName, true);
+  return siblings;
+}
+
+size_t CXFA_Node::GetIndex(bool bIsProperty, bool bIsClassIndex) {
+  CXFA_Node* parent = GetParent();
+  if (!parent)
+    return 0;
+
+  if (!bIsProperty) {
+    parent = GetTransparentParent();
+    if (!parent)
+      return 0;
+  }
+  uint32_t dwHashName = bIsClassIndex ? GetClassHashCode() : GetNameHash();
+  std::vector<CXFA_Node*> siblings;
+  TraverseSiblings(parent, dwHashName, &siblings, bIsClassIndex, true);
+  for (size_t i = 0; i < siblings.size(); ++i) {
+    if (siblings[i] == this)
+      return i;
+  }
+  return 0;
+}
+
+size_t CXFA_Node::GetIndexByName() {
+  return GetIndex(IsProperty(), /*bIsClassIndex=*/false);
+}
+
+size_t CXFA_Node::GetIndexByClassName() {
+  return GetIndex(IsProperty(), /*bIsClassIndex=*/true);
 }
 
 CXFA_Node* CXFA_Node::GetInstanceMgrOfSubform() {
   CXFA_Node* pInstanceMgr = nullptr;
   if (m_ePacket == XFA_PacketType::Form) {
     CXFA_Node* pParentNode = GetParent();
-    if (!pParentNode || pParentNode->GetElementType() == XFA_Element::Area) {
+    if (!pParentNode || pParentNode->GetElementType() == XFA_Element::Area)
       return pInstanceMgr;
-    }
+
     for (CXFA_Node* pNode = GetPrevSibling(); pNode;
          pNode = pNode->GetPrevSibling()) {
       XFA_Element eType = pNode->GetElementType();
@@ -1051,7 +1727,7 @@
         WideString wsInstName =
             pNode->JSObject()->GetCData(XFA_Attribute::Name);
         if (wsInstName.GetLength() > 0 && wsInstName[0] == '_' &&
-            wsInstName.Right(wsInstName.GetLength() - 1) == wsName) {
+            wsInstName.Last(wsInstName.GetLength() - 1) == wsName) {
           pInstanceMgr = pNode;
         }
         break;
@@ -1069,12 +1745,14 @@
   if (m_uNodeFlags & dwFlag)
     return true;
   if (dwFlag == XFA_NodeFlag_HasRemovedChildren)
-    return m_pParent && m_pParent->HasFlag(dwFlag);
+    return GetParent() && GetParent()->HasFlag(dwFlag);
   return false;
 }
 
-void CXFA_Node::SetFlag(uint32_t dwFlag, bool bNotify) {
-  if (dwFlag == XFA_NodeFlag_Initialized && bNotify && !IsInitialized()) {
+void CXFA_Node::SetFlagAndNotify(uint32_t dwFlag) {
+  ASSERT(dwFlag == XFA_NodeFlag_Initialized);
+
+  if (!IsInitialized()) {
     CXFA_FFNotify* pNotify = m_pDocument->GetNotify();
     if (pNotify) {
       pNotify->OnNodeReady(this);
@@ -1083,26 +1761,20 @@
   m_uNodeFlags |= dwFlag;
 }
 
+void CXFA_Node::SetFlag(uint32_t dwFlag) {
+  m_uNodeFlags |= dwFlag;
+}
+
 void CXFA_Node::ClearFlag(uint32_t dwFlag) {
   m_uNodeFlags &= ~dwFlag;
 }
 
-void CXFA_Node::ReleaseBindingNodes() {
-  // Clear any binding nodes as we don't necessarily destruct in an order that
-  // makes sense.
-  for (auto& node : binding_nodes_)
-    node.Release();
-
-  for (CXFA_Node* pNode = m_pChild; pNode; pNode = pNode->m_pNext)
-    pNode->ReleaseBindingNodes();
-}
-
 bool CXFA_Node::IsAttributeInXML() {
   return JSObject()->GetEnum(XFA_Attribute::Contains) ==
-         XFA_AttributeEnum::MetaData;
+         XFA_AttributeValue::MetaData;
 }
 
-void CXFA_Node::OnRemoved(bool bNotify) {
+void CXFA_Node::OnRemoved(bool bNotify) const {
   if (!bNotify)
     return;
 
@@ -1117,17 +1789,16 @@
 }
 
 CFX_XMLNode* CXFA_Node::CreateXMLMappingNode() {
-  if (!m_pXMLNode) {
-    WideString wsTag(JSObject()->GetCData(XFA_Attribute::Name));
-    m_pXMLNode = new CFX_XMLElement(wsTag);
-    SetFlag(XFA_NodeFlag_OwnXMLNode, false);
+  if (!xml_node_) {
+    xml_node_ = GetXMLDocument()->CreateNode<CFX_XMLElement>(
+        JSObject()->GetCData(XFA_Attribute::Name));
   }
-  return m_pXMLNode;
+  return xml_node_.Get();
 }
 
-bool CXFA_Node::IsNeedSavingXMLNode() {
-  return m_pXMLNode && (GetPacketType() == XFA_PacketType::Datasets ||
-                        GetElementType() == XFA_Element::Xfa);
+bool CXFA_Node::IsNeedSavingXMLNode() const {
+  return xml_node_ && (GetPacketType() == XFA_PacketType::Datasets ||
+                       GetElementType() == XFA_Element::Xfa);
 }
 
 CXFA_Node* CXFA_Node::GetItemIfExists(int32_t iIndex) {
@@ -1146,7 +1817,7 @@
       WideString wsName = pNode->JSObject()->GetCData(XFA_Attribute::Name);
       WideString wsInstName = JSObject()->GetCData(XFA_Attribute::Name);
       if (wsInstName.GetLength() < 1 || wsInstName[0] != '_' ||
-          wsInstName.Right(wsInstName.GetLength() - 1) != wsName) {
+          wsInstName.Last(wsInstName.GetLength() - 1) != wsName) {
         return nullptr;
       }
       dwNameHash = pNode->GetNameHash();
@@ -1177,7 +1848,7 @@
       WideString wsName = pNode->JSObject()->GetCData(XFA_Attribute::Name);
       WideString wsInstName = JSObject()->GetCData(XFA_Attribute::Name);
       if (wsInstName.GetLength() < 1 || wsInstName[0] != '_' ||
-          wsInstName.Right(wsInstName.GetLength() - 1) != wsName) {
+          wsInstName.Last(wsInstName.GetLength() - 1) != wsName) {
         return iCount;
       }
       dwNameHash = pNode->GetNameHash();
@@ -1205,7 +1876,7 @@
 
     CXFA_Node* pNextSibling =
         iCount > 0 ? item->GetNextSibling() : GetNextSibling();
-    GetParent()->InsertChild(pNewInstance, pNextSibling);
+    GetParent()->InsertChildAndNotify(pNewInstance, pNextSibling);
     if (bMoveDataBindingNodes) {
       std::set<CXFA_Node*> sNew;
       std::set<CXFA_Node*> sAfter;
@@ -1240,7 +1911,7 @@
       return;
     }
 
-    GetParent()->InsertChild(pNewInstance, pBeforeInstance);
+    GetParent()->InsertChildAndNotify(pNewInstance, pBeforeInstance);
     if (bMoveDataBindingNodes) {
       std::set<CXFA_Node*> sNew;
       std::set<CXFA_Node*> sBefore;
@@ -1273,7 +1944,7 @@
 
 void CXFA_Node::RemoveItem(CXFA_Node* pRemoveInstance,
                            bool bRemoveDataBinding) {
-  GetParent()->RemoveChild(pRemoveInstance, true);
+  GetParent()->RemoveChildAndNotify(pRemoveInstance, true);
   if (!bRemoveDataBinding)
     return;
 
@@ -1287,7 +1958,7 @@
 
     if (pDataNode->RemoveBindItem(pFormNode) == 0) {
       if (CXFA_Node* pDataParent = pDataNode->GetParent()) {
-        pDataParent->RemoveChild(pDataNode, true);
+        pDataParent->RemoveChildAndNotify(pDataNode, true);
       }
     }
     pFormNode->SetBindingNode(nullptr);
@@ -1318,7 +1989,7 @@
       pTemplateNode, pFormParent, pDataScope, true, bDataMerge, true);
   if (pInstance) {
     pDocument->DataMerge_UpdateBindingRelations(pInstance);
-    pFormParent->RemoveChild(pInstance, true);
+    pFormParent->RemoveChildAndNotify(pInstance, true);
   }
   return pInstance;
 }
@@ -1355,12 +2026,12 @@
   return {WideString(static_cast<const wchar_t*>(*value))};
 }
 
-Optional<XFA_AttributeEnum> CXFA_Node::GetDefaultEnum(
+Optional<XFA_AttributeValue> CXFA_Node::GetDefaultEnum(
     XFA_Attribute attr) const {
   Optional<void*> value = GetDefaultValue(attr, XFA_AttributeType::Enum);
   if (!value)
     return {};
-  return {static_cast<XFA_AttributeEnum>(reinterpret_cast<uintptr_t>(*value))};
+  return {static_cast<XFA_AttributeValue>(reinterpret_cast<uintptr_t>(*value))};
 }
 
 Optional<void*> CXFA_Node::GetDefaultValue(XFA_Attribute attr,
@@ -1375,10 +2046,6 @@
 
 void CXFA_Node::SendAttributeChangeMessage(XFA_Attribute eAttribute,
                                            bool bScriptModify) {
-  CXFA_LayoutProcessor* pLayoutPro = GetDocument()->GetLayoutProcessor();
-  if (!pLayoutPro)
-    return;
-
   CXFA_FFNotify* pNotify = GetDocument()->GetNotify();
   if (!pNotify)
     return;
@@ -1417,9 +2084,8 @@
                                 pParentNode->GetParent());
       } else {
         CXFA_Node* pNode = pParentNode->GetParent();
-        if (pNode && pNode->GetElementType() == XFA_Element::Ui) {
+        if (pNode && pNode->GetElementType() == XFA_Element::Ui)
           pNotify->OnValueChanged(this, eAttribute, pNode, pNode->GetParent());
-        }
       }
       break;
     }
@@ -1474,7 +2140,7 @@
     case XFA_Element::Field:
     case XFA_Element::Subform:
     case XFA_Element::SubformSet:
-      pLayoutPro->AddChangedContainer(this);
+      pNotify->OnContainerChanged(this);
       pNotify->OnValueChanged(this, eAttribute, this, this);
       break;
     case XFA_Element::Sharptext:
@@ -1522,14 +2188,14 @@
     pParent = pParent->GetParent();
 
   if (pParent)
-    pLayoutPro->AddChangedContainer(pParent);
+    pNotify->OnContainerChanged(pParent);
 }
 
 void CXFA_Node::SyncValue(const WideString& wsValue, bool bNotify) {
   WideString wsFormatValue = wsValue;
-  CXFA_WidgetAcc* pContainerWidgetAcc = GetContainerWidgetAcc();
-  if (pContainerWidgetAcc)
-    wsFormatValue = pContainerWidgetAcc->GetFormatDataValue(wsValue);
+  CXFA_Node* pContainerNode = GetContainerNode();
+  if (pContainerNode)
+    wsFormatValue = pContainerNode->GetFormatDataValue(wsValue);
 
   JSObject()->SetContent(wsValue, wsFormatValue, bNotify, false, true);
 }
@@ -1538,7 +2204,7 @@
   return JSObject()->GetContent(false);
 }
 
-int32_t CXFA_Node::GetRotate() {
+int32_t CXFA_Node::GetRotate() const {
   Optional<int32_t> degrees =
       JSObject()->TryInteger(XFA_Attribute::Rotate, false);
   return degrees ? XFA_MapRotation(*degrees) / 90 * 90 : 0;
@@ -1594,10 +2260,10 @@
   return JSObject()->GetProperty<CXFA_Para>(0, XFA_Element::Para);
 }
 
-bool CXFA_Node::IsOpenAccess() {
+bool CXFA_Node::IsOpenAccess() const {
   for (auto* pNode = this; pNode; pNode = pNode->GetContainerParent()) {
-    XFA_AttributeEnum iAcc = pNode->JSObject()->GetEnum(XFA_Attribute::Access);
-    if (iAcc != XFA_AttributeEnum::Open)
+    XFA_AttributeValue iAcc = pNode->JSObject()->GetEnum(XFA_Attribute::Access);
+    if (iAcc != XFA_AttributeValue::Open)
       return false;
   }
   return true;
@@ -1631,6 +2297,49 @@
   return JSObject()->GetProperty<CXFA_Bind>(0, XFA_Element::Bind);
 }
 
+Optional<XFA_AttributeValue> CXFA_Node::GetIntactFromKeep(
+    const CXFA_Keep* pKeep,
+    XFA_AttributeValue eLayoutType) const {
+  Optional<XFA_AttributeValue> intact =
+      pKeep->JSObject()->TryEnum(XFA_Attribute::Intact, false);
+  if (!intact.has_value())
+    return {};
+
+  if (intact.value() != XFA_AttributeValue::None ||
+      eLayoutType != XFA_AttributeValue::Row ||
+      m_pDocument->GetCurVersionMode() >= XFA_VERSION_208) {
+    return intact;
+  }
+
+  CXFA_Node* pPreviewRow = GetPrevContainerSibling();
+  if (!pPreviewRow || pPreviewRow->JSObject()->GetEnum(XFA_Attribute::Layout) !=
+                          XFA_AttributeValue::Row) {
+    return intact;
+  }
+
+  Optional<XFA_AttributeValue> value =
+      pKeep->JSObject()->TryEnum(XFA_Attribute::Previous, false);
+  if (value && (*value == XFA_AttributeValue::ContentArea ||
+                *value == XFA_AttributeValue::PageArea)) {
+    return XFA_AttributeValue::ContentArea;
+  }
+
+  CXFA_Keep* pNode =
+      pPreviewRow->GetFirstChildByClass<CXFA_Keep>(XFA_Element::Keep);
+  if (!pNode)
+    return intact;
+
+  Optional<XFA_AttributeValue> ret =
+      pNode->JSObject()->TryEnum(XFA_Attribute::Next, false);
+  if (!ret)
+    return intact;
+
+  return (*ret == XFA_AttributeValue::ContentArea ||
+          *ret == XFA_AttributeValue::PageArea)
+             ? XFA_AttributeValue::ContentArea
+             : intact;
+}
+
 Optional<float> CXFA_Node::TryWidth() {
   return JSObject()->TryMeasureAsFloat(XFA_Attribute::W);
 }
@@ -1662,275 +2371,300 @@
   return pExcl;
 }
 
-int32_t CXFA_Node::ProcessEvent(CXFA_FFDocView* docView,
-                                XFA_AttributeEnum iActivity,
-                                CXFA_EventParam* pEventParam) {
+XFA_EventError CXFA_Node::ProcessEvent(CXFA_FFDocView* pDocView,
+                                       XFA_AttributeValue iActivity,
+                                       CXFA_EventParam* pEventParam) {
   if (GetElementType() == XFA_Element::Draw)
-    return XFA_EVENTERROR_NotExist;
+    return XFA_EventError::kNotExist;
 
-  std::vector<CXFA_Event*> eventArray = GetWidgetAcc()->GetEventByActivity(
-      iActivity, pEventParam->m_bIsFormReady);
+  std::vector<CXFA_Event*> eventArray =
+      GetEventByActivity(iActivity, pEventParam->m_bIsFormReady);
   bool first = true;
-  int32_t iRet = XFA_EVENTERROR_NotExist;
+  XFA_EventError iRet = XFA_EventError::kNotExist;
   for (CXFA_Event* event : eventArray) {
-    int32_t result = ProcessEvent(docView, event, pEventParam);
-    if (first || result == XFA_EVENTERROR_Success)
+    XFA_EventError result =
+        ProcessEventInternal(pDocView, iActivity, event, pEventParam);
+    if (first || result == XFA_EventError::kSuccess)
       iRet = result;
     first = false;
   }
   return iRet;
 }
 
-int32_t CXFA_Node::ProcessEvent(CXFA_FFDocView* docView,
-                                CXFA_Event* event,
-                                CXFA_EventParam* pEventParam) {
+XFA_EventError CXFA_Node::ProcessEventInternal(CXFA_FFDocView* pDocView,
+                                               XFA_AttributeValue iActivity,
+                                               CXFA_Event* event,
+                                               CXFA_EventParam* pEventParam) {
   if (!event)
-    return XFA_EVENTERROR_NotExist;
+    return XFA_EventError::kNotExist;
 
   switch (event->GetEventType()) {
     case XFA_Element::Execute:
       break;
     case XFA_Element::Script:
-      return ExecuteScript(docView, event->GetScriptIfExists(), pEventParam);
+      if (iActivity == XFA_AttributeValue::DocClose) {
+        // Too late, scripting engine already gone.
+        return XFA_EventError::kNotExist;
+      }
+      return ExecuteScript(pDocView, event->GetScriptIfExists(), pEventParam);
     case XFA_Element::SignData:
       break;
     case XFA_Element::Submit: {
+// TODO(crbug.com/867485): Submit is disabled for now. Fix it and reenable this
+// code.
+#ifdef PDF_XFA_ELEMENT_SUBMIT_ENABLED
       CXFA_Submit* submit = event->GetSubmitIfExists();
       if (!submit)
-        return XFA_EVENTERROR_NotExist;
-      return docView->GetDoc()->GetDocEnvironment()->Submit(docView->GetDoc(),
-                                                            submit);
+        return XFA_EventError::kNotExist;
+      return pDocView->GetDoc()->GetDocEnvironment()->Submit(pDocView->GetDoc(),
+                                                             submit);
+#else
+      return XFA_EventError::kDisabled;
+#endif  // PDF_XFA_ELEMENT_SUBMIT_ENABLED
     }
     default:
       break;
   }
-  return XFA_EVENTERROR_NotExist;
+  return XFA_EventError::kNotExist;
 }
 
-int32_t CXFA_Node::ProcessCalculate(CXFA_FFDocView* docView) {
+XFA_EventError CXFA_Node::ProcessCalculate(CXFA_FFDocView* pDocView) {
   if (GetElementType() == XFA_Element::Draw)
-    return XFA_EVENTERROR_NotExist;
+    return XFA_EventError::kNotExist;
 
   CXFA_Calculate* calc = GetCalculateIfExists();
   if (!calc)
-    return XFA_EVENTERROR_NotExist;
+    return XFA_EventError::kNotExist;
   if (IsUserInteractive())
-    return XFA_EVENTERROR_Disabled;
+    return XFA_EventError::kDisabled;
 
   CXFA_EventParam EventParam;
   EventParam.m_eType = XFA_EVENT_Calculate;
-  int32_t iRet = ExecuteScript(docView, calc->GetScriptIfExists(), &EventParam);
-  if (iRet != XFA_EVENTERROR_Success)
+  XFA_EventError iRet =
+      ExecuteScript(pDocView, calc->GetScriptIfExists(), &EventParam);
+  if (iRet != XFA_EventError::kSuccess)
     return iRet;
 
   if (GetRawValue() != EventParam.m_wsResult) {
-    GetWidgetAcc()->SetValue(XFA_VALUEPICTURE_Raw, EventParam.m_wsResult);
-    GetWidgetAcc()->UpdateUIDisplay(docView, nullptr);
+    SetValue(XFA_VALUEPICTURE_Raw, EventParam.m_wsResult);
+    pDocView->UpdateUIDisplay(this, nullptr);
   }
-  return XFA_EVENTERROR_Success;
+  return XFA_EventError::kSuccess;
 }
 
-void CXFA_Node::ProcessScriptTestValidate(CXFA_FFDocView* docView,
+void CXFA_Node::ProcessScriptTestValidate(CXFA_FFDocView* pDocView,
                                           CXFA_Validate* validate,
-                                          int32_t iRet,
+                                          XFA_EventError iRet,
                                           bool bRetValue,
                                           bool bVersionFlag) {
-  if (iRet != XFA_EVENTERROR_Success)
+  if (iRet != XFA_EventError::kSuccess)
     return;
   if (bRetValue)
     return;
 
   IXFA_AppProvider* pAppProvider =
-      docView->GetDoc()->GetApp()->GetAppProvider();
+      pDocView->GetDoc()->GetApp()->GetAppProvider();
   if (!pAppProvider)
     return;
 
   WideString wsTitle = pAppProvider->GetAppTitle();
   WideString wsScriptMsg = validate->GetScriptMessageText();
-  if (validate->GetScriptTest() == XFA_AttributeEnum::Warning) {
+  if (validate->GetScriptTest() == XFA_AttributeValue::Warning) {
     if (IsUserInteractive())
       return;
     if (wsScriptMsg.IsEmpty())
       wsScriptMsg = GetValidateMessage(false, bVersionFlag);
 
     if (bVersionFlag) {
-      pAppProvider->MsgBox(wsScriptMsg, wsTitle, XFA_MBICON_Warning, XFA_MB_OK);
+      pAppProvider->MsgBox(wsScriptMsg, wsTitle,
+                           static_cast<uint32_t>(AlertIcon::kWarning),
+                           static_cast<uint32_t>(AlertButton::kOK));
       return;
     }
-    if (pAppProvider->MsgBox(wsScriptMsg, wsTitle, XFA_MBICON_Warning,
-                             XFA_MB_YesNo) == XFA_IDYes) {
-      SetFlag(XFA_NodeFlag_UserInteractive, false);
+    if (pAppProvider->MsgBox(wsScriptMsg, wsTitle,
+                             static_cast<uint32_t>(AlertIcon::kWarning),
+                             static_cast<uint32_t>(AlertButton::kYesNo)) ==
+        static_cast<uint32_t>(AlertReturn::kYes)) {
+      SetFlag(XFA_NodeFlag_UserInteractive);
     }
     return;
   }
 
   if (wsScriptMsg.IsEmpty())
     wsScriptMsg = GetValidateMessage(true, bVersionFlag);
-  pAppProvider->MsgBox(wsScriptMsg, wsTitle, XFA_MBICON_Error, XFA_MB_OK);
+  pAppProvider->MsgBox(wsScriptMsg, wsTitle,
+                       static_cast<uint32_t>(AlertIcon::kError),
+                       static_cast<uint32_t>(AlertButton::kOK));
 }
 
-int32_t CXFA_Node::ProcessFormatTestValidate(CXFA_FFDocView* docView,
-                                             CXFA_Validate* validate,
-                                             bool bVersionFlag) {
+XFA_EventError CXFA_Node::ProcessFormatTestValidate(CXFA_FFDocView* pDocView,
+                                                    CXFA_Validate* validate,
+                                                    bool bVersionFlag) {
+  WideString wsPicture = validate->GetPicture();
+  if (wsPicture.IsEmpty())
+    return XFA_EventError::kNotExist;
+
   WideString wsRawValue = GetRawValue();
-  if (!wsRawValue.IsEmpty()) {
-    WideString wsPicture = validate->GetPicture();
-    if (wsPicture.IsEmpty())
-      return XFA_EVENTERROR_NotExist;
+  if (wsRawValue.IsEmpty())
+    return XFA_EventError::kError;
 
-    IFX_Locale* pLocale = GetLocale();
-    if (!pLocale)
-      return XFA_EVENTERROR_NotExist;
+  LocaleIface* pLocale = GetLocale();
+  if (!pLocale)
+    return XFA_EventError::kNotExist;
 
-    CXFA_LocaleValue lcValue = XFA_GetLocaleValue(this);
-    if (!lcValue.ValidateValue(lcValue.GetValue(), wsPicture, pLocale,
-                               nullptr)) {
-      IXFA_AppProvider* pAppProvider =
-          docView->GetDoc()->GetApp()->GetAppProvider();
-      if (!pAppProvider)
-        return XFA_EVENTERROR_NotExist;
+  CXFA_LocaleValue lcValue = XFA_GetLocaleValue(this);
+  if (lcValue.ValidateValue(lcValue.GetValue(), wsPicture, pLocale, nullptr))
+    return XFA_EventError::kSuccess;
 
-      WideString wsFormatMsg = validate->GetFormatMessageText();
-      WideString wsTitle = pAppProvider->GetAppTitle();
-      if (validate->GetFormatTest() == XFA_AttributeEnum::Error) {
-        if (wsFormatMsg.IsEmpty())
-          wsFormatMsg = GetValidateMessage(true, bVersionFlag);
-        pAppProvider->MsgBox(wsFormatMsg, wsTitle, XFA_MBICON_Error, XFA_MB_OK);
-        return XFA_EVENTERROR_Success;
-      }
-      if (IsUserInteractive())
-        return XFA_EVENTERROR_NotExist;
-      if (wsFormatMsg.IsEmpty())
-        wsFormatMsg = GetValidateMessage(false, bVersionFlag);
+  IXFA_AppProvider* pAppProvider =
+      pDocView->GetDoc()->GetApp()->GetAppProvider();
+  if (!pAppProvider)
+    return XFA_EventError::kNotExist;
 
-      if (bVersionFlag) {
-        pAppProvider->MsgBox(wsFormatMsg, wsTitle, XFA_MBICON_Warning,
-                             XFA_MB_OK);
-        return XFA_EVENTERROR_Success;
-      }
-      if (pAppProvider->MsgBox(wsFormatMsg, wsTitle, XFA_MBICON_Warning,
-                               XFA_MB_YesNo) == XFA_IDYes) {
-        SetFlag(XFA_NodeFlag_UserInteractive, false);
-      }
-      return XFA_EVENTERROR_Success;
-    }
+  WideString wsFormatMsg = validate->GetFormatMessageText();
+  WideString wsTitle = pAppProvider->GetAppTitle();
+  if (validate->GetFormatTest() == XFA_AttributeValue::Error) {
+    if (wsFormatMsg.IsEmpty())
+      wsFormatMsg = GetValidateMessage(true, bVersionFlag);
+    pAppProvider->MsgBox(wsFormatMsg, wsTitle,
+                         static_cast<uint32_t>(AlertIcon::kError),
+                         static_cast<uint32_t>(AlertButton::kOK));
+    return XFA_EventError::kError;
   }
-  return XFA_EVENTERROR_NotExist;
+
+  if (wsFormatMsg.IsEmpty())
+    wsFormatMsg = GetValidateMessage(false, bVersionFlag);
+
+  if (bVersionFlag) {
+    pAppProvider->MsgBox(wsFormatMsg, wsTitle,
+                         static_cast<uint32_t>(AlertIcon::kWarning),
+                         static_cast<uint32_t>(AlertButton::kOK));
+    return XFA_EventError::kError;
+  }
+
+  if (pAppProvider->MsgBox(wsFormatMsg, wsTitle,
+                           static_cast<uint32_t>(AlertIcon::kWarning),
+                           static_cast<uint32_t>(AlertButton::kYesNo)) ==
+      static_cast<uint32_t>(AlertReturn::kYes)) {
+    SetFlag(XFA_NodeFlag_UserInteractive);
+  }
+
+  return XFA_EventError::kError;
 }
 
-int32_t CXFA_Node::ProcessNullTestValidate(CXFA_FFDocView* docView,
-                                           CXFA_Validate* validate,
-                                           int32_t iFlags,
-                                           bool bVersionFlag) {
-  if (!GetWidgetAcc()->GetValue(XFA_VALUEPICTURE_Raw).IsEmpty())
-    return XFA_EVENTERROR_Success;
-  if (GetWidgetAcc()->IsNull() && GetWidgetAcc()->IsPreNull())
-    return XFA_EVENTERROR_Success;
+XFA_EventError CXFA_Node::ProcessNullTestValidate(CXFA_FFDocView* pDocView,
+                                                  CXFA_Validate* validate,
+                                                  int32_t iFlags,
+                                                  bool bVersionFlag) {
+  if (!GetValue(XFA_VALUEPICTURE_Raw).IsEmpty())
+    return XFA_EventError::kSuccess;
+  if (m_bIsNull && m_bPreNull)
+    return XFA_EventError::kSuccess;
 
-  XFA_AttributeEnum eNullTest = validate->GetNullTest();
+  XFA_AttributeValue eNullTest = validate->GetNullTest();
   WideString wsNullMsg = validate->GetNullMessageText();
   if (iFlags & 0x01) {
-    int32_t iRet = XFA_EVENTERROR_Success;
-    if (eNullTest != XFA_AttributeEnum::Disabled)
-      iRet = XFA_EVENTERROR_Error;
+    XFA_EventError iRet = XFA_EventError::kSuccess;
+    if (eNullTest != XFA_AttributeValue::Disabled)
+      iRet = XFA_EventError::kError;
 
-    if (!wsNullMsg.IsEmpty()) {
-      if (eNullTest != XFA_AttributeEnum::Disabled) {
-        docView->m_arrNullTestMsg.push_back(wsNullMsg);
-        return XFA_EVENTERROR_Error;
-      }
-      return XFA_EVENTERROR_Success;
+    if (wsNullMsg.IsEmpty())
+      return iRet;
+
+    if (eNullTest != XFA_AttributeValue::Disabled) {
+      pDocView->m_arrNullTestMsg.push_back(wsNullMsg);
+      return XFA_EventError::kError;
     }
-    return iRet;
+    return XFA_EventError::kSuccess;
   }
   if (wsNullMsg.IsEmpty() && bVersionFlag &&
-      eNullTest != XFA_AttributeEnum::Disabled) {
-    return XFA_EVENTERROR_Error;
+      eNullTest != XFA_AttributeValue::Disabled) {
+    return XFA_EventError::kError;
   }
   IXFA_AppProvider* pAppProvider =
-      docView->GetDoc()->GetApp()->GetAppProvider();
+      pDocView->GetDoc()->GetApp()->GetAppProvider();
   if (!pAppProvider)
-    return XFA_EVENTERROR_NotExist;
+    return XFA_EventError::kNotExist;
 
   WideString wsCaptionName;
   WideString wsTitle = pAppProvider->GetAppTitle();
   switch (eNullTest) {
-    case XFA_AttributeEnum::Error: {
+    case XFA_AttributeValue::Error: {
       if (wsNullMsg.IsEmpty()) {
         wsCaptionName = GetValidateCaptionName(bVersionFlag);
-        wsNullMsg =
-            WideString::Format(L"%ls cannot be blank.", wsCaptionName.c_str());
+        wsNullMsg = wsCaptionName + L" cannot be blank.";
       }
-      pAppProvider->MsgBox(wsNullMsg, wsTitle, XFA_MBICON_Status, XFA_MB_OK);
-      return XFA_EVENTERROR_Error;
+      pAppProvider->MsgBox(wsNullMsg, wsTitle,
+                           static_cast<uint32_t>(AlertIcon::kStatus),
+                           static_cast<uint32_t>(AlertButton::kOK));
+      return XFA_EventError::kError;
     }
-    case XFA_AttributeEnum::Warning: {
+    case XFA_AttributeValue::Warning: {
       if (IsUserInteractive())
-        return true;
+        return XFA_EventError::kSuccess;
 
       if (wsNullMsg.IsEmpty()) {
         wsCaptionName = GetValidateCaptionName(bVersionFlag);
-        wsNullMsg = WideString::Format(
-            L"%ls cannot be blank. To ignore validations for %ls, click "
-            L"Ignore.",
-            wsCaptionName.c_str(), wsCaptionName.c_str());
+        wsNullMsg = wsCaptionName +
+                    L" cannot be blank. To ignore validations for " +
+                    wsCaptionName + L", click Ignore.";
       }
-      if (pAppProvider->MsgBox(wsNullMsg, wsTitle, XFA_MBICON_Warning,
-                               XFA_MB_YesNo) == XFA_IDYes) {
-        SetFlag(XFA_NodeFlag_UserInteractive, false);
+      if (pAppProvider->MsgBox(wsNullMsg, wsTitle,
+                               static_cast<uint32_t>(AlertIcon::kWarning),
+                               static_cast<uint32_t>(AlertButton::kYesNo)) ==
+          static_cast<uint32_t>(AlertReturn::kYes)) {
+        SetFlag(XFA_NodeFlag_UserInteractive);
       }
-      return XFA_EVENTERROR_Error;
+      return XFA_EventError::kError;
     }
-    case XFA_AttributeEnum::Disabled:
+    case XFA_AttributeValue::Disabled:
     default:
       break;
   }
-  return XFA_EVENTERROR_Success;
+  return XFA_EventError::kSuccess;
 }
 
-int32_t CXFA_Node::ProcessValidate(CXFA_FFDocView* docView, int32_t iFlags) {
+XFA_EventError CXFA_Node::ProcessValidate(CXFA_FFDocView* pDocView,
+                                          int32_t iFlags) {
   if (GetElementType() == XFA_Element::Draw)
-    return XFA_EVENTERROR_NotExist;
+    return XFA_EventError::kNotExist;
 
   CXFA_Validate* validate = GetValidateIfExists();
   if (!validate)
-    return XFA_EVENTERROR_NotExist;
+    return XFA_EventError::kNotExist;
 
   bool bInitDoc = validate->NeedsInitApp();
-  bool bStatus = docView->GetLayoutStatus() < XFA_DOCVIEW_LAYOUTSTATUS_End;
-  int32_t iFormat = 0;
-  int32_t iRet = XFA_EVENTERROR_NotExist;
+  bool bStatus = pDocView->GetLayoutStatus() < XFA_DOCVIEW_LAYOUTSTATUS_End;
+  XFA_EventError iFormat = XFA_EventError::kNotExist;
+  XFA_EventError iRet = XFA_EventError::kNotExist;
   CXFA_Script* script = validate->GetScriptIfExists();
   bool bRet = false;
   bool hasBoolResult = (bInitDoc || bStatus) && GetRawValue().IsEmpty();
   if (script) {
     CXFA_EventParam eParam;
     eParam.m_eType = XFA_EVENT_Validate;
-    eParam.m_pTarget = GetWidgetAcc();
-    std::tie(iRet, bRet) = ExecuteBoolScript(docView, script, &eParam);
+    eParam.m_pTarget = this;
+    std::tie(iRet, bRet) = ExecuteBoolScript(pDocView, script, &eParam);
   }
 
-  XFA_VERSION version = docView->GetDoc()->GetXFADoc()->GetCurVersionMode();
-  bool bVersionFlag = false;
-  if (version < XFA_VERSION_208)
-    bVersionFlag = true;
+  XFA_VERSION version = pDocView->GetDoc()->GetXFADoc()->GetCurVersionMode();
+  bool bVersionFlag = version < XFA_VERSION_208;
 
   if (bInitDoc) {
     validate->ClearFlag(XFA_NodeFlag_NeedsInitApp);
   } else {
-    iFormat = ProcessFormatTestValidate(docView, validate, bVersionFlag);
-    if (!bVersionFlag) {
-      bVersionFlag =
-          docView->GetDoc()->GetXFADoc()->HasFlag(XFA_DOCFLAG_Scripting);
-    }
-
-    iRet |= ProcessNullTestValidate(docView, validate, iFlags, bVersionFlag);
+    iFormat = ProcessFormatTestValidate(pDocView, validate, bVersionFlag);
+    if (!bVersionFlag)
+      bVersionFlag = pDocView->GetDoc()->GetXFADoc()->is_scripting();
+    XFA_EventErrorAccumulate(
+        &iRet,
+        ProcessNullTestValidate(pDocView, validate, iFlags, bVersionFlag));
   }
+  if (iFormat != XFA_EventError::kSuccess && hasBoolResult)
+    ProcessScriptTestValidate(pDocView, validate, iRet, bRet, bVersionFlag);
 
-  if (iFormat != XFA_EVENTERROR_Success && hasBoolResult)
-    ProcessScriptTestValidate(docView, validate, iRet, bRet, bVersionFlag);
-
-  return iRet | iFormat;
+  XFA_EventErrorAccumulate(&iRet, iFormat);
+  return iRet;
 }
 
 WideString CXFA_Node::GetValidateCaptionName(bool bVersionFlag) {
@@ -1955,50 +2689,46 @@
 WideString CXFA_Node::GetValidateMessage(bool bError, bool bVersionFlag) {
   WideString wsCaptionName = GetValidateCaptionName(bVersionFlag);
   if (bVersionFlag)
-    return WideString::Format(L"%ls validation failed", wsCaptionName.c_str());
-  if (bError) {
-    return WideString::Format(L"The value you entered for %ls is invalid.",
-                              wsCaptionName.c_str());
+    return wsCaptionName + L" validation failed";
+  WideString result =
+      L"The value you entered for " + wsCaptionName + L" is invalid.";
+  if (!bError) {
+    result +=
+        L" To ignore validations for " + wsCaptionName + L", click Ignore.";
   }
-  return WideString::Format(
-      L"The value you entered for %ls is invalid. To ignore "
-      L"validations for %ls, click Ignore.",
-      wsCaptionName.c_str(), wsCaptionName.c_str());
+  return result;
 }
 
-int32_t CXFA_Node::ExecuteScript(CXFA_FFDocView* docView,
-                                 CXFA_Script* script,
-                                 CXFA_EventParam* pEventParam) {
-  bool bRet;
-  int32_t iRet;
-  std::tie(iRet, bRet) = ExecuteBoolScript(docView, script, pEventParam);
-  return iRet;
+XFA_EventError CXFA_Node::ExecuteScript(CXFA_FFDocView* pDocView,
+                                        CXFA_Script* script,
+                                        CXFA_EventParam* pEventParam) {
+  return ExecuteBoolScript(pDocView, script, pEventParam).first;
 }
 
-std::pair<int32_t, bool> CXFA_Node::ExecuteBoolScript(
-    CXFA_FFDocView* docView,
+std::pair<XFA_EventError, bool> CXFA_Node::ExecuteBoolScript(
+    CXFA_FFDocView* pDocView,
     CXFA_Script* script,
     CXFA_EventParam* pEventParam) {
   if (m_ExecuteRecursionDepth > kMaxExecuteRecursion)
-    return {XFA_EVENTERROR_Success, false};
+    return {XFA_EventError::kSuccess, false};
 
   ASSERT(pEventParam);
   if (!script)
-    return {XFA_EVENTERROR_NotExist, false};
-  if (script->GetRunAt() == XFA_AttributeEnum::Server)
-    return {XFA_EVENTERROR_Disabled, false};
+    return {XFA_EventError::kNotExist, false};
+  if (script->GetRunAt() == XFA_AttributeValue::Server)
+    return {XFA_EventError::kDisabled, false};
 
   WideString wsExpression = script->GetExpression();
   if (wsExpression.IsEmpty())
-    return {XFA_EVENTERROR_NotExist, false};
+    return {XFA_EventError::kNotExist, false};
 
   CXFA_Script::Type eScriptType = script->GetContentType();
   if (eScriptType == CXFA_Script::Type::Unknown)
-    return {XFA_EVENTERROR_Success, false};
+    return {XFA_EventError::kSuccess, false};
 
-  CXFA_FFDoc* pDoc = docView->GetDoc();
+  CXFA_FFDoc* pDoc = pDocView->GetDoc();
   CFXJSE_Engine* pContext = pDoc->GetXFADoc()->GetScriptContext();
-  pContext->SetEventParam(*pEventParam);
+  pContext->SetEventParam(pEventParam);
   pContext->SetRunAtType(script->GetRunAt());
 
   std::vector<CXFA_Node*> refNodes;
@@ -2016,25 +2746,24 @@
                                pTmpRetValue.get(), this);
   }
 
-  int32_t iRet = XFA_EVENTERROR_Error;
+  XFA_EventError iRet = XFA_EventError::kError;
   if (bRet) {
-    iRet = XFA_EVENTERROR_Success;
+    iRet = XFA_EventError::kSuccess;
     if (pEventParam->m_eType == XFA_EVENT_Calculate ||
         pEventParam->m_eType == XFA_EVENT_InitCalculate) {
       if (!pTmpRetValue->IsUndefined()) {
         if (!pTmpRetValue->IsNull())
           pEventParam->m_wsResult = pTmpRetValue->ToWideString();
 
-        iRet = XFA_EVENTERROR_Success;
+        iRet = XFA_EventError::kSuccess;
       } else {
-        iRet = XFA_EVENTERROR_Error;
+        iRet = XFA_EventError::kError;
       }
       if (pEventParam->m_eType == XFA_EVENT_InitCalculate) {
-        if ((iRet == XFA_EVENTERROR_Success) &&
+        if ((iRet == XFA_EventError::kSuccess) &&
             (GetRawValue() != pEventParam->m_wsResult)) {
-          GetWidgetAcc()->SetValue(XFA_VALUEPICTURE_Raw,
-                                   pEventParam->m_wsResult);
-          docView->AddValidateWidget(GetWidgetAcc());
+          SetValue(XFA_VALUEPICTURE_Raw, pEventParam->m_wsResult);
+          pDocView->AddValidateNode(this);
         }
       }
       for (CXFA_Node* pRefNode : refNodes) {
@@ -2053,162 +2782,3228 @@
     }
   }
   pContext->SetNodesOfRunScript(nullptr);
+  pContext->SetEventParam(nullptr);
 
-  return {iRet, pTmpRetValue->IsBoolean() ? pTmpRetValue->ToBoolean() : false};
+  return {iRet, pTmpRetValue->IsBoolean() && pTmpRetValue->ToBoolean()};
 }
 
-WideString CXFA_Node::GetBarcodeType() {
-  CXFA_Node* pUIChild = GetWidgetAcc()->GetUIChild();
-  return pUIChild
-             ? WideString(pUIChild->JSObject()->GetCData(XFA_Attribute::Type))
-             : WideString();
+std::pair<XFA_FFWidgetType, CXFA_Ui*>
+CXFA_Node::CreateChildUIAndValueNodesIfNeeded() {
+  XFA_Element eType = GetElementType();
+  ASSERT(eType == XFA_Element::Field || eType == XFA_Element::Draw);
+
+  // Both Field and Draw have a UI property. We should always be able to
+  // retrieve or create the UI element. If we can't something is wrong.
+  CXFA_Ui* pUI = JSObject()->GetOrCreateProperty<CXFA_Ui>(0, XFA_Element::Ui);
+  ASSERT(pUI);
+
+  CXFA_Node* pUIChild = nullptr;
+  // Search through the children of the UI node to see if we have any of our
+  // One-Of entries. If so, that is the node associated with our UI.
+  for (CXFA_Node* pChild = pUI->GetFirstChild(); pChild;
+       pChild = pChild->GetNextSibling()) {
+    if (pUI->IsAOneOfChild(pChild)) {
+      pUIChild = pChild;
+      break;
+    }
+  }
+
+  XFA_FFWidgetType widget_type = XFA_FFWidgetType::kNone;
+  XFA_Element expected_ui_child_type = XFA_Element::Unknown;
+
+  // Both Field and Draw nodes have a Value child. So, we should either always
+  // have it, or always create it. If we don't get the Value child for some
+  // reason something has gone really wrong.
+  CXFA_Value* value =
+      JSObject()->GetOrCreateProperty<CXFA_Value>(0, XFA_Element::Value);
+  ASSERT(value);
+
+  // The Value nodes only have One-Of children. So, if we have a first child
+  // that child must be the type we want to use.
+  CXFA_Node* child = value->GetFirstChild();
+  if (child) {
+    switch (child->GetElementType()) {
+      case XFA_Element::Boolean:
+        expected_ui_child_type = XFA_Element::CheckButton;
+        break;
+      case XFA_Element::Integer:
+      case XFA_Element::Decimal:
+      case XFA_Element::Float:
+        expected_ui_child_type = XFA_Element::NumericEdit;
+        break;
+      case XFA_Element::ExData:
+      case XFA_Element::Text:
+        expected_ui_child_type = XFA_Element::TextEdit;
+        widget_type = XFA_FFWidgetType::kText;
+        break;
+      case XFA_Element::Date:
+      case XFA_Element::Time:
+      case XFA_Element::DateTime:
+        expected_ui_child_type = XFA_Element::DateTimeEdit;
+        break;
+      case XFA_Element::Image:
+        expected_ui_child_type = XFA_Element::ImageEdit;
+        widget_type = XFA_FFWidgetType::kImage;
+        break;
+      case XFA_Element::Arc:
+        expected_ui_child_type = XFA_Element::DefaultUi;
+        widget_type = XFA_FFWidgetType::kArc;
+        break;
+      case XFA_Element::Line:
+        expected_ui_child_type = XFA_Element::DefaultUi;
+        widget_type = XFA_FFWidgetType::kLine;
+        break;
+      case XFA_Element::Rectangle:
+        expected_ui_child_type = XFA_Element::DefaultUi;
+        widget_type = XFA_FFWidgetType::kRectangle;
+        break;
+      default:
+        NOTREACHED();
+        break;
+    }
+  }
+
+  if (eType == XFA_Element::Draw) {
+    if (pUIChild && pUIChild->GetElementType() == XFA_Element::TextEdit) {
+      widget_type = XFA_FFWidgetType::kText;
+    } else if (pUIChild &&
+               pUIChild->GetElementType() == XFA_Element::ImageEdit) {
+      widget_type = XFA_FFWidgetType::kImage;
+    } else if (widget_type == XFA_FFWidgetType::kNone) {
+      widget_type = XFA_FFWidgetType::kText;
+    }
+  } else if (eType == XFA_Element::Field) {
+    if (pUIChild && pUIChild->GetElementType() == XFA_Element::DefaultUi) {
+      widget_type = XFA_FFWidgetType::kTextEdit;
+    } else if (pUIChild) {
+      widget_type = pUIChild->GetDefaultFFWidgetType();
+    } else if (expected_ui_child_type == XFA_Element::Unknown) {
+      widget_type = XFA_FFWidgetType::kTextEdit;
+    }
+  } else {
+    NOTREACHED();
+  }
+
+  if (!pUIChild) {
+    if (expected_ui_child_type == XFA_Element::Unknown)
+      expected_ui_child_type = XFA_Element::TextEdit;
+    pUIChild = pUI->JSObject()->GetOrCreateProperty<CXFA_Node>(
+        0, expected_ui_child_type);
+  }
+
+  CreateValueNodeIfNeeded(value, pUIChild);
+  return {widget_type, pUI};
 }
 
-Optional<BC_CHAR_ENCODING> CXFA_Node::GetBarcodeAttribute_CharEncoding() {
-  Optional<WideString> wsCharEncoding =
-      GetWidgetAcc()->GetUIChild()->JSObject()->TryCData(
-          XFA_Attribute::CharEncoding, true);
-  if (!wsCharEncoding)
-    return {};
-  if (wsCharEncoding->CompareNoCase(L"UTF-16"))
-    return {CHAR_ENCODING_UNICODE};
-  if (wsCharEncoding->CompareNoCase(L"UTF-8"))
-    return {CHAR_ENCODING_UTF8};
-  return {};
+XFA_FFWidgetType CXFA_Node::GetDefaultFFWidgetType() const {
+  NOTREACHED();
+  return XFA_FFWidgetType::kNone;
 }
 
-Optional<bool> CXFA_Node::GetBarcodeAttribute_Checksum() {
-  Optional<XFA_AttributeEnum> checksum =
-      GetWidgetAcc()->GetUIChild()->JSObject()->TryEnum(XFA_Attribute::Checksum,
-                                                        true);
-  if (!checksum)
-    return {};
+CXFA_Node* CXFA_Node::CreateUINodeIfNeeded(CXFA_Ui* ui, XFA_Element type) {
+  return ui->JSObject()->GetOrCreateProperty<CXFA_Node>(0, type);
+}
 
-  switch (*checksum) {
-    case XFA_AttributeEnum::None:
-      return {false};
-    case XFA_AttributeEnum::Auto:
-      return {true};
-    case XFA_AttributeEnum::Checksum_1mod10:
-    case XFA_AttributeEnum::Checksum_1mod10_1mod11:
-    case XFA_AttributeEnum::Checksum_2mod10:
+void CXFA_Node::CreateValueNodeIfNeeded(CXFA_Value* value,
+                                        CXFA_Node* pUIChild) {
+  // Value nodes only have one child. If we have one already we're done.
+  if (value->GetFirstChild())
+    return;
+
+  // Create the Value node for our UI if needed.
+  XFA_Element valueType = pUIChild->GetValueNodeType();
+  if (pUIChild->GetElementType() == XFA_Element::CheckButton) {
+    CXFA_Items* pItems = GetChild<CXFA_Items>(0, XFA_Element::Items, false);
+    if (pItems) {
+      CXFA_Node* pItem =
+          pItems->GetChild<CXFA_Node>(0, XFA_Element::Unknown, false);
+      if (pItem)
+        valueType = pItem->GetElementType();
+    }
+  }
+  value->JSObject()->GetOrCreateProperty<CXFA_Node>(0, valueType);
+}
+
+XFA_Element CXFA_Node::GetValueNodeType() const {
+  return XFA_Element::Text;
+}
+
+CXFA_Node* CXFA_Node::GetUIChildNode() {
+  ASSERT(HasCreatedUIWidget());
+
+  if (ff_widget_type_ != XFA_FFWidgetType::kNone)
+    return ui_ ? ui_->GetFirstChild() : nullptr;
+
+  XFA_Element type = GetElementType();
+  if (type == XFA_Element::Field || type == XFA_Element::Draw) {
+    std::tie(ff_widget_type_, ui_) = CreateChildUIAndValueNodesIfNeeded();
+  } else if (type == XFA_Element::Subform) {
+    ff_widget_type_ = XFA_FFWidgetType::kSubform;
+  } else if (type == XFA_Element::ExclGroup) {
+    ff_widget_type_ = XFA_FFWidgetType::kExclGroup;
+  } else {
+    NOTREACHED();
+  }
+  return ui_ ? ui_->GetFirstChild() : nullptr;
+}
+
+XFA_FFWidgetType CXFA_Node::GetFFWidgetType() {
+  GetUIChildNode();
+  return ff_widget_type_;
+}
+
+CXFA_Border* CXFA_Node::GetUIBorder() {
+  CXFA_Node* pUIChild = GetUIChildNode();
+  return pUIChild ? pUIChild->JSObject()->GetProperty<CXFA_Border>(
+                        0, XFA_Element::Border)
+                  : nullptr;
+}
+
+CFX_RectF CXFA_Node::GetUIMargin() {
+  CXFA_Node* pUIChild = GetUIChildNode();
+  if (!pUIChild)
+    return CFX_RectF();
+
+  CXFA_Margin* mgUI =
+      pUIChild->JSObject()->GetProperty<CXFA_Margin>(0, XFA_Element::Margin);
+  if (!mgUI)
+    return CFX_RectF();
+
+  CXFA_Border* border = GetUIBorder();
+  if (border && border->GetPresence() != XFA_AttributeValue::Visible)
+    return CFX_RectF();
+
+  Optional<float> left = mgUI->TryLeftInset();
+  Optional<float> top = mgUI->TryTopInset();
+  Optional<float> right = mgUI->TryRightInset();
+  Optional<float> bottom = mgUI->TryBottomInset();
+  if (border) {
+    bool bVisible = false;
+    float fThickness = 0;
+    XFA_AttributeValue iType = XFA_AttributeValue::Unknown;
+    std::tie(iType, bVisible, fThickness) = border->Get3DStyle();
+    if (!left || !top || !right || !bottom) {
+      std::vector<CXFA_Stroke*> strokes = border->GetStrokes();
+      if (!top)
+        top = GetEdgeThickness(strokes, bVisible, 0);
+      if (!right)
+        right = GetEdgeThickness(strokes, bVisible, 1);
+      if (!bottom)
+        bottom = GetEdgeThickness(strokes, bVisible, 2);
+      if (!left)
+        left = GetEdgeThickness(strokes, bVisible, 3);
+    }
+  }
+  return CFX_RectF(left.value_or(0.0), top.value_or(0.0), right.value_or(0.0),
+                   bottom.value_or(0.0));
+}
+
+std::vector<CXFA_Event*> CXFA_Node::GetEventByActivity(
+    XFA_AttributeValue iActivity,
+    bool bIsFormReady) {
+  std::vector<CXFA_Event*> events;
+  for (CXFA_Node* node : GetNodeListForType(XFA_Element::Event)) {
+    auto* event = static_cast<CXFA_Event*>(node);
+    if (event->GetActivity() != iActivity)
+      continue;
+
+    if (iActivity != XFA_AttributeValue::Ready) {
+      events.push_back(event);
+      continue;
+    }
+
+    WideString wsRef = event->GetRef();
+    if (bIsFormReady) {
+      if (wsRef == WideStringView(L"$form"))
+        events.push_back(event);
+      continue;
+    }
+
+    if (wsRef == WideStringView(L"$layout"))
+      events.push_back(event);
+  }
+  return events;
+}
+
+void CXFA_Node::ResetData() {
+  WideString wsValue;
+  switch (GetFFWidgetType()) {
+    case XFA_FFWidgetType::kImageEdit: {
+      CXFA_Value* imageValue = GetDefaultValueIfExists();
+      CXFA_Image* image = imageValue ? imageValue->GetImageIfExists() : nullptr;
+      WideString wsContentType, wsHref;
+      if (image) {
+        wsValue = image->GetContent();
+        wsContentType = image->GetContentType();
+        wsHref = image->GetHref();
+      }
+      SetImageEdit(wsContentType, wsHref, wsValue);
+      break;
+    }
+    case XFA_FFWidgetType::kExclGroup: {
+      CXFA_Node* pNextChild = GetFirstContainerChild();
+      while (pNextChild) {
+        CXFA_Node* pChild = pNextChild;
+        if (!pChild->IsWidgetReady())
+          continue;
+
+        bool done = false;
+        if (wsValue.IsEmpty()) {
+          CXFA_Value* defValue = pChild->GetDefaultValueIfExists();
+          if (defValue) {
+            wsValue = defValue->GetChildValueContent();
+            SetValue(XFA_VALUEPICTURE_Raw, wsValue);
+            pChild->SetValue(XFA_VALUEPICTURE_Raw, wsValue);
+            done = true;
+          }
+        }
+        if (!done) {
+          CXFA_Items* pItems =
+              pChild->GetChild<CXFA_Items>(0, XFA_Element::Items, false);
+          if (!pItems)
+            continue;
+
+          WideString itemText;
+          if (pItems->CountChildren(XFA_Element::Unknown, false) > 1) {
+            itemText =
+                pItems->GetChild<CXFA_Node>(1, XFA_Element::Unknown, false)
+                    ->JSObject()
+                    ->GetContent(false);
+          }
+          pChild->SetValue(XFA_VALUEPICTURE_Raw, itemText);
+        }
+        pNextChild = pChild->GetNextContainerSibling();
+      }
+      break;
+    }
+    case XFA_FFWidgetType::kChoiceList:
+      ClearAllSelections();
+      FALLTHROUGH;
+    default: {
+      CXFA_Value* defValue = GetDefaultValueIfExists();
+      if (defValue)
+        wsValue = defValue->GetChildValueContent();
+
+      SetValue(XFA_VALUEPICTURE_Raw, wsValue);
+      break;
+    }
+  }
+}
+
+void CXFA_Node::SetImageEdit(const WideString& wsContentType,
+                             const WideString& wsHref,
+                             const WideString& wsData) {
+  CXFA_Value* formValue = GetFormValueIfExists();
+  CXFA_Image* image = formValue ? formValue->GetImageIfExists() : nullptr;
+  if (image) {
+    image->SetContentType(WideString(wsContentType));
+    image->SetHref(wsHref);
+  }
+
+  JSObject()->SetContent(wsData, GetFormatDataValue(wsData), true, false, true);
+
+  CXFA_Node* pBind = GetBindData();
+  if (!pBind) {
+    if (image)
+      image->SetTransferEncoding(XFA_AttributeValue::Base64);
+    return;
+  }
+  pBind->JSObject()->SetCData(XFA_Attribute::ContentType, wsContentType, false,
+                              false);
+  CXFA_Node* pHrefNode = pBind->GetFirstChild();
+  if (pHrefNode) {
+    pHrefNode->JSObject()->SetCData(XFA_Attribute::Value, wsHref, false, false);
+    return;
+  }
+  CFX_XMLElement* pElement = ToXMLElement(pBind->GetXMLMappingNode());
+  pElement->SetAttribute(L"href", wsHref);
+}
+
+void CXFA_Node::CalcCaptionSize(CXFA_FFDoc* doc, CFX_SizeF* pszCap) {
+  CXFA_Caption* caption = GetCaptionIfExists();
+  if (!caption || !caption->IsVisible())
+    return;
+
+  LoadCaption(doc);
+
+  const float fCapReserve = caption->GetReserve();
+  const XFA_AttributeValue iCapPlacement = caption->GetPlacementType();
+  const bool bReserveExit = fCapReserve > 0.01;
+  const bool bVert = iCapPlacement == XFA_AttributeValue::Top ||
+                     iCapPlacement == XFA_AttributeValue::Bottom;
+  CXFA_TextLayout* pCapTextLayout =
+      m_pLayoutData->AsFieldLayoutData()->m_pCapTextLayout.get();
+  if (pCapTextLayout) {
+    if (!bVert && GetFFWidgetType() != XFA_FFWidgetType::kButton)
+      pszCap->width = fCapReserve;
+
+    CFX_SizeF minSize;
+    *pszCap = pCapTextLayout->CalcSize(minSize, *pszCap);
+    if (bReserveExit)
+      bVert ? pszCap->height = fCapReserve : pszCap->width = fCapReserve;
+  } else {
+    float fFontSize = 10.0f;
+    CXFA_Font* font = caption->GetFontIfExists();
+    if (font) {
+      fFontSize = font->GetFontSize();
+    } else {
+      CXFA_Font* widgetfont = GetFontIfExists();
+      if (widgetfont)
+        fFontSize = widgetfont->GetFontSize();
+    }
+
+    if (bVert) {
+      pszCap->height = fCapReserve > 0 ? fCapReserve : fFontSize;
+    } else {
+      pszCap->width = fCapReserve > 0 ? fCapReserve : 0;
+      pszCap->height = fFontSize;
+    }
+  }
+
+  CXFA_Margin* captionMargin = caption->GetMarginIfExists();
+  if (!captionMargin)
+    return;
+
+  float fLeftInset = captionMargin->GetLeftInset();
+  float fTopInset = captionMargin->GetTopInset();
+  float fRightInset = captionMargin->GetRightInset();
+  float fBottomInset = captionMargin->GetBottomInset();
+  if (bReserveExit) {
+    bVert ? (pszCap->width += fLeftInset + fRightInset)
+          : (pszCap->height += fTopInset + fBottomInset);
+  } else {
+    pszCap->width += fLeftInset + fRightInset;
+    pszCap->height += fTopInset + fBottomInset;
+  }
+}
+
+bool CXFA_Node::CalculateFieldAutoSize(CXFA_FFDoc* doc, CFX_SizeF* pSize) {
+  CFX_SizeF szCap;
+  CalcCaptionSize(doc, &szCap);
+
+  CFX_RectF rtUIMargin = GetUIMargin();
+  pSize->width += rtUIMargin.left + rtUIMargin.width;
+  pSize->height += rtUIMargin.top + rtUIMargin.height;
+  if (szCap.width > 0 && szCap.height > 0) {
+    CXFA_Caption* caption = GetCaptionIfExists();
+    XFA_AttributeValue placement = caption
+                                       ? caption->GetPlacementType()
+                                       : CXFA_Caption::kDefaultPlacementType;
+    switch (placement) {
+      case XFA_AttributeValue::Left:
+      case XFA_AttributeValue::Right:
+      case XFA_AttributeValue::Inline: {
+        pSize->width += szCap.width;
+        pSize->height = std::max(pSize->height, szCap.height);
+      } break;
+      case XFA_AttributeValue::Top:
+      case XFA_AttributeValue::Bottom: {
+        pSize->height += szCap.height;
+        pSize->width = std::max(pSize->width, szCap.width);
+        break;
+      }
+      default:
+        break;
+    }
+  }
+  return CalculateWidgetAutoSize(pSize);
+}
+
+bool CXFA_Node::CalculateWidgetAutoSize(CFX_SizeF* pSize) {
+  CXFA_Margin* margin = GetMarginIfExists();
+  if (margin) {
+    pSize->width += margin->GetLeftInset() + margin->GetRightInset();
+    pSize->height += margin->GetTopInset() + margin->GetBottomInset();
+  }
+
+  CXFA_Para* para = GetParaIfExists();
+  if (para)
+    pSize->width += para->GetMarginLeft() + para->GetTextIndent();
+
+  Optional<float> width = TryWidth();
+  if (width) {
+    pSize->width = *width;
+  } else {
+    Optional<float> min = TryMinWidth();
+    if (min)
+      pSize->width = std::max(pSize->width, *min);
+
+    Optional<float> max = TryMaxWidth();
+    if (max && *max > 0)
+      pSize->width = std::min(pSize->width, *max);
+  }
+
+  Optional<float> height = TryHeight();
+  if (height) {
+    pSize->height = *height;
+  } else {
+    Optional<float> min = TryMinHeight();
+    if (min)
+      pSize->height = std::max(pSize->height, *min);
+
+    Optional<float> max = TryMaxHeight();
+    if (max && *max > 0)
+      pSize->height = std::min(pSize->height, *max);
+  }
+  return true;
+}
+
+void CXFA_Node::CalculateTextContentSize(CXFA_FFDoc* doc, CFX_SizeF* pSize) {
+  float fFontSize = GetFontSize();
+  WideString wsText = GetValue(XFA_VALUEPICTURE_Display);
+  if (wsText.IsEmpty()) {
+    pSize->height += fFontSize;
+    return;
+  }
+
+  if (wsText.Back() == L'\n')
+    wsText += L'\n';
+
+  CXFA_FieldLayoutData* layoutData = m_pLayoutData->AsFieldLayoutData();
+  if (!layoutData->m_pTextOut) {
+    layoutData->m_pTextOut = pdfium::MakeUnique<CFDE_TextOut>();
+    CFDE_TextOut* pTextOut = layoutData->m_pTextOut.get();
+    pTextOut->SetFont(GetFDEFont(doc));
+    pTextOut->SetFontSize(fFontSize);
+    pTextOut->SetLineBreakTolerance(fFontSize * 0.2f);
+    pTextOut->SetLineSpace(GetLineHeight());
+
+    FDE_TextStyle dwStyles;
+    dwStyles.last_line_height_ = true;
+    if (GetFFWidgetType() == XFA_FFWidgetType::kTextEdit && IsMultiLine())
+      dwStyles.line_wrap_ = true;
+
+    pTextOut->SetStyles(dwStyles);
+  }
+  layoutData->m_pTextOut->CalcLogicSize(wsText.AsStringView(), pSize);
+}
+
+bool CXFA_Node::CalculateTextEditAutoSize(CXFA_FFDoc* doc, CFX_SizeF* pSize) {
+  if (pSize->width > 0) {
+    CFX_SizeF szOrz = *pSize;
+    CFX_SizeF szCap;
+    CalcCaptionSize(doc, &szCap);
+    bool bCapExit = szCap.width > 0.01 && szCap.height > 0.01;
+    XFA_AttributeValue iCapPlacement = XFA_AttributeValue::Unknown;
+    if (bCapExit) {
+      CXFA_Caption* caption = GetCaptionIfExists();
+      iCapPlacement = caption ? caption->GetPlacementType()
+                              : CXFA_Caption::kDefaultPlacementType;
+      switch (iCapPlacement) {
+        case XFA_AttributeValue::Left:
+        case XFA_AttributeValue::Right:
+        case XFA_AttributeValue::Inline: {
+          pSize->width -= szCap.width;
+          break;
+        }
+        default:
+          break;
+      }
+    }
+    CFX_RectF rtUIMargin = GetUIMargin();
+    pSize->width -= rtUIMargin.left + rtUIMargin.width;
+    CXFA_Margin* margin = GetMarginIfExists();
+    if (margin)
+      pSize->width -= margin->GetLeftInset() + margin->GetRightInset();
+
+    CalculateTextContentSize(doc, pSize);
+    pSize->height += rtUIMargin.top + rtUIMargin.height;
+    if (bCapExit) {
+      switch (iCapPlacement) {
+        case XFA_AttributeValue::Left:
+        case XFA_AttributeValue::Right:
+        case XFA_AttributeValue::Inline: {
+          pSize->height = std::max(pSize->height, szCap.height);
+        } break;
+        case XFA_AttributeValue::Top:
+        case XFA_AttributeValue::Bottom: {
+          pSize->height += szCap.height;
+          break;
+        }
+        default:
+          break;
+      }
+    }
+    pSize->width = szOrz.width;
+    return CalculateWidgetAutoSize(pSize);
+  }
+  CalculateTextContentSize(doc, pSize);
+  return CalculateFieldAutoSize(doc, pSize);
+}
+
+bool CXFA_Node::CalculateCheckButtonAutoSize(CXFA_FFDoc* doc,
+                                             CFX_SizeF* pSize) {
+  float fCheckSize = GetCheckButtonSize();
+  *pSize = CFX_SizeF(fCheckSize, fCheckSize);
+  return CalculateFieldAutoSize(doc, pSize);
+}
+
+bool CXFA_Node::CalculatePushButtonAutoSize(CXFA_FFDoc* doc, CFX_SizeF* pSize) {
+  CalcCaptionSize(doc, pSize);
+  return CalculateWidgetAutoSize(pSize);
+}
+
+CFX_SizeF CXFA_Node::CalculateImageSize(float img_width,
+                                        float img_height,
+                                        const CFX_Size& dpi) {
+  CFX_RectF rtImage(0, 0, XFA_UnitPx2Pt(img_width, dpi.width),
+                    XFA_UnitPx2Pt(img_height, dpi.height));
+
+  CFX_RectF rtFit;
+  Optional<float> width = TryWidth();
+  if (width) {
+    rtFit.width = *width;
+    GetWidthWithoutMargin(rtFit.width);
+  } else {
+    rtFit.width = rtImage.width;
+  }
+
+  Optional<float> height = TryHeight();
+  if (height) {
+    rtFit.height = *height;
+    GetHeightWithoutMargin(rtFit.height);
+  } else {
+    rtFit.height = rtImage.height;
+  }
+
+  return rtFit.Size();
+}
+
+bool CXFA_Node::CalculateImageAutoSize(CXFA_FFDoc* doc, CFX_SizeF* pSize) {
+  if (!GetImageImage())
+    LoadImageImage(doc);
+
+  pSize->clear();
+  RetainPtr<CFX_DIBitmap> pBitmap = GetImageImage();
+  if (!pBitmap)
+    return CalculateWidgetAutoSize(pSize);
+
+  *pSize = CalculateImageSize(pBitmap->GetWidth(), pBitmap->GetHeight(),
+                              GetImageDpi());
+  return CalculateWidgetAutoSize(pSize);
+}
+
+bool CXFA_Node::CalculateImageEditAutoSize(CXFA_FFDoc* doc, CFX_SizeF* pSize) {
+  if (!GetImageEditImage())
+    LoadImageEditImage(doc);
+
+  pSize->clear();
+  RetainPtr<CFX_DIBitmap> pBitmap = GetImageEditImage();
+  if (!pBitmap)
+    return CalculateFieldAutoSize(doc, pSize);
+
+  *pSize = CalculateImageSize(pBitmap->GetWidth(), pBitmap->GetHeight(),
+                              GetImageEditDpi());
+  return CalculateFieldAutoSize(doc, pSize);
+}
+
+bool CXFA_Node::LoadImageImage(CXFA_FFDoc* doc) {
+  InitLayoutData();
+  return m_pLayoutData->AsImageLayoutData()->LoadImageData(doc, this);
+}
+
+bool CXFA_Node::LoadImageEditImage(CXFA_FFDoc* doc) {
+  InitLayoutData();
+  return m_pLayoutData->AsFieldLayoutData()->AsImageEditData()->LoadImageData(
+      doc, this);
+}
+
+CFX_Size CXFA_Node::GetImageDpi() const {
+  CXFA_ImageLayoutData* pData = m_pLayoutData->AsImageLayoutData();
+  return CFX_Size(pData->m_iImageXDpi, pData->m_iImageYDpi);
+}
+
+CFX_Size CXFA_Node::GetImageEditDpi() const {
+  CXFA_ImageEditData* pData =
+      m_pLayoutData->AsFieldLayoutData()->AsImageEditData();
+  return CFX_Size(pData->m_iImageXDpi, pData->m_iImageYDpi);
+}
+
+float CXFA_Node::CalculateWidgetAutoWidth(float fWidthCalc) {
+  CXFA_Margin* margin = GetMarginIfExists();
+  if (margin)
+    fWidthCalc += margin->GetLeftInset() + margin->GetRightInset();
+
+  Optional<float> min = TryMinWidth();
+  if (min)
+    fWidthCalc = std::max(fWidthCalc, *min);
+
+  Optional<float> max = TryMaxWidth();
+  if (max && *max > 0)
+    fWidthCalc = std::min(fWidthCalc, *max);
+
+  return fWidthCalc;
+}
+
+float CXFA_Node::GetWidthWithoutMargin(float fWidthCalc) const {
+  CXFA_Margin* margin = GetMarginIfExists();
+  if (margin)
+    fWidthCalc -= margin->GetLeftInset() + margin->GetRightInset();
+  return fWidthCalc;
+}
+
+float CXFA_Node::CalculateWidgetAutoHeight(float fHeightCalc) {
+  CXFA_Margin* margin = GetMarginIfExists();
+  if (margin)
+    fHeightCalc += margin->GetTopInset() + margin->GetBottomInset();
+
+  Optional<float> min = TryMinHeight();
+  if (min)
+    fHeightCalc = std::max(fHeightCalc, *min);
+
+  Optional<float> max = TryMaxHeight();
+  if (max && *max > 0)
+    fHeightCalc = std::min(fHeightCalc, *max);
+
+  return fHeightCalc;
+}
+
+float CXFA_Node::GetHeightWithoutMargin(float fHeightCalc) const {
+  CXFA_Margin* margin = GetMarginIfExists();
+  if (margin)
+    fHeightCalc -= margin->GetTopInset() + margin->GetBottomInset();
+  return fHeightCalc;
+}
+
+void CXFA_Node::StartWidgetLayout(CXFA_FFDoc* doc,
+                                  float* pCalcWidth,
+                                  float* pCalcHeight) {
+  InitLayoutData();
+
+  if (GetFFWidgetType() == XFA_FFWidgetType::kText) {
+    m_pLayoutData->m_fWidgetHeight = TryHeight().value_or(-1);
+    StartTextLayout(doc, pCalcWidth, pCalcHeight);
+    return;
+  }
+  if (*pCalcWidth > 0 && *pCalcHeight > 0)
+    return;
+
+  m_pLayoutData->m_fWidgetHeight = -1;
+  float fWidth = 0;
+  if (*pCalcWidth > 0 && *pCalcHeight < 0) {
+    Optional<float> height = TryHeight();
+    if (height) {
+      *pCalcHeight = *height;
+    } else {
+      CFX_SizeF size = CalculateAccWidthAndHeight(doc, *pCalcWidth);
+      *pCalcWidth = size.width;
+      *pCalcHeight = size.height;
+    }
+
+    m_pLayoutData->m_fWidgetHeight = *pCalcHeight;
+    return;
+  }
+  if (*pCalcWidth < 0 && *pCalcHeight < 0) {
+    Optional<float> height;
+    Optional<float> width = TryWidth();
+    if (width) {
+      fWidth = *width;
+
+      height = TryHeight();
+      if (height)
+        *pCalcHeight = *height;
+    }
+    if (!width || !height) {
+      CFX_SizeF size = CalculateAccWidthAndHeight(doc, fWidth);
+      *pCalcWidth = size.width;
+      *pCalcHeight = size.height;
+    } else {
+      *pCalcWidth = fWidth;
+    }
+  }
+  m_pLayoutData->m_fWidgetHeight = *pCalcHeight;
+}
+
+CFX_SizeF CXFA_Node::CalculateAccWidthAndHeight(CXFA_FFDoc* doc, float fWidth) {
+  CFX_SizeF sz(fWidth, m_pLayoutData->m_fWidgetHeight);
+  switch (GetFFWidgetType()) {
+    case XFA_FFWidgetType::kBarcode:
+    case XFA_FFWidgetType::kChoiceList:
+    case XFA_FFWidgetType::kSignature:
+      CalculateFieldAutoSize(doc, &sz);
+      break;
+    case XFA_FFWidgetType::kImageEdit:
+      CalculateImageEditAutoSize(doc, &sz);
+      break;
+    case XFA_FFWidgetType::kButton:
+      CalculatePushButtonAutoSize(doc, &sz);
+      break;
+    case XFA_FFWidgetType::kCheckButton:
+      CalculateCheckButtonAutoSize(doc, &sz);
+      break;
+    case XFA_FFWidgetType::kDateTimeEdit:
+    case XFA_FFWidgetType::kNumericEdit:
+    case XFA_FFWidgetType::kPasswordEdit:
+    case XFA_FFWidgetType::kTextEdit:
+      CalculateTextEditAutoSize(doc, &sz);
+      break;
+    case XFA_FFWidgetType::kImage:
+      CalculateImageAutoSize(doc, &sz);
+      break;
+    case XFA_FFWidgetType::kArc:
+    case XFA_FFWidgetType::kLine:
+    case XFA_FFWidgetType::kRectangle:
+    case XFA_FFWidgetType::kSubform:
+    case XFA_FFWidgetType::kExclGroup:
+      CalculateWidgetAutoSize(&sz);
+      break;
+    case XFA_FFWidgetType::kText:
+    case XFA_FFWidgetType::kNone:
+      break;
+  }
+
+  m_pLayoutData->m_fWidgetHeight = sz.height;
+  return sz;
+}
+
+Optional<float> CXFA_Node::FindSplitPos(CXFA_FFDocView* pDocView,
+                                        size_t szBlockIndex,
+                                        float fCalcHeight) {
+  if (GetFFWidgetType() == XFA_FFWidgetType::kSubform)
+    return pdfium::nullopt;
+
+  switch (GetFFWidgetType()) {
+    case XFA_FFWidgetType::kText:
+    case XFA_FFWidgetType::kTextEdit:
+    case XFA_FFWidgetType::kNumericEdit:
+    case XFA_FFWidgetType::kPasswordEdit:
+      break;
+    default:
+      return 0.0f;
+  }
+
+  float fTopInset = 0;
+  float fBottomInset = 0;
+  if (szBlockIndex == 0) {
+    CXFA_Margin* margin = GetMarginIfExists();
+    if (margin) {
+      fTopInset = margin->GetTopInset();
+      fBottomInset = margin->GetBottomInset();
+    }
+
+    CFX_RectF rtUIMargin = GetUIMargin();
+    fTopInset += rtUIMargin.top;
+    fBottomInset += rtUIMargin.width;
+  }
+  if (GetFFWidgetType() == XFA_FFWidgetType::kText) {
+    float fHeight = fCalcHeight;
+    if (szBlockIndex == 0) {
+      fCalcHeight -= fTopInset;
+      fCalcHeight = std::max(fCalcHeight, 0.0f);
+    }
+    CXFA_TextLayout* pTextLayout =
+        m_pLayoutData->AsTextLayoutData()->GetTextLayout();
+    fCalcHeight = pTextLayout->DoSplitLayout(
+        szBlockIndex, fCalcHeight, m_pLayoutData->m_fWidgetHeight - fTopInset);
+    if (fCalcHeight != 0) {
+      if (szBlockIndex == 0)
+        fCalcHeight += fTopInset;
+      if (fabs(fHeight - fCalcHeight) < kXFAWidgetPrecision)
+        return pdfium::nullopt;
+    }
+    return fCalcHeight;
+  }
+
+  XFA_AttributeValue iCapPlacement = XFA_AttributeValue::Unknown;
+  float fCapReserve = 0;
+  if (szBlockIndex == 0) {
+    CXFA_Caption* caption = GetCaptionIfExists();
+    if (caption && !caption->IsHidden()) {
+      iCapPlacement = caption->GetPlacementType();
+      fCapReserve = caption->GetReserve();
+    }
+    if (iCapPlacement == XFA_AttributeValue::Top &&
+        fCalcHeight < fCapReserve + fTopInset) {
+      return 0.0f;
+    }
+    if (iCapPlacement == XFA_AttributeValue::Bottom &&
+        m_pLayoutData->m_fWidgetHeight - fCapReserve - fBottomInset) {
+      return 0.0f;
+    }
+    if (iCapPlacement != XFA_AttributeValue::Top)
+      fCapReserve = 0;
+  }
+  CXFA_FieldLayoutData* pFieldData = m_pLayoutData->AsFieldLayoutData();
+  int32_t iLinesCount = 0;
+  float fHeight = m_pLayoutData->m_fWidgetHeight;
+  if (GetValue(XFA_VALUEPICTURE_Display).IsEmpty()) {
+    iLinesCount = 1;
+  } else {
+    if (!pFieldData->m_pTextOut) {
+      CFX_SizeF size = CalculateAccWidthAndHeight(pDocView->GetDoc(),
+                                                  TryWidth().value_or(0));
+      fHeight = size.height;
+    }
+
+    iLinesCount = pFieldData->m_pTextOut->GetTotalLines();
+  }
+  std::vector<float>* pFieldArray = &pFieldData->m_FieldSplitArray;
+  size_t szFieldSplitCount = pFieldArray->size();
+  if (szFieldSplitCount < szBlockIndex * 3)
+    return pdfium::nullopt;
+
+  for (size_t i = 0; i < szBlockIndex * 3; i += 3) {
+    iLinesCount -= (int32_t)(*pFieldArray)[i + 1];
+    fHeight -= (*pFieldArray)[i + 2];
+  }
+  if (iLinesCount == 0)
+    return pdfium::nullopt;
+
+  float fLineHeight = GetLineHeight();
+  float fFontSize = GetFontSize();
+  float fTextHeight = iLinesCount * fLineHeight - fLineHeight + fFontSize;
+  float fSpaceAbove = 0;
+  float fStartOffset = 0;
+  if (fHeight > 0.1f && szBlockIndex == 0) {
+    fStartOffset = fTopInset;
+    fHeight -= (fTopInset + fBottomInset);
+    CXFA_Para* para = GetParaIfExists();
+    if (para) {
+      fSpaceAbove = para->GetSpaceAbove();
+      float fSpaceBelow = para->GetSpaceBelow();
+      fHeight -= (fSpaceAbove + fSpaceBelow);
+      switch (para->GetVerticalAlign()) {
+        case XFA_AttributeValue::Top:
+          fStartOffset += fSpaceAbove;
+          break;
+        case XFA_AttributeValue::Middle:
+          fStartOffset += ((fHeight - fTextHeight) / 2 + fSpaceAbove);
+          break;
+        case XFA_AttributeValue::Bottom:
+          fStartOffset += (fHeight - fTextHeight + fSpaceAbove);
+          break;
+        default:
+          NOTREACHED();
+          break;
+      }
+    }
+    if (fStartOffset < 0.1f)
+      fStartOffset = 0;
+  }
+  if (szBlockIndex > 0) {
+    size_t i = szBlockIndex - 1;
+    fStartOffset = (*pFieldArray)[i * 3] - (*pFieldArray)[i * 3 + 2];
+    if (fStartOffset < 0.1f)
+      fStartOffset = 0;
+  }
+  if (szFieldSplitCount / 3 == (szBlockIndex + 1))
+    (*pFieldArray)[0] = fStartOffset;
+  else
+    pFieldArray->push_back(fStartOffset);
+
+  XFA_VERSION version = pDocView->GetDoc()->GetXFADoc()->GetCurVersionMode();
+  bool bCanSplitNoContent = false;
+  auto value = GetParent()->JSObject()->TryEnum(XFA_Attribute::Layout, true);
+  XFA_AttributeValue eLayoutMode = value.value_or(XFA_AttributeValue::Position);
+  if ((eLayoutMode == XFA_AttributeValue::Position ||
+       eLayoutMode == XFA_AttributeValue::Tb ||
+       eLayoutMode == XFA_AttributeValue::Row ||
+       eLayoutMode == XFA_AttributeValue::Table) &&
+      version > XFA_VERSION_208) {
+    bCanSplitNoContent = true;
+  }
+  if ((eLayoutMode == XFA_AttributeValue::Tb ||
+       eLayoutMode == XFA_AttributeValue::Row ||
+       eLayoutMode == XFA_AttributeValue::Table) &&
+      version <= XFA_VERSION_208) {
+    if (fStartOffset >= fCalcHeight)
+      return 0.0f;
+
+    bCanSplitNoContent = true;
+  }
+  if (!bCanSplitNoContent ||
+      fCalcHeight - fTopInset - fSpaceAbove < fLineHeight) {
+    return 0.0f;
+  }
+
+  if (fStartOffset + kXFAWidgetPrecision >= fCalcHeight) {
+    if (szFieldSplitCount / 3 == (szBlockIndex + 1)) {
+      (*pFieldArray)[szBlockIndex * 3 + 1] = 0;
+      (*pFieldArray)[szBlockIndex * 3 + 2] = fCalcHeight;
+    } else {
+      pFieldArray->push_back(0);
+      pFieldArray->push_back(fCalcHeight);
+    }
+    return pdfium::nullopt;
+  }
+
+  if (fCalcHeight - fStartOffset < fLineHeight) {
+    fCalcHeight = fStartOffset;
+    if (szFieldSplitCount / 3 == (szBlockIndex + 1)) {
+      (*pFieldArray)[szBlockIndex * 3 + 1] = 0;
+      (*pFieldArray)[szBlockIndex * 3 + 2] = fCalcHeight;
+    } else {
+      pFieldArray->push_back(0);
+      pFieldArray->push_back(fCalcHeight);
+    }
+    return fCalcHeight;
+  }
+
+  float fTextNum =
+      fCalcHeight + kXFAWidgetPrecision - fCapReserve - fStartOffset;
+  int32_t iLineNum =
+      (int32_t)((fTextNum + (fLineHeight - fFontSize)) / fLineHeight);
+  if (iLineNum >= iLinesCount) {
+    if (fCalcHeight - fStartOffset - fTextHeight >= fFontSize) {
+      if (szFieldSplitCount / 3 == (szBlockIndex + 1)) {
+        (*pFieldArray)[szBlockIndex * 3 + 1] = iLinesCount;
+        (*pFieldArray)[szBlockIndex * 3 + 2] = fCalcHeight;
+      } else {
+        pFieldArray->push_back(iLinesCount);
+        pFieldArray->push_back(fCalcHeight);
+      }
+      return pdfium::nullopt;
+    }
+    if (fHeight - fStartOffset - fTextHeight < fFontSize) {
+      iLineNum -= 1;
+      if (iLineNum == 0)
+        return 0.0f;
+    } else {
+      iLineNum = (int32_t)(fTextNum / fLineHeight);
+    }
+  }
+  if (iLineNum <= 0)
+    return 0.0f;
+
+  float fSplitHeight = iLineNum * fLineHeight + fCapReserve + fStartOffset;
+  if (szFieldSplitCount / 3 == (szBlockIndex + 1)) {
+    (*pFieldArray)[szBlockIndex * 3 + 1] = iLineNum;
+    (*pFieldArray)[szBlockIndex * 3 + 2] = fSplitHeight;
+  } else {
+    pFieldArray->push_back(iLineNum);
+    pFieldArray->push_back(fSplitHeight);
+  }
+  if (fabs(fSplitHeight - fCalcHeight) < kXFAWidgetPrecision)
+    return pdfium::nullopt;
+  return fSplitHeight;
+}
+
+void CXFA_Node::InitLayoutData() {
+  if (m_pLayoutData)
+    return;
+
+  switch (GetFFWidgetType()) {
+    case XFA_FFWidgetType::kText:
+      m_pLayoutData = pdfium::MakeUnique<CXFA_TextLayoutData>();
+      return;
+    case XFA_FFWidgetType::kTextEdit:
+      m_pLayoutData = pdfium::MakeUnique<CXFA_TextEditData>();
+      return;
+    case XFA_FFWidgetType::kImage:
+      m_pLayoutData = pdfium::MakeUnique<CXFA_ImageLayoutData>();
+      return;
+    case XFA_FFWidgetType::kImageEdit:
+      m_pLayoutData = pdfium::MakeUnique<CXFA_ImageEditData>();
+      return;
     default:
       break;
   }
+  if (GetElementType() == XFA_Element::Field) {
+    m_pLayoutData = pdfium::MakeUnique<CXFA_FieldLayoutData>();
+    return;
+  }
+  m_pLayoutData = pdfium::MakeUnique<CXFA_WidgetLayoutData>();
+}
+
+void CXFA_Node::StartTextLayout(CXFA_FFDoc* doc,
+                                float* pCalcWidth,
+                                float* pCalcHeight) {
+  InitLayoutData();
+
+  CXFA_TextLayoutData* pTextLayoutData = m_pLayoutData->AsTextLayoutData();
+  pTextLayoutData->LoadText(doc, this);
+
+  CXFA_TextLayout* pTextLayout = pTextLayoutData->GetTextLayout();
+  float fTextHeight = 0;
+  if (*pCalcWidth > 0 && *pCalcHeight > 0) {
+    float fWidth = GetWidthWithoutMargin(*pCalcWidth);
+    pTextLayout->StartLayout(fWidth);
+    fTextHeight = *pCalcHeight;
+    fTextHeight = GetHeightWithoutMargin(fTextHeight);
+    pTextLayout->DoLayout(fTextHeight);
+    return;
+  }
+  if (*pCalcWidth > 0 && *pCalcHeight < 0) {
+    float fWidth = GetWidthWithoutMargin(*pCalcWidth);
+    pTextLayout->StartLayout(fWidth);
+  }
+  if (*pCalcWidth < 0 && *pCalcHeight < 0) {
+    Optional<float> width = TryWidth();
+    if (width) {
+      pTextLayout->StartLayout(GetWidthWithoutMargin(*width));
+      *pCalcWidth = *width;
+    } else {
+      float fMaxWidth = CalculateWidgetAutoWidth(pTextLayout->StartLayout(-1));
+      pTextLayout->StartLayout(GetWidthWithoutMargin(fMaxWidth));
+      *pCalcWidth = fMaxWidth;
+    }
+  }
+  if (m_pLayoutData->m_fWidgetHeight < 0) {
+    m_pLayoutData->m_fWidgetHeight = pTextLayout->GetLayoutHeight();
+    m_pLayoutData->m_fWidgetHeight =
+        CalculateWidgetAutoHeight(m_pLayoutData->m_fWidgetHeight);
+  }
+  fTextHeight = m_pLayoutData->m_fWidgetHeight;
+  fTextHeight = GetHeightWithoutMargin(fTextHeight);
+  pTextLayout->DoLayout(fTextHeight);
+  *pCalcHeight = m_pLayoutData->m_fWidgetHeight;
+}
+
+bool CXFA_Node::LoadCaption(CXFA_FFDoc* doc) {
+  InitLayoutData();
+  return m_pLayoutData->AsFieldLayoutData()->LoadCaption(doc, this);
+}
+
+CXFA_TextLayout* CXFA_Node::GetCaptionTextLayout() {
+  return m_pLayoutData
+             ? m_pLayoutData->AsFieldLayoutData()->m_pCapTextLayout.get()
+             : nullptr;
+}
+
+CXFA_TextLayout* CXFA_Node::GetTextLayout() {
+  return m_pLayoutData ? m_pLayoutData->AsTextLayoutData()->GetTextLayout()
+                       : nullptr;
+}
+
+RetainPtr<CFX_DIBitmap> CXFA_Node::GetImageImage() {
+  return m_pLayoutData ? m_pLayoutData->AsImageLayoutData()->m_pDIBitmap
+                       : nullptr;
+}
+
+RetainPtr<CFX_DIBitmap> CXFA_Node::GetImageEditImage() {
+  return m_pLayoutData ? m_pLayoutData->AsFieldLayoutData()
+                             ->AsImageEditData()
+                             ->m_pDIBitmap
+                       : nullptr;
+}
+
+void CXFA_Node::SetImageImage(const RetainPtr<CFX_DIBitmap>& newImage) {
+  CXFA_ImageLayoutData* pData = m_pLayoutData->AsImageLayoutData();
+  if (pData->m_pDIBitmap != newImage)
+    pData->m_pDIBitmap = newImage;
+}
+
+void CXFA_Node::SetImageEditImage(const RetainPtr<CFX_DIBitmap>& newImage) {
+  CXFA_ImageEditData* pData =
+      m_pLayoutData->AsFieldLayoutData()->AsImageEditData();
+  if (pData->m_pDIBitmap != newImage)
+    pData->m_pDIBitmap = newImage;
+}
+
+RetainPtr<CFGAS_GEFont> CXFA_Node::GetFDEFont(CXFA_FFDoc* doc) {
+  WideString wsFontName = L"Courier";
+  uint32_t dwFontStyle = 0;
+  CXFA_Font* font = GetFontIfExists();
+  if (font) {
+    if (font->IsBold())
+      dwFontStyle |= FXFONT_FORCE_BOLD;
+    if (font->IsItalic())
+      dwFontStyle |= FXFONT_ITALIC;
+
+    wsFontName = font->GetTypeface();
+  }
+  return doc->GetApp()->GetXFAFontMgr()->GetFont(doc, wsFontName.AsStringView(),
+                                                 dwFontStyle);
+}
+
+bool CXFA_Node::HasButtonRollover() {
+  CXFA_Items* pItems = GetChild<CXFA_Items>(0, XFA_Element::Items, false);
+  if (!pItems)
+    return false;
+
+  for (CXFA_Node* pText = pItems->GetFirstChild(); pText;
+       pText = pText->GetNextSibling()) {
+    if (pText->JSObject()
+            ->GetCData(XFA_Attribute::Name)
+            .EqualsASCII("rollover")) {
+      return !pText->JSObject()->GetContent(false).IsEmpty();
+    }
+  }
+  return false;
+}
+
+bool CXFA_Node::HasButtonDown() {
+  CXFA_Items* pItems = GetChild<CXFA_Items>(0, XFA_Element::Items, false);
+  if (!pItems)
+    return false;
+
+  for (CXFA_Node* pText = pItems->GetFirstChild(); pText;
+       pText = pText->GetNextSibling()) {
+    if (pText->JSObject()->GetCData(XFA_Attribute::Name).EqualsASCII("down")) {
+      return !pText->JSObject()->GetContent(false).IsEmpty();
+    }
+  }
+  return false;
+}
+
+bool CXFA_Node::IsRadioButton() {
+  CXFA_Node* pParent = GetParent();
+  return pParent && pParent->GetElementType() == XFA_Element::ExclGroup;
+}
+
+float CXFA_Node::GetCheckButtonSize() {
+  CXFA_Node* pUIChild = GetUIChildNode();
+  if (pUIChild) {
+    return pUIChild->JSObject()->GetMeasureInUnit(XFA_Attribute::Size,
+                                                  XFA_Unit::Pt);
+  }
+  return CXFA_Measurement(10, XFA_Unit::Pt).ToUnit(XFA_Unit::Pt);
+}
+
+XFA_CHECKSTATE CXFA_Node::GetCheckState() {
+  WideString wsValue = GetRawValue();
+  if (wsValue.IsEmpty())
+    return XFA_CHECKSTATE_Off;
+
+  auto* pItems = GetChild<CXFA_Items>(0, XFA_Element::Items, false);
+  if (!pItems)
+    return XFA_CHECKSTATE_Off;
+
+  CXFA_Node* pText = pItems->GetFirstChild();
+  int32_t i = 0;
+  while (pText) {
+    Optional<WideString> wsContent = pText->JSObject()->TryContent(false, true);
+    if (wsContent && *wsContent == wsValue)
+      return static_cast<XFA_CHECKSTATE>(i);
+
+    i++;
+    pText = pText->GetNextSibling();
+  }
+  return XFA_CHECKSTATE_Off;
+}
+
+void CXFA_Node::SetCheckState(XFA_CHECKSTATE eCheckState, bool bNotify) {
+  CXFA_Node* node = GetExclGroupIfExists();
+  if (!node) {
+    CXFA_Items* pItems = GetChild<CXFA_Items>(0, XFA_Element::Items, false);
+    if (!pItems)
+      return;
+
+    int32_t i = -1;
+    CXFA_Node* pText = pItems->GetFirstChild();
+    WideString wsContent;
+    while (pText) {
+      i++;
+      if (i == eCheckState) {
+        wsContent = pText->JSObject()->GetContent(false);
+        break;
+      }
+      pText = pText->GetNextSibling();
+    }
+    SyncValue(wsContent, bNotify);
+
+    return;
+  }
+
+  WideString wsValue;
+  if (eCheckState != XFA_CHECKSTATE_Off) {
+    if (CXFA_Items* pItems =
+            GetChild<CXFA_Items>(0, XFA_Element::Items, false)) {
+      CXFA_Node* pText = pItems->GetFirstChild();
+      if (pText)
+        wsValue = pText->JSObject()->GetContent(false);
+    }
+  }
+  CXFA_Node* pChild = node->GetFirstChild();
+  for (; pChild; pChild = pChild->GetNextSibling()) {
+    if (pChild->GetElementType() != XFA_Element::Field)
+      continue;
+
+    CXFA_Items* pItem =
+        pChild->GetChild<CXFA_Items>(0, XFA_Element::Items, false);
+    if (!pItem)
+      continue;
+
+    CXFA_Node* pItemchild = pItem->GetFirstChild();
+    if (!pItemchild)
+      continue;
+
+    WideString text = pItemchild->JSObject()->GetContent(false);
+    WideString wsChildValue = text;
+    if (wsValue != text) {
+      pItemchild = pItemchild->GetNextSibling();
+      if (pItemchild)
+        wsChildValue = pItemchild->JSObject()->GetContent(false);
+      else
+        wsChildValue.clear();
+    }
+    pChild->SyncValue(wsChildValue, bNotify);
+  }
+  node->SyncValue(wsValue, bNotify);
+}
+
+CXFA_Node* CXFA_Node::GetSelectedMember() {
+  CXFA_Node* pSelectedMember = nullptr;
+  WideString wsState = GetRawValue();
+  if (wsState.IsEmpty())
+    return pSelectedMember;
+
+  for (CXFA_Node* pNode = ToNode(GetFirstChild()); pNode;
+       pNode = pNode->GetNextSibling()) {
+    if (pNode->GetCheckState() == XFA_CHECKSTATE_On) {
+      pSelectedMember = pNode;
+      break;
+    }
+  }
+  return pSelectedMember;
+}
+
+CXFA_Node* CXFA_Node::SetSelectedMember(WideStringView wsName, bool bNotify) {
+  uint32_t nameHash = FX_HashCode_GetW(wsName, false);
+  for (CXFA_Node* pNode = ToNode(GetFirstChild()); pNode;
+       pNode = pNode->GetNextSibling()) {
+    if (pNode->GetNameHash() == nameHash) {
+      pNode->SetCheckState(XFA_CHECKSTATE_On, bNotify);
+      return pNode;
+    }
+  }
+  return nullptr;
+}
+
+void CXFA_Node::SetSelectedMemberByValue(WideStringView wsValue,
+                                         bool bNotify,
+                                         bool bScriptModify,
+                                         bool bSyncData) {
+  WideString wsExclGroup;
+  for (CXFA_Node* pNode = GetFirstChild(); pNode;
+       pNode = pNode->GetNextSibling()) {
+    if (pNode->GetElementType() != XFA_Element::Field)
+      continue;
+
+    CXFA_Items* pItem =
+        pNode->GetChild<CXFA_Items>(0, XFA_Element::Items, false);
+    if (!pItem)
+      continue;
+
+    CXFA_Node* pItemchild = pItem->GetFirstChild();
+    if (!pItemchild)
+      continue;
+
+    WideString wsChildValue = pItemchild->JSObject()->GetContent(false);
+    if (wsValue != wsChildValue) {
+      pItemchild = pItemchild->GetNextSibling();
+      if (pItemchild)
+        wsChildValue = pItemchild->JSObject()->GetContent(false);
+      else
+        wsChildValue.clear();
+    } else {
+      wsExclGroup = wsValue;
+    }
+    pNode->JSObject()->SetContent(wsChildValue, wsChildValue, bNotify,
+                                  bScriptModify, false);
+  }
+  JSObject()->SetContent(wsExclGroup, wsExclGroup, bNotify, bScriptModify,
+                         bSyncData);
+}
+
+CXFA_Node* CXFA_Node::GetExclGroupFirstMember() {
+  CXFA_Node* pNode = GetFirstChild();
+  while (pNode) {
+    if (pNode->GetElementType() == XFA_Element::Field)
+      return pNode;
+
+    pNode = pNode->GetNextSibling();
+  }
+  return nullptr;
+}
+
+CXFA_Node* CXFA_Node::GetExclGroupNextMember(CXFA_Node* pNode) {
+  if (!pNode)
+    return nullptr;
+
+  CXFA_Node* pNodeField = pNode->GetNextSibling();
+  while (pNodeField) {
+    if (pNodeField->GetElementType() == XFA_Element::Field)
+      return pNodeField;
+
+    pNodeField = pNodeField->GetNextSibling();
+  }
+  return nullptr;
+}
+
+bool CXFA_Node::IsChoiceListCommitOnSelect() {
+  CXFA_Node* pUIChild = GetUIChildNode();
+  if (pUIChild) {
+    return pUIChild->JSObject()->GetEnum(XFA_Attribute::CommitOn) ==
+           XFA_AttributeValue::Select;
+  }
+  return true;
+}
+
+bool CXFA_Node::IsChoiceListAllowTextEntry() {
+  CXFA_Node* pUIChild = GetUIChildNode();
+  return pUIChild && pUIChild->JSObject()->GetBoolean(XFA_Attribute::TextEntry);
+}
+
+bool CXFA_Node::IsChoiceListMultiSelect() {
+  CXFA_Node* pUIChild = GetUIChildNode();
+  if (pUIChild) {
+    return pUIChild->JSObject()->GetEnum(XFA_Attribute::Open) ==
+           XFA_AttributeValue::MultiSelect;
+  }
+  return false;
+}
+
+bool CXFA_Node::IsListBox() {
+  CXFA_Node* pUIChild = GetUIChildNode();
+  if (!pUIChild)
+    return false;
+
+  XFA_AttributeValue attr = pUIChild->JSObject()->GetEnum(XFA_Attribute::Open);
+  return attr == XFA_AttributeValue::Always ||
+         attr == XFA_AttributeValue::MultiSelect;
+}
+
+int32_t CXFA_Node::CountChoiceListItems(bool bSaveValue) {
+  std::vector<CXFA_Node*> pItems;
+  int32_t iCount = 0;
+  for (CXFA_Node* pNode = GetFirstChild(); pNode;
+       pNode = pNode->GetNextSibling()) {
+    if (pNode->GetElementType() != XFA_Element::Items)
+      continue;
+    iCount++;
+    pItems.push_back(pNode);
+    if (iCount == 2)
+      break;
+  }
+  if (iCount == 0)
+    return 0;
+
+  CXFA_Node* pItem = pItems[0];
+  if (iCount > 1) {
+    bool bItemOneHasSave =
+        pItems[0]->JSObject()->GetBoolean(XFA_Attribute::Save);
+    bool bItemTwoHasSave =
+        pItems[1]->JSObject()->GetBoolean(XFA_Attribute::Save);
+    if (bItemOneHasSave != bItemTwoHasSave && bSaveValue == bItemTwoHasSave)
+      pItem = pItems[1];
+  }
+  return pItem->CountChildren(XFA_Element::Unknown, false);
+}
+
+Optional<WideString> CXFA_Node::GetChoiceListItem(int32_t nIndex,
+                                                  bool bSaveValue) {
+  std::vector<CXFA_Node*> pItemsArray;
+  int32_t iCount = 0;
+  for (CXFA_Node* pNode = GetFirstChild(); pNode;
+       pNode = pNode->GetNextSibling()) {
+    if (pNode->GetElementType() != XFA_Element::Items)
+      continue;
+
+    ++iCount;
+    pItemsArray.push_back(pNode);
+    if (iCount == 2)
+      break;
+  }
+  if (iCount == 0)
+    return {};
+
+  CXFA_Node* pItems = pItemsArray[0];
+  if (iCount > 1) {
+    bool bItemOneHasSave =
+        pItemsArray[0]->JSObject()->GetBoolean(XFA_Attribute::Save);
+    bool bItemTwoHasSave =
+        pItemsArray[1]->JSObject()->GetBoolean(XFA_Attribute::Save);
+    if (bItemOneHasSave != bItemTwoHasSave && bSaveValue == bItemTwoHasSave)
+      pItems = pItemsArray[1];
+  }
+  if (!pItems)
+    return {};
+
+  CXFA_Node* pItem =
+      pItems->GetChild<CXFA_Node>(nIndex, XFA_Element::Unknown, false);
+  if (pItem)
+    return {pItem->JSObject()->GetContent(false)};
   return {};
 }
 
-Optional<int32_t> CXFA_Node::GetBarcodeAttribute_DataLength() {
-  Optional<WideString> wsDataLength =
-      GetWidgetAcc()->GetUIChild()->JSObject()->TryCData(
-          XFA_Attribute::DataLength, true);
-  if (!wsDataLength)
-    return {};
+std::vector<WideString> CXFA_Node::GetChoiceListItems(bool bSaveValue) {
+  std::vector<CXFA_Node*> items;
+  for (CXFA_Node* pNode = GetFirstChild(); pNode && items.size() < 2;
+       pNode = pNode->GetNextSibling()) {
+    if (pNode->GetElementType() == XFA_Element::Items)
+      items.push_back(pNode);
+  }
+  if (items.empty())
+    return std::vector<WideString>();
 
-  return {FXSYS_wtoi(wsDataLength->c_str())};
+  CXFA_Node* pItem = items.front();
+  if (items.size() > 1) {
+    bool bItemOneHasSave =
+        items[0]->JSObject()->GetBoolean(XFA_Attribute::Save);
+    bool bItemTwoHasSave =
+        items[1]->JSObject()->GetBoolean(XFA_Attribute::Save);
+    if (bItemOneHasSave != bItemTwoHasSave && bSaveValue == bItemTwoHasSave)
+      pItem = items[1];
+  }
+
+  std::vector<WideString> wsTextArray;
+  for (CXFA_Node* pNode = pItem->GetFirstChild(); pNode;
+       pNode = pNode->GetNextSibling()) {
+    wsTextArray.emplace_back(pNode->JSObject()->GetContent(false));
+  }
+  return wsTextArray;
 }
 
-Optional<char> CXFA_Node::GetBarcodeAttribute_StartChar() {
-  Optional<WideString> wsStartEndChar =
-      GetWidgetAcc()->GetUIChild()->JSObject()->TryCData(
-          XFA_Attribute::StartChar, true);
-  if (!wsStartEndChar || wsStartEndChar->IsEmpty())
-    return {};
+int32_t CXFA_Node::CountSelectedItems() {
+  std::vector<WideString> wsValueArray = GetSelectedItemsValue();
+  if (IsListBox() || !IsChoiceListAllowTextEntry())
+    return pdfium::CollectionSize<int32_t>(wsValueArray);
 
-  return {static_cast<char>((*wsStartEndChar)[0])};
+  int32_t iSelected = 0;
+  std::vector<WideString> wsSaveTextArray = GetChoiceListItems(true);
+  for (const auto& value : wsValueArray) {
+    if (pdfium::ContainsValue(wsSaveTextArray, value))
+      iSelected++;
+  }
+  return iSelected;
 }
 
-Optional<char> CXFA_Node::GetBarcodeAttribute_EndChar() {
-  Optional<WideString> wsStartEndChar =
-      GetWidgetAcc()->GetUIChild()->JSObject()->TryCData(XFA_Attribute::EndChar,
-                                                         true);
-  if (!wsStartEndChar || wsStartEndChar->IsEmpty())
-    return {};
+int32_t CXFA_Node::GetSelectedItem(int32_t nIndex) {
+  std::vector<WideString> wsValueArray = GetSelectedItemsValue();
+  if (!pdfium::IndexInBounds(wsValueArray, nIndex))
+    return -1;
 
-  return {static_cast<char>((*wsStartEndChar)[0])};
+  std::vector<WideString> wsSaveTextArray = GetChoiceListItems(true);
+  auto it = std::find(wsSaveTextArray.begin(), wsSaveTextArray.end(),
+                      wsValueArray[nIndex]);
+  return it != wsSaveTextArray.end() ? it - wsSaveTextArray.begin() : -1;
 }
 
-Optional<int32_t> CXFA_Node::GetBarcodeAttribute_ECLevel() {
-  Optional<WideString> wsECLevel =
-      GetWidgetAcc()->GetUIChild()->JSObject()->TryCData(
-          XFA_Attribute::ErrorCorrectionLevel, true);
-  if (!wsECLevel)
-    return {};
-  return {FXSYS_wtoi(wsECLevel->c_str())};
+std::vector<int32_t> CXFA_Node::GetSelectedItems() {
+  std::vector<int32_t> iSelArray;
+  std::vector<WideString> wsValueArray = GetSelectedItemsValue();
+  std::vector<WideString> wsSaveTextArray = GetChoiceListItems(true);
+  for (const auto& value : wsValueArray) {
+    auto it = std::find(wsSaveTextArray.begin(), wsSaveTextArray.end(), value);
+    if (it != wsSaveTextArray.end())
+      iSelArray.push_back(it - wsSaveTextArray.begin());
+  }
+  return iSelArray;
 }
 
-Optional<int32_t> CXFA_Node::GetBarcodeAttribute_ModuleWidth() {
-  Optional<CXFA_Measurement> moduleWidthHeight =
-      GetWidgetAcc()->GetUIChild()->JSObject()->TryMeasure(
-          XFA_Attribute::ModuleWidth, true);
-  if (!moduleWidthHeight)
-    return {};
+std::vector<WideString> CXFA_Node::GetSelectedItemsValue() {
+  WideString wsValue = GetRawValue();
+  if (IsChoiceListMultiSelect())
+    return fxcrt::Split(wsValue, L'\n');
 
-  return {static_cast<int32_t>(moduleWidthHeight->ToUnit(XFA_Unit::Pt))};
+  std::vector<WideString> wsSelTextArray;
+  wsSelTextArray.push_back(wsValue);
+  return wsSelTextArray;
 }
 
-Optional<int32_t> CXFA_Node::GetBarcodeAttribute_ModuleHeight() {
-  Optional<CXFA_Measurement> moduleWidthHeight =
-      GetWidgetAcc()->GetUIChild()->JSObject()->TryMeasure(
-          XFA_Attribute::ModuleHeight, true);
-  if (!moduleWidthHeight)
-    return {};
-
-  return {static_cast<int32_t>(moduleWidthHeight->ToUnit(XFA_Unit::Pt))};
+bool CXFA_Node::GetItemState(int32_t nIndex) {
+  std::vector<WideString> wsSaveTextArray = GetChoiceListItems(true);
+  return pdfium::IndexInBounds(wsSaveTextArray, nIndex) &&
+         pdfium::ContainsValue(GetSelectedItemsValue(),
+                               wsSaveTextArray[nIndex]);
 }
 
-Optional<bool> CXFA_Node::GetBarcodeAttribute_PrintChecksum() {
-  return GetWidgetAcc()->GetUIChild()->JSObject()->TryBoolean(
-      XFA_Attribute::PrintCheckDigit, true);
+void CXFA_Node::SetItemState(int32_t nIndex,
+                             bool bSelected,
+                             bool bNotify,
+                             bool bScriptModify,
+                             bool bSyncData) {
+  std::vector<WideString> wsSaveTextArray = GetChoiceListItems(true);
+  if (!pdfium::IndexInBounds(wsSaveTextArray, nIndex))
+    return;
+
+  int32_t iSel = -1;
+  std::vector<WideString> wsValueArray = GetSelectedItemsValue();
+  auto value_iter = std::find(wsValueArray.begin(), wsValueArray.end(),
+                              wsSaveTextArray[nIndex]);
+  if (value_iter != wsValueArray.end())
+    iSel = value_iter - wsValueArray.begin();
+
+  if (IsChoiceListMultiSelect()) {
+    if (bSelected) {
+      if (iSel < 0) {
+        WideString wsValue = GetRawValue();
+        if (!wsValue.IsEmpty()) {
+          wsValue += L"\n";
+        }
+        wsValue += wsSaveTextArray[nIndex];
+        JSObject()->SetContent(wsValue, wsValue, bNotify, bScriptModify,
+                               bSyncData);
+      }
+    } else if (iSel >= 0) {
+      std::vector<int32_t> iSelArray = GetSelectedItems();
+      auto selected_iter =
+          std::find(iSelArray.begin(), iSelArray.end(), nIndex);
+      if (selected_iter != iSelArray.end())
+        iSelArray.erase(selected_iter);
+      SetSelectedItems(iSelArray, bNotify, bScriptModify, bSyncData);
+    }
+  } else {
+    if (bSelected) {
+      if (iSel < 0) {
+        WideString wsSaveText = wsSaveTextArray[nIndex];
+        JSObject()->SetContent(wsSaveText, GetFormatDataValue(wsSaveText),
+                               bNotify, bScriptModify, bSyncData);
+      }
+    } else if (iSel >= 0) {
+      JSObject()->SetContent(WideString(), WideString(), bNotify, bScriptModify,
+                             bSyncData);
+    }
+  }
 }
 
-Optional<BC_TEXT_LOC> CXFA_Node::GetBarcodeAttribute_TextLocation() {
-  Optional<XFA_AttributeEnum> textLocation =
-      GetWidgetAcc()->GetUIChild()->JSObject()->TryEnum(
-          XFA_Attribute::TextLocation, true);
-  if (!textLocation)
-    return {};
+void CXFA_Node::SetSelectedItems(const std::vector<int32_t>& iSelArray,
+                                 bool bNotify,
+                                 bool bScriptModify,
+                                 bool bSyncData) {
+  WideString wsValue;
+  int32_t iSize = pdfium::CollectionSize<int32_t>(iSelArray);
+  if (iSize >= 1) {
+    std::vector<WideString> wsSaveTextArray = GetChoiceListItems(true);
+    WideString wsItemValue;
+    for (int32_t i = 0; i < iSize; i++) {
+      wsItemValue = (iSize == 1) ? wsSaveTextArray[iSelArray[i]]
+                                 : wsSaveTextArray[iSelArray[i]] + L"\n";
+      wsValue += wsItemValue;
+    }
+  }
+  WideString wsFormat(wsValue);
+  if (!IsChoiceListMultiSelect())
+    wsFormat = GetFormatDataValue(wsValue);
 
-  switch (*textLocation) {
-    case XFA_AttributeEnum::None:
-      return {BC_TEXT_LOC_NONE};
-    case XFA_AttributeEnum::Above:
-      return {BC_TEXT_LOC_ABOVE};
-    case XFA_AttributeEnum::Below:
-      return {BC_TEXT_LOC_BELOW};
-    case XFA_AttributeEnum::AboveEmbedded:
-      return {BC_TEXT_LOC_ABOVEEMBED};
-    case XFA_AttributeEnum::BelowEmbedded:
-      return {BC_TEXT_LOC_BELOWEMBED};
+  JSObject()->SetContent(wsValue, wsFormat, bNotify, bScriptModify, bSyncData);
+}
+
+void CXFA_Node::ClearAllSelections() {
+  CXFA_Node* pBind = GetBindData();
+  if (!pBind || !IsChoiceListMultiSelect()) {
+    SyncValue(WideString(), false);
+    return;
+  }
+
+  while (CXFA_Node* pChildNode = pBind->GetFirstChild())
+    pBind->RemoveChildAndNotify(pChildNode, true);
+}
+
+void CXFA_Node::InsertItem(const WideString& wsLabel,
+                           const WideString& wsValue,
+                           bool bNotify) {
+  int32_t nIndex = -1;
+  WideString wsNewValue(wsValue);
+  if (wsNewValue.IsEmpty())
+    wsNewValue = wsLabel;
+
+  std::vector<CXFA_Node*> listitems;
+  for (CXFA_Node* pItem = GetFirstChild(); pItem;
+       pItem = pItem->GetNextSibling()) {
+    if (pItem->GetElementType() == XFA_Element::Items)
+      listitems.push_back(pItem);
+  }
+  if (listitems.empty()) {
+    CXFA_Node* pItems = CreateSamePacketNode(XFA_Element::Items);
+    InsertChildAndNotify(-1, pItems);
+    InsertListTextItem(pItems, wsLabel, nIndex);
+    CXFA_Node* pSaveItems = CreateSamePacketNode(XFA_Element::Items);
+    InsertChildAndNotify(-1, pSaveItems);
+    pSaveItems->JSObject()->SetBoolean(XFA_Attribute::Save, true, false);
+    InsertListTextItem(pSaveItems, wsNewValue, nIndex);
+  } else if (listitems.size() > 1) {
+    for (int32_t i = 0; i < 2; i++) {
+      CXFA_Node* pNode = listitems[i];
+      bool bHasSave = pNode->JSObject()->GetBoolean(XFA_Attribute::Save);
+      if (bHasSave)
+        InsertListTextItem(pNode, wsNewValue, nIndex);
+      else
+        InsertListTextItem(pNode, wsLabel, nIndex);
+    }
+  } else {
+    CXFA_Node* pNode = listitems[0];
+    pNode->JSObject()->SetBoolean(XFA_Attribute::Save, false, false);
+    pNode->JSObject()->SetEnum(XFA_Attribute::Presence,
+                               XFA_AttributeValue::Visible, false);
+    CXFA_Node* pSaveItems = CreateSamePacketNode(XFA_Element::Items);
+    InsertChildAndNotify(-1, pSaveItems);
+    pSaveItems->JSObject()->SetBoolean(XFA_Attribute::Save, true, false);
+    pSaveItems->JSObject()->SetEnum(XFA_Attribute::Presence,
+                                    XFA_AttributeValue::Hidden, false);
+    CXFA_Node* pListNode = pNode->GetFirstChild();
+    int32_t i = 0;
+    while (pListNode) {
+      InsertListTextItem(pSaveItems, pListNode->JSObject()->GetContent(false),
+                         i);
+      ++i;
+
+      pListNode = pListNode->GetNextSibling();
+    }
+    InsertListTextItem(pNode, wsLabel, nIndex);
+    InsertListTextItem(pSaveItems, wsNewValue, nIndex);
+  }
+  if (bNotify)
+    GetDocument()->GetNotify()->OnWidgetListItemAdded(this, wsLabel, nIndex);
+}
+
+WideString CXFA_Node::GetItemLabel(WideStringView wsValue) const {
+  std::vector<CXFA_Node*> listitems;
+  CXFA_Node* pItems = GetFirstChild();
+  for (; pItems; pItems = pItems->GetNextSibling()) {
+    if (pItems->GetElementType() != XFA_Element::Items)
+      continue;
+    listitems.push_back(pItems);
+  }
+
+  if (listitems.size() <= 1)
+    return WideString(wsValue);
+
+  CXFA_Node* pLabelItems = listitems[0];
+  bool bSave = pLabelItems->JSObject()->GetBoolean(XFA_Attribute::Save);
+  CXFA_Node* pSaveItems = nullptr;
+  if (bSave) {
+    pSaveItems = pLabelItems;
+    pLabelItems = listitems[1];
+  } else {
+    pSaveItems = listitems[1];
+  }
+
+  int32_t iCount = 0;
+  int32_t iSearch = -1;
+  for (CXFA_Node* pChildItem = pSaveItems->GetFirstChild(); pChildItem;
+       pChildItem = pChildItem->GetNextSibling()) {
+    if (pChildItem->JSObject()->GetContent(false) == wsValue) {
+      iSearch = iCount;
+      break;
+    }
+    iCount++;
+  }
+  if (iSearch < 0)
+    return WideString();
+
+  CXFA_Node* pText =
+      pLabelItems->GetChild<CXFA_Node>(iSearch, XFA_Element::Unknown, false);
+  return pText ? pText->JSObject()->GetContent(false) : WideString();
+}
+
+WideString CXFA_Node::GetItemValue(WideStringView wsLabel) {
+  int32_t iCount = 0;
+  std::vector<CXFA_Node*> listitems;
+  for (CXFA_Node* pItems = GetFirstChild(); pItems;
+       pItems = pItems->GetNextSibling()) {
+    if (pItems->GetElementType() != XFA_Element::Items)
+      continue;
+    iCount++;
+    listitems.push_back(pItems);
+  }
+  if (iCount <= 1)
+    return WideString(wsLabel);
+
+  CXFA_Node* pLabelItems = listitems[0];
+  bool bSave = pLabelItems->JSObject()->GetBoolean(XFA_Attribute::Save);
+  CXFA_Node* pSaveItems = nullptr;
+  if (bSave) {
+    pSaveItems = pLabelItems;
+    pLabelItems = listitems[1];
+  } else {
+    pSaveItems = listitems[1];
+  }
+  iCount = 0;
+
+  int32_t iSearch = -1;
+  WideString wsContent;
+  CXFA_Node* pChildItem = pLabelItems->GetFirstChild();
+  for (; pChildItem; pChildItem = pChildItem->GetNextSibling()) {
+    if (pChildItem->JSObject()->GetContent(false) == wsLabel) {
+      iSearch = iCount;
+      break;
+    }
+    iCount++;
+  }
+  if (iSearch < 0)
+    return WideString();
+
+  CXFA_Node* pText =
+      pSaveItems->GetChild<CXFA_Node>(iSearch, XFA_Element::Unknown, false);
+  return pText ? pText->JSObject()->GetContent(false) : WideString();
+}
+
+bool CXFA_Node::DeleteItem(int32_t nIndex, bool bNotify, bool bScriptModify) {
+  bool bSetValue = false;
+  CXFA_Node* pItems = GetFirstChild();
+  for (; pItems; pItems = pItems->GetNextSibling()) {
+    if (pItems->GetElementType() != XFA_Element::Items)
+      continue;
+
+    if (nIndex < 0) {
+      while (CXFA_Node* pNode = pItems->GetFirstChild()) {
+        pItems->RemoveChildAndNotify(pNode, true);
+      }
+    } else {
+      if (!bSetValue && pItems->JSObject()->GetBoolean(XFA_Attribute::Save)) {
+        SetItemState(nIndex, false, true, bScriptModify, true);
+        bSetValue = true;
+      }
+      int32_t i = 0;
+      CXFA_Node* pNode = pItems->GetFirstChild();
+      while (pNode) {
+        if (i == nIndex) {
+          pItems->RemoveChildAndNotify(pNode, true);
+          break;
+        }
+        i++;
+        pNode = pNode->GetNextSibling();
+      }
+    }
+  }
+  if (bNotify)
+    GetDocument()->GetNotify()->OnWidgetListItemRemoved(this, nIndex);
+  return true;
+}
+
+bool CXFA_Node::IsHorizontalScrollPolicyOff() {
+  CXFA_Node* pUIChild = GetUIChildNode();
+  if (pUIChild) {
+    return pUIChild->JSObject()->GetEnum(XFA_Attribute::HScrollPolicy) ==
+           XFA_AttributeValue::Off;
+  }
+  return false;
+}
+
+bool CXFA_Node::IsVerticalScrollPolicyOff() {
+  CXFA_Node* pUIChild = GetUIChildNode();
+  if (pUIChild) {
+    return pUIChild->JSObject()->GetEnum(XFA_Attribute::VScrollPolicy) ==
+           XFA_AttributeValue::Off;
+  }
+  return false;
+}
+
+Optional<int32_t> CXFA_Node::GetNumberOfCells() {
+  CXFA_Node* pUIChild = GetUIChildNode();
+  if (!pUIChild)
+    return {};
+  if (CXFA_Comb* pNode =
+          pUIChild->GetChild<CXFA_Comb>(0, XFA_Element::Comb, false))
+    return {pNode->JSObject()->GetInteger(XFA_Attribute::NumberOfCells)};
+  return {};
+}
+
+bool CXFA_Node::IsMultiLine() {
+  CXFA_Node* pUIChild = GetUIChildNode();
+  return pUIChild && pUIChild->JSObject()->GetBoolean(XFA_Attribute::MultiLine);
+}
+
+std::pair<XFA_Element, int32_t> CXFA_Node::GetMaxChars() {
+  if (CXFA_Value* pNode = GetChild<CXFA_Value>(0, XFA_Element::Value, false)) {
+    if (CXFA_Node* pChild = pNode->GetFirstChild()) {
+      switch (pChild->GetElementType()) {
+        case XFA_Element::Text:
+          return {XFA_Element::Text,
+                  pChild->JSObject()->GetInteger(XFA_Attribute::MaxChars)};
+        case XFA_Element::ExData: {
+          int32_t iMax =
+              pChild->JSObject()->GetInteger(XFA_Attribute::MaxLength);
+          return {XFA_Element::ExData, iMax < 0 ? 0 : iMax};
+        }
+        default:
+          break;
+      }
+    }
+  }
+  return {XFA_Element::Unknown, 0};
+}
+
+int32_t CXFA_Node::GetFracDigits() {
+  CXFA_Value* pNode = GetChild<CXFA_Value>(0, XFA_Element::Value, false);
+  if (!pNode)
+    return -1;
+
+  CXFA_Decimal* pChild =
+      pNode->GetChild<CXFA_Decimal>(0, XFA_Element::Decimal, false);
+  if (!pChild)
+    return -1;
+
+  return pChild->JSObject()
+      ->TryInteger(XFA_Attribute::FracDigits, true)
+      .value_or(-1);
+}
+
+int32_t CXFA_Node::GetLeadDigits() {
+  CXFA_Value* pNode = GetChild<CXFA_Value>(0, XFA_Element::Value, false);
+  if (!pNode)
+    return -1;
+
+  CXFA_Decimal* pChild =
+      pNode->GetChild<CXFA_Decimal>(0, XFA_Element::Decimal, false);
+  if (!pChild)
+    return -1;
+
+  return pChild->JSObject()
+      ->TryInteger(XFA_Attribute::LeadDigits, true)
+      .value_or(-1);
+}
+
+bool CXFA_Node::SetValue(XFA_VALUEPICTURE eValueType,
+                         const WideString& wsValue) {
+  if (wsValue.IsEmpty()) {
+    SyncValue(wsValue, true);
+    return true;
+  }
+
+  SetPreNull(IsNull());
+  SetIsNull(false);
+
+  WideString wsNewText(wsValue);
+  WideString wsPicture = GetPictureContent(eValueType);
+  bool bValidate = true;
+  bool bSyncData = false;
+  CXFA_Node* pNode = GetUIChildNode();
+  if (!pNode)
+    return true;
+
+  XFA_Element eType = pNode->GetElementType();
+  if (!wsPicture.IsEmpty()) {
+    CXFA_LocaleMgr* pLocaleMgr = GetDocument()->GetLocaleMgr();
+    LocaleIface* pLocale = GetLocale();
+    CXFA_LocaleValue widgetValue = XFA_GetLocaleValue(this);
+    bValidate =
+        widgetValue.ValidateValue(wsValue, wsPicture, pLocale, &wsPicture);
+    if (bValidate) {
+      widgetValue = CXFA_LocaleValue(widgetValue.GetType(), wsNewText,
+                                     wsPicture, pLocale, pLocaleMgr);
+      wsNewText = widgetValue.GetValue();
+      if (eType == XFA_Element::NumericEdit)
+        wsNewText = NumericLimit(wsNewText);
+
+      bSyncData = true;
+    }
+  } else if (eType == XFA_Element::NumericEdit) {
+    if (!wsNewText.EqualsASCII("0"))
+      wsNewText = NumericLimit(wsNewText);
+
+    bSyncData = true;
+  }
+  if (eType != XFA_Element::NumericEdit || bSyncData)
+    SyncValue(wsNewText, true);
+
+  return bValidate;
+}
+
+WideString CXFA_Node::GetPictureContent(XFA_VALUEPICTURE ePicture) {
+  if (ePicture == XFA_VALUEPICTURE_Raw)
+    return WideString();
+
+  CXFA_LocaleValue widgetValue = XFA_GetLocaleValue(this);
+  switch (ePicture) {
+    case XFA_VALUEPICTURE_Display: {
+      if (CXFA_Format* pFormat =
+              GetChild<CXFA_Format>(0, XFA_Element::Format, false)) {
+        if (CXFA_Picture* pPicture = pFormat->GetChild<CXFA_Picture>(
+                0, XFA_Element::Picture, false)) {
+          Optional<WideString> picture =
+              pPicture->JSObject()->TryContent(false, true);
+          if (picture)
+            return *picture;
+        }
+      }
+
+      LocaleIface* pLocale = GetLocale();
+      if (!pLocale)
+        return WideString();
+
+      uint32_t dwType = widgetValue.GetType();
+      switch (dwType) {
+        case XFA_VT_DATE:
+          return pLocale->GetDatePattern(FX_LOCALEDATETIMESUBCATEGORY_Medium);
+        case XFA_VT_TIME:
+          return pLocale->GetTimePattern(FX_LOCALEDATETIMESUBCATEGORY_Medium);
+        case XFA_VT_DATETIME:
+          return pLocale->GetDatePattern(FX_LOCALEDATETIMESUBCATEGORY_Medium) +
+                 L"T" +
+                 pLocale->GetTimePattern(FX_LOCALEDATETIMESUBCATEGORY_Medium);
+        case XFA_VT_DECIMAL:
+        case XFA_VT_FLOAT:
+        default:
+          return WideString();
+      }
+    }
+    case XFA_VALUEPICTURE_Edit: {
+      CXFA_Ui* pUI = GetChild<CXFA_Ui>(0, XFA_Element::Ui, false);
+      if (pUI) {
+        if (CXFA_Picture* pPicture =
+                pUI->GetChild<CXFA_Picture>(0, XFA_Element::Picture, false)) {
+          Optional<WideString> picture =
+              pPicture->JSObject()->TryContent(false, true);
+          if (picture)
+            return *picture;
+        }
+      }
+
+      LocaleIface* pLocale = GetLocale();
+      if (!pLocale)
+        return WideString();
+
+      uint32_t dwType = widgetValue.GetType();
+      switch (dwType) {
+        case XFA_VT_DATE:
+          return pLocale->GetDatePattern(FX_LOCALEDATETIMESUBCATEGORY_Short);
+        case XFA_VT_TIME:
+          return pLocale->GetTimePattern(FX_LOCALEDATETIMESUBCATEGORY_Short);
+        case XFA_VT_DATETIME:
+          return pLocale->GetDatePattern(FX_LOCALEDATETIMESUBCATEGORY_Short) +
+                 L"T" +
+                 pLocale->GetTimePattern(FX_LOCALEDATETIMESUBCATEGORY_Short);
+        default:
+          return WideString();
+      }
+    }
+    case XFA_VALUEPICTURE_DataBind: {
+      CXFA_Bind* bind = GetBindIfExists();
+      if (bind)
+        return bind->GetPicture();
+      break;
+    }
     default:
       break;
   }
-  return {};
+  return WideString();
 }
 
-Optional<bool> CXFA_Node::GetBarcodeAttribute_Truncate() {
-  return GetWidgetAcc()->GetUIChild()->JSObject()->TryBoolean(
-      XFA_Attribute::Truncate, true);
+WideString CXFA_Node::GetValue(XFA_VALUEPICTURE eValueType) {
+  WideString wsValue = JSObject()->GetContent(false);
+
+  if (eValueType == XFA_VALUEPICTURE_Display)
+    wsValue = GetItemLabel(wsValue.AsStringView());
+
+  WideString wsPicture = GetPictureContent(eValueType);
+  CXFA_Node* pNode = GetUIChildNode();
+  if (!pNode)
+    return wsValue;
+
+  switch (pNode->GetElementType()) {
+    case XFA_Element::ChoiceList: {
+      if (eValueType == XFA_VALUEPICTURE_Display) {
+        int32_t iSelItemIndex = GetSelectedItem(0);
+        if (iSelItemIndex >= 0) {
+          wsValue =
+              GetChoiceListItem(iSelItemIndex, false).value_or(WideString());
+          wsPicture.clear();
+        }
+      }
+      break;
+    }
+    case XFA_Element::NumericEdit:
+      if (eValueType != XFA_VALUEPICTURE_Raw && wsPicture.IsEmpty()) {
+        LocaleIface* pLocale = GetLocale();
+        if (eValueType == XFA_VALUEPICTURE_Display && pLocale)
+          wsValue = FormatNumStr(NormalizeNumStr(wsValue), pLocale);
+      }
+      break;
+    default:
+      break;
+  }
+  if (wsPicture.IsEmpty())
+    return wsValue;
+
+  if (LocaleIface* pLocale = GetLocale()) {
+    CXFA_LocaleValue widgetValue = XFA_GetLocaleValue(this);
+    CXFA_LocaleMgr* pLocaleMgr = GetDocument()->GetLocaleMgr();
+    switch (widgetValue.GetType()) {
+      case XFA_VT_DATE: {
+        WideString wsDate, wsTime;
+        if (SplitDateTime(wsValue, wsDate, wsTime)) {
+          CXFA_LocaleValue date(XFA_VT_DATE, wsDate, pLocaleMgr);
+          if (date.FormatPatterns(wsValue, wsPicture, pLocale, eValueType))
+            return wsValue;
+        }
+        break;
+      }
+      case XFA_VT_TIME: {
+        WideString wsDate, wsTime;
+        if (SplitDateTime(wsValue, wsDate, wsTime)) {
+          CXFA_LocaleValue time(XFA_VT_TIME, wsTime, pLocaleMgr);
+          if (time.FormatPatterns(wsValue, wsPicture, pLocale, eValueType))
+            return wsValue;
+        }
+        break;
+      }
+      default:
+        break;
+    }
+    widgetValue.FormatPatterns(wsValue, wsPicture, pLocale, eValueType);
+  }
+  return wsValue;
 }
 
-Optional<int8_t> CXFA_Node::GetBarcodeAttribute_WideNarrowRatio() {
-  Optional<WideString> wsWideNarrowRatio =
-      GetWidgetAcc()->GetUIChild()->JSObject()->TryCData(
-          XFA_Attribute::WideNarrowRatio, true);
-  if (!wsWideNarrowRatio)
-    return {};
+WideString CXFA_Node::GetNormalizeDataValue(const WideString& wsValue) {
+  if (wsValue.IsEmpty())
+    return WideString();
 
-  Optional<size_t> ptPos = wsWideNarrowRatio->Find(':');
-  if (!ptPos)
-    return {static_cast<int8_t>(FXSYS_wtoi(wsWideNarrowRatio->c_str()))};
+  WideString wsPicture = GetPictureContent(XFA_VALUEPICTURE_DataBind);
+  if (wsPicture.IsEmpty())
+    return wsValue;
 
-  int32_t fB = FXSYS_wtoi(
-      wsWideNarrowRatio->Right(wsWideNarrowRatio->GetLength() - (*ptPos + 1))
-          .c_str());
-  if (!fB)
-    return {0};
+  CXFA_LocaleMgr* pLocaleMgr = GetDocument()->GetLocaleMgr();
+  LocaleIface* pLocale = GetLocale();
+  CXFA_LocaleValue widgetValue = XFA_GetLocaleValue(this);
+  if (widgetValue.ValidateValue(wsValue, wsPicture, pLocale, &wsPicture)) {
+    widgetValue = CXFA_LocaleValue(widgetValue.GetType(), wsValue, wsPicture,
+                                   pLocale, pLocaleMgr);
+    return widgetValue.GetValue();
+  }
+  return wsValue;
+}
 
-  int32_t fA = FXSYS_wtoi(wsWideNarrowRatio->Left(*ptPos).c_str());
-  float result = static_cast<float>(fA) / static_cast<float>(fB);
-  return {static_cast<int8_t>(result)};
+WideString CXFA_Node::GetFormatDataValue(const WideString& wsValue) {
+  if (wsValue.IsEmpty())
+    return WideString();
+
+  WideString wsPicture = GetPictureContent(XFA_VALUEPICTURE_DataBind);
+  if (wsPicture.IsEmpty())
+    return wsValue;
+
+  WideString wsFormattedValue = wsValue;
+  if (LocaleIface* pLocale = GetLocale()) {
+    CXFA_Value* pNodeValue = GetChild<CXFA_Value>(0, XFA_Element::Value, false);
+    if (!pNodeValue)
+      return wsValue;
+
+    CXFA_Node* pValueChild = pNodeValue->GetFirstChild();
+    if (!pValueChild)
+      return wsValue;
+
+    int32_t iVTType = XFA_VT_NULL;
+    switch (pValueChild->GetElementType()) {
+      case XFA_Element::Decimal:
+        iVTType = XFA_VT_DECIMAL;
+        break;
+      case XFA_Element::Float:
+        iVTType = XFA_VT_FLOAT;
+        break;
+      case XFA_Element::Date:
+        iVTType = XFA_VT_DATE;
+        break;
+      case XFA_Element::Time:
+        iVTType = XFA_VT_TIME;
+        break;
+      case XFA_Element::DateTime:
+        iVTType = XFA_VT_DATETIME;
+        break;
+      case XFA_Element::Boolean:
+        iVTType = XFA_VT_BOOLEAN;
+        break;
+      case XFA_Element::Integer:
+        iVTType = XFA_VT_INTEGER;
+        break;
+      case XFA_Element::Text:
+        iVTType = XFA_VT_TEXT;
+        break;
+      default:
+        iVTType = XFA_VT_NULL;
+        break;
+    }
+    CXFA_LocaleMgr* pLocaleMgr = GetDocument()->GetLocaleMgr();
+    CXFA_LocaleValue widgetValue(iVTType, wsValue, pLocaleMgr);
+    switch (widgetValue.GetType()) {
+      case XFA_VT_DATE: {
+        WideString wsDate, wsTime;
+        if (SplitDateTime(wsValue, wsDate, wsTime)) {
+          CXFA_LocaleValue date(XFA_VT_DATE, wsDate, pLocaleMgr);
+          if (date.FormatPatterns(wsFormattedValue, wsPicture, pLocale,
+                                  XFA_VALUEPICTURE_DataBind)) {
+            return wsFormattedValue;
+          }
+        }
+        break;
+      }
+      case XFA_VT_TIME: {
+        WideString wsDate, wsTime;
+        if (SplitDateTime(wsValue, wsDate, wsTime)) {
+          CXFA_LocaleValue time(XFA_VT_TIME, wsTime, pLocaleMgr);
+          if (time.FormatPatterns(wsFormattedValue, wsPicture, pLocale,
+                                  XFA_VALUEPICTURE_DataBind)) {
+            return wsFormattedValue;
+          }
+        }
+        break;
+      }
+      default:
+        break;
+    }
+    widgetValue.FormatPatterns(wsFormattedValue, wsPicture, pLocale,
+                               XFA_VALUEPICTURE_DataBind);
+  }
+  return wsFormattedValue;
+}
+
+WideString CXFA_Node::NormalizeNumStr(const WideString& wsValue) {
+  if (wsValue.IsEmpty())
+    return WideString();
+
+  WideString wsOutput = wsValue;
+  wsOutput.TrimLeft('0');
+
+  if (!wsOutput.IsEmpty() && wsOutput.Contains('.') && GetFracDigits() != -1) {
+    wsOutput.TrimRight(L"0");
+    wsOutput.TrimRight(L".");
+  }
+  if (wsOutput.IsEmpty() || wsOutput[0] == '.')
+    wsOutput.InsertAtFront('0');
+
+  return wsOutput;
+}
+
+void CXFA_Node::InsertListTextItem(CXFA_Node* pItems,
+                                   const WideString& wsText,
+                                   int32_t nIndex) {
+  CXFA_Node* pText = pItems->CreateSamePacketNode(XFA_Element::Text);
+  pItems->InsertChildAndNotify(nIndex, pText);
+  pText->JSObject()->SetContent(wsText, wsText, false, false, false);
+}
+
+WideString CXFA_Node::NumericLimit(const WideString& wsValue) {
+  int32_t iLead = GetLeadDigits();
+  int32_t iTread = GetFracDigits();
+
+  if ((iLead == -1) && (iTread == -1))
+    return wsValue;
+
+  WideString wsRet;
+  int32_t iLead_ = 0, iTread_ = -1;
+  int32_t iCount = wsValue.GetLength();
+  if (iCount == 0)
+    return wsValue;
+
+  int32_t i = 0;
+  if (wsValue[i] == L'-') {
+    wsRet += L'-';
+    i++;
+  }
+  for (; i < iCount; i++) {
+    wchar_t wc = wsValue[i];
+    if (FXSYS_IsDecimalDigit(wc)) {
+      if (iLead >= 0) {
+        iLead_++;
+        if (iLead_ > iLead)
+          return L"0";
+      } else if (iTread_ >= 0) {
+        iTread_++;
+        if (iTread_ > iTread) {
+          if (iTread != -1) {
+            CFGAS_Decimal wsDeci = CFGAS_Decimal(wsValue.AsStringView());
+            wsDeci.SetScale(iTread);
+            wsRet = wsDeci.ToWideString();
+          }
+          return wsRet;
+        }
+      }
+    } else if (wc == L'.') {
+      iTread_ = 0;
+      iLead = -1;
+    }
+    wsRet += wc;
+  }
+  return wsRet;
+}
+
+bool CXFA_Node::IsTransparent() const {
+  XFA_Element type = GetElementType();
+  return type == XFA_Element::SubformSet || type == XFA_Element::Area ||
+         type == XFA_Element::Proto || (IsUnnamed() && IsContainerNode());
+}
+
+bool CXFA_Node::IsProperty() const {
+  CXFA_Node* parent = GetParent();
+  return parent && parent->HasProperty(GetElementType());
+}
+
+bool CXFA_Node::PresenceRequiresSpace() const {
+  auto value = JSObject()->TryEnum(XFA_Attribute::Presence, true);
+  XFA_AttributeValue ePresence = value.value_or(XFA_AttributeValue::Visible);
+  return ePresence == XFA_AttributeValue::Visible ||
+         ePresence == XFA_AttributeValue::Invisible;
+}
+
+void CXFA_Node::SetBindingNode(CXFA_Node* node) {
+  binding_nodes_.clear();
+  if (node)
+    binding_nodes_.emplace_back(node);
+}
+
+void CXFA_Node::SetNodeAndDescendantsUnused() {
+  CXFA_NodeIterator sIterator(this);
+  for (CXFA_Node* pNode = sIterator.GetCurrent(); pNode;
+       pNode = sIterator.MoveToNext()) {
+    pNode->SetFlag(XFA_NodeFlag_UnusedNode);
+  }
+}
+
+void CXFA_Node::SetToXML(const WideString& value) {
+  auto* pNode = GetXMLMappingNode();
+  switch (pNode->GetType()) {
+    case CFX_XMLNode::Type::kElement: {
+      auto* elem = static_cast<CFX_XMLElement*>(pNode);
+      if (IsAttributeInXML()) {
+        elem->SetAttribute(JSObject()->GetCData(XFA_Attribute::QualifiedName),
+                           value);
+        return;
+      }
+
+      bool bDeleteChildren = true;
+      if (GetPacketType() == XFA_PacketType::Datasets) {
+        for (CXFA_Node* pChildDataNode = GetFirstChild(); pChildDataNode;
+             pChildDataNode = pChildDataNode->GetNextSibling()) {
+          if (pChildDataNode->HasBindItems()) {
+            bDeleteChildren = false;
+            break;
+          }
+        }
+      }
+      if (bDeleteChildren)
+        elem->RemoveAllChildren();
+
+      auto* text = GetXMLDocument()->CreateNode<CFX_XMLText>(value);
+      elem->AppendLastChild(text);
+      break;
+    }
+    case CFX_XMLNode::Type::kText:
+      ToXMLText(GetXMLMappingNode())->SetText(value);
+      break;
+    default:
+      NOTREACHED();
+  }
+}
+
+CXFA_Node* CXFA_Node::GetTransparentParent() {
+  CXFA_Node* parent = GetParent();
+  while (parent) {
+    XFA_Element type = parent->GetElementType();
+    if (type == XFA_Element::Variables ||
+        (type != XFA_Element::SubformSet && !parent->IsUnnamed())) {
+      return parent;
+    }
+    parent = parent->GetParent();
+  }
+  return nullptr;
+}
+
+CFX_XMLDocument* CXFA_Node::GetXMLDocument() const {
+  return GetDocument()->GetNotify()->GetHDOC()->GetXMLDocument();
+}
+
+// static
+std::unique_ptr<CXFA_Node> CXFA_Node::Create(CXFA_Document* doc,
+                                             XFA_Element element,
+                                             XFA_PacketType packet) {
+  std::unique_ptr<CXFA_Node> node;
+  switch (element) {
+    case XFA_Element::Ps:
+      node = pdfium::MakeUnique<CXFA_Ps>(doc, packet);
+      break;
+    case XFA_Element::To:
+      node = pdfium::MakeUnique<CXFA_To>(doc, packet);
+      break;
+    case XFA_Element::Ui:
+      node = pdfium::MakeUnique<CXFA_Ui>(doc, packet);
+      break;
+    case XFA_Element::RecordSet:
+      node = pdfium::MakeUnique<CXFA_RecordSet>(doc, packet);
+      break;
+    case XFA_Element::SubsetBelow:
+      node = pdfium::MakeUnique<CXFA_SubsetBelow>(doc, packet);
+      break;
+    case XFA_Element::SubformSet:
+      node = pdfium::MakeUnique<CXFA_SubformSet>(doc, packet);
+      break;
+    case XFA_Element::AdobeExtensionLevel:
+      node = pdfium::MakeUnique<CXFA_AdobeExtensionLevel>(doc, packet);
+      break;
+    case XFA_Element::Typeface:
+      node = pdfium::MakeUnique<CXFA_Typeface>(doc, packet);
+      break;
+    case XFA_Element::Break:
+      node = pdfium::MakeUnique<CXFA_Break>(doc, packet);
+      break;
+    case XFA_Element::FontInfo:
+      node = pdfium::MakeUnique<CXFA_FontInfo>(doc, packet);
+      break;
+    case XFA_Element::NumberPattern:
+      node = pdfium::MakeUnique<CXFA_NumberPattern>(doc, packet);
+      break;
+    case XFA_Element::DynamicRender:
+      node = pdfium::MakeUnique<CXFA_DynamicRender>(doc, packet);
+      break;
+    case XFA_Element::PrintScaling:
+      node = pdfium::MakeUnique<CXFA_PrintScaling>(doc, packet);
+      break;
+    case XFA_Element::CheckButton:
+      node = pdfium::MakeUnique<CXFA_CheckButton>(doc, packet);
+      break;
+    case XFA_Element::DatePatterns:
+      node = pdfium::MakeUnique<CXFA_DatePatterns>(doc, packet);
+      break;
+    case XFA_Element::SourceSet:
+      node = pdfium::MakeUnique<CXFA_SourceSet>(doc, packet);
+      break;
+    case XFA_Element::Amd:
+      node = pdfium::MakeUnique<CXFA_Amd>(doc, packet);
+      break;
+    case XFA_Element::Arc:
+      node = pdfium::MakeUnique<CXFA_Arc>(doc, packet);
+      break;
+    case XFA_Element::Day:
+      node = pdfium::MakeUnique<CXFA_Day>(doc, packet);
+      break;
+    case XFA_Element::Era:
+      node = pdfium::MakeUnique<CXFA_Era>(doc, packet);
+      break;
+    case XFA_Element::Jog:
+      node = pdfium::MakeUnique<CXFA_Jog>(doc, packet);
+      break;
+    case XFA_Element::Log:
+      node = pdfium::MakeUnique<CXFA_Log>(doc, packet);
+      break;
+    case XFA_Element::Map:
+      node = pdfium::MakeUnique<CXFA_Map>(doc, packet);
+      break;
+    case XFA_Element::Mdp:
+      node = pdfium::MakeUnique<CXFA_Mdp>(doc, packet);
+      break;
+    case XFA_Element::BreakBefore:
+      node = pdfium::MakeUnique<CXFA_BreakBefore>(doc, packet);
+      break;
+    case XFA_Element::Oid:
+      node = pdfium::MakeUnique<CXFA_Oid>(doc, packet);
+      break;
+    case XFA_Element::Pcl:
+      node = pdfium::MakeUnique<CXFA_Pcl>(doc, packet);
+      break;
+    case XFA_Element::Pdf:
+      node = pdfium::MakeUnique<CXFA_Pdf>(doc, packet);
+      break;
+    case XFA_Element::Ref:
+      node = pdfium::MakeUnique<CXFA_Ref>(doc, packet);
+      break;
+    case XFA_Element::Uri:
+      node = pdfium::MakeUnique<CXFA_Uri>(doc, packet);
+      break;
+    case XFA_Element::Xdc:
+      node = pdfium::MakeUnique<CXFA_Xdc>(doc, packet);
+      break;
+    case XFA_Element::Xdp:
+      node = pdfium::MakeUnique<CXFA_Xdp>(doc, packet);
+      break;
+    case XFA_Element::Xfa:
+      node = pdfium::MakeUnique<CXFA_Xfa>(doc, packet);
+      break;
+    case XFA_Element::Xsl:
+      node = pdfium::MakeUnique<CXFA_Xsl>(doc, packet);
+      break;
+    case XFA_Element::Zpl:
+      node = pdfium::MakeUnique<CXFA_Zpl>(doc, packet);
+      break;
+    case XFA_Element::Cache:
+      node = pdfium::MakeUnique<CXFA_Cache>(doc, packet);
+      break;
+    case XFA_Element::Margin:
+      node = pdfium::MakeUnique<CXFA_Margin>(doc, packet);
+      break;
+    case XFA_Element::KeyUsage:
+      node = pdfium::MakeUnique<CXFA_KeyUsage>(doc, packet);
+      break;
+    case XFA_Element::Exclude:
+      node = pdfium::MakeUnique<CXFA_Exclude>(doc, packet);
+      break;
+    case XFA_Element::ChoiceList:
+      node = pdfium::MakeUnique<CXFA_ChoiceList>(doc, packet);
+      break;
+    case XFA_Element::Level:
+      node = pdfium::MakeUnique<CXFA_Level>(doc, packet);
+      break;
+    case XFA_Element::LabelPrinter:
+      node = pdfium::MakeUnique<CXFA_LabelPrinter>(doc, packet);
+      break;
+    case XFA_Element::CalendarSymbols:
+      node = pdfium::MakeUnique<CXFA_CalendarSymbols>(doc, packet);
+      break;
+    case XFA_Element::Para:
+      node = pdfium::MakeUnique<CXFA_Para>(doc, packet);
+      break;
+    case XFA_Element::Part:
+      node = pdfium::MakeUnique<CXFA_Part>(doc, packet);
+      break;
+    case XFA_Element::Pdfa:
+      node = pdfium::MakeUnique<CXFA_Pdfa>(doc, packet);
+      break;
+    case XFA_Element::Filter:
+      node = pdfium::MakeUnique<CXFA_Filter>(doc, packet);
+      break;
+    case XFA_Element::Present:
+      node = pdfium::MakeUnique<CXFA_Present>(doc, packet);
+      break;
+    case XFA_Element::Pagination:
+      node = pdfium::MakeUnique<CXFA_Pagination>(doc, packet);
+      break;
+    case XFA_Element::Encoding:
+      node = pdfium::MakeUnique<CXFA_Encoding>(doc, packet);
+      break;
+    case XFA_Element::Event:
+      node = pdfium::MakeUnique<CXFA_Event>(doc, packet);
+      break;
+    case XFA_Element::Whitespace:
+      node = pdfium::MakeUnique<CXFA_Whitespace>(doc, packet);
+      break;
+    case XFA_Element::DefaultUi:
+      node = pdfium::MakeUnique<CXFA_DefaultUi>(doc, packet);
+      break;
+    case XFA_Element::DataModel:
+      node = pdfium::MakeUnique<CXFA_DataModel>(doc, packet);
+      break;
+    case XFA_Element::Barcode:
+      node = pdfium::MakeUnique<CXFA_Barcode>(doc, packet);
+      break;
+    case XFA_Element::TimePattern:
+      node = pdfium::MakeUnique<CXFA_TimePattern>(doc, packet);
+      break;
+    case XFA_Element::BatchOutput:
+      node = pdfium::MakeUnique<CXFA_BatchOutput>(doc, packet);
+      break;
+    case XFA_Element::Enforce:
+      node = pdfium::MakeUnique<CXFA_Enforce>(doc, packet);
+      break;
+    case XFA_Element::CurrencySymbols:
+      node = pdfium::MakeUnique<CXFA_CurrencySymbols>(doc, packet);
+      break;
+    case XFA_Element::AddSilentPrint:
+      node = pdfium::MakeUnique<CXFA_AddSilentPrint>(doc, packet);
+      break;
+    case XFA_Element::Rename:
+      node = pdfium::MakeUnique<CXFA_Rename>(doc, packet);
+      break;
+    case XFA_Element::Operation:
+      node = pdfium::MakeUnique<CXFA_Operation>(doc, packet);
+      break;
+    case XFA_Element::Typefaces:
+      node = pdfium::MakeUnique<CXFA_Typefaces>(doc, packet);
+      break;
+    case XFA_Element::SubjectDNs:
+      node = pdfium::MakeUnique<CXFA_SubjectDNs>(doc, packet);
+      break;
+    case XFA_Element::Issuers:
+      node = pdfium::MakeUnique<CXFA_Issuers>(doc, packet);
+      break;
+    case XFA_Element::WsdlConnection:
+      node = pdfium::MakeUnique<CXFA_WsdlConnection>(doc, packet);
+      break;
+    case XFA_Element::Debug:
+      node = pdfium::MakeUnique<CXFA_Debug>(doc, packet);
+      break;
+    case XFA_Element::Delta:
+      node = pdfium::MakeUnique<CXFA_Delta>(doc, packet);
+      break;
+    case XFA_Element::EraNames:
+      node = pdfium::MakeUnique<CXFA_EraNames>(doc, packet);
+      break;
+    case XFA_Element::ModifyAnnots:
+      node = pdfium::MakeUnique<CXFA_ModifyAnnots>(doc, packet);
+      break;
+    case XFA_Element::StartNode:
+      node = pdfium::MakeUnique<CXFA_StartNode>(doc, packet);
+      break;
+    case XFA_Element::Button:
+      node = pdfium::MakeUnique<CXFA_Button>(doc, packet);
+      break;
+    case XFA_Element::Format:
+      node = pdfium::MakeUnique<CXFA_Format>(doc, packet);
+      break;
+    case XFA_Element::Border:
+      node = pdfium::MakeUnique<CXFA_Border>(doc, packet);
+      break;
+    case XFA_Element::Area:
+      node = pdfium::MakeUnique<CXFA_Area>(doc, packet);
+      break;
+    case XFA_Element::Hyphenation:
+      node = pdfium::MakeUnique<CXFA_Hyphenation>(doc, packet);
+      break;
+    case XFA_Element::Text:
+      node = pdfium::MakeUnique<CXFA_Text>(doc, packet);
+      break;
+    case XFA_Element::Time:
+      node = pdfium::MakeUnique<CXFA_Time>(doc, packet);
+      break;
+    case XFA_Element::Type:
+      node = pdfium::MakeUnique<CXFA_Type>(doc, packet);
+      break;
+    case XFA_Element::Overprint:
+      node = pdfium::MakeUnique<CXFA_Overprint>(doc, packet);
+      break;
+    case XFA_Element::Certificates:
+      node = pdfium::MakeUnique<CXFA_Certificates>(doc, packet);
+      break;
+    case XFA_Element::EncryptionMethods:
+      node = pdfium::MakeUnique<CXFA_EncryptionMethods>(doc, packet);
+      break;
+    case XFA_Element::SetProperty:
+      node = pdfium::MakeUnique<CXFA_SetProperty>(doc, packet);
+      break;
+    case XFA_Element::PrinterName:
+      node = pdfium::MakeUnique<CXFA_PrinterName>(doc, packet);
+      break;
+    case XFA_Element::StartPage:
+      node = pdfium::MakeUnique<CXFA_StartPage>(doc, packet);
+      break;
+    case XFA_Element::PageOffset:
+      node = pdfium::MakeUnique<CXFA_PageOffset>(doc, packet);
+      break;
+    case XFA_Element::DateTime:
+      node = pdfium::MakeUnique<CXFA_DateTime>(doc, packet);
+      break;
+    case XFA_Element::Comb:
+      node = pdfium::MakeUnique<CXFA_Comb>(doc, packet);
+      break;
+    case XFA_Element::Pattern:
+      node = pdfium::MakeUnique<CXFA_Pattern>(doc, packet);
+      break;
+    case XFA_Element::IfEmpty:
+      node = pdfium::MakeUnique<CXFA_IfEmpty>(doc, packet);
+      break;
+    case XFA_Element::SuppressBanner:
+      node = pdfium::MakeUnique<CXFA_SuppressBanner>(doc, packet);
+      break;
+    case XFA_Element::OutputBin:
+      node = pdfium::MakeUnique<CXFA_OutputBin>(doc, packet);
+      break;
+    case XFA_Element::Field:
+      node = pdfium::MakeUnique<CXFA_Field>(doc, packet);
+      break;
+    case XFA_Element::Agent:
+      node = pdfium::MakeUnique<CXFA_Agent>(doc, packet);
+      break;
+    case XFA_Element::OutputXSL:
+      node = pdfium::MakeUnique<CXFA_OutputXSL>(doc, packet);
+      break;
+    case XFA_Element::AdjustData:
+      node = pdfium::MakeUnique<CXFA_AdjustData>(doc, packet);
+      break;
+    case XFA_Element::AutoSave:
+      node = pdfium::MakeUnique<CXFA_AutoSave>(doc, packet);
+      break;
+    case XFA_Element::ContentArea:
+      node = pdfium::MakeUnique<CXFA_ContentArea>(doc, packet);
+      break;
+    case XFA_Element::WsdlAddress:
+      node = pdfium::MakeUnique<CXFA_WsdlAddress>(doc, packet);
+      break;
+    case XFA_Element::Solid:
+      node = pdfium::MakeUnique<CXFA_Solid>(doc, packet);
+      break;
+    case XFA_Element::DateTimeSymbols:
+      node = pdfium::MakeUnique<CXFA_DateTimeSymbols>(doc, packet);
+      break;
+    case XFA_Element::EncryptionLevel:
+      node = pdfium::MakeUnique<CXFA_EncryptionLevel>(doc, packet);
+      break;
+    case XFA_Element::Edge:
+      node = pdfium::MakeUnique<CXFA_Edge>(doc, packet);
+      break;
+    case XFA_Element::Stipple:
+      node = pdfium::MakeUnique<CXFA_Stipple>(doc, packet);
+      break;
+    case XFA_Element::Attributes:
+      node = pdfium::MakeUnique<CXFA_Attributes>(doc, packet);
+      break;
+    case XFA_Element::VersionControl:
+      node = pdfium::MakeUnique<CXFA_VersionControl>(doc, packet);
+      break;
+    case XFA_Element::Meridiem:
+      node = pdfium::MakeUnique<CXFA_Meridiem>(doc, packet);
+      break;
+    case XFA_Element::ExclGroup:
+      node = pdfium::MakeUnique<CXFA_ExclGroup>(doc, packet);
+      break;
+    case XFA_Element::ToolTip:
+      node = pdfium::MakeUnique<CXFA_ToolTip>(doc, packet);
+      break;
+    case XFA_Element::Compress:
+      node = pdfium::MakeUnique<CXFA_Compress>(doc, packet);
+      break;
+    case XFA_Element::Reason:
+      node = pdfium::MakeUnique<CXFA_Reason>(doc, packet);
+      break;
+    case XFA_Element::Execute:
+      node = pdfium::MakeUnique<CXFA_Execute>(doc, packet);
+      break;
+    case XFA_Element::ContentCopy:
+      node = pdfium::MakeUnique<CXFA_ContentCopy>(doc, packet);
+      break;
+    case XFA_Element::DateTimeEdit:
+      node = pdfium::MakeUnique<CXFA_DateTimeEdit>(doc, packet);
+      break;
+    case XFA_Element::Config:
+      node = pdfium::MakeUnique<CXFA_Config>(doc, packet);
+      break;
+    case XFA_Element::Image:
+      node = pdfium::MakeUnique<CXFA_Image>(doc, packet);
+      break;
+    case XFA_Element::SharpxHTML:
+      node = pdfium::MakeUnique<CXFA_SharpxHTML>(doc, packet);
+      break;
+    case XFA_Element::NumberOfCopies:
+      node = pdfium::MakeUnique<CXFA_NumberOfCopies>(doc, packet);
+      break;
+    case XFA_Element::BehaviorOverride:
+      node = pdfium::MakeUnique<CXFA_BehaviorOverride>(doc, packet);
+      break;
+    case XFA_Element::TimeStamp:
+      node = pdfium::MakeUnique<CXFA_TimeStamp>(doc, packet);
+      break;
+    case XFA_Element::Month:
+      node = pdfium::MakeUnique<CXFA_Month>(doc, packet);
+      break;
+    case XFA_Element::ViewerPreferences:
+      node = pdfium::MakeUnique<CXFA_ViewerPreferences>(doc, packet);
+      break;
+    case XFA_Element::ScriptModel:
+      node = pdfium::MakeUnique<CXFA_ScriptModel>(doc, packet);
+      break;
+    case XFA_Element::Decimal:
+      node = pdfium::MakeUnique<CXFA_Decimal>(doc, packet);
+      break;
+    case XFA_Element::Subform:
+      node = pdfium::MakeUnique<CXFA_Subform>(doc, packet);
+      break;
+    case XFA_Element::Select:
+      node = pdfium::MakeUnique<CXFA_Select>(doc, packet);
+      break;
+    case XFA_Element::Window:
+      node = pdfium::MakeUnique<CXFA_Window>(doc, packet);
+      break;
+    case XFA_Element::LocaleSet:
+      node = pdfium::MakeUnique<CXFA_LocaleSet>(doc, packet);
+      break;
+    case XFA_Element::Handler:
+      node = pdfium::MakeUnique<CXFA_Handler>(doc, packet);
+      break;
+    case XFA_Element::Presence:
+      node = pdfium::MakeUnique<CXFA_Presence>(doc, packet);
+      break;
+    case XFA_Element::Record:
+      node = pdfium::MakeUnique<CXFA_Record>(doc, packet);
+      break;
+    case XFA_Element::Embed:
+      node = pdfium::MakeUnique<CXFA_Embed>(doc, packet);
+      break;
+    case XFA_Element::Version:
+      node = pdfium::MakeUnique<CXFA_Version>(doc, packet);
+      break;
+    case XFA_Element::Command:
+      node = pdfium::MakeUnique<CXFA_Command>(doc, packet);
+      break;
+    case XFA_Element::Copies:
+      node = pdfium::MakeUnique<CXFA_Copies>(doc, packet);
+      break;
+    case XFA_Element::Staple:
+      node = pdfium::MakeUnique<CXFA_Staple>(doc, packet);
+      break;
+    case XFA_Element::SubmitFormat:
+      node = pdfium::MakeUnique<CXFA_SubmitFormat>(doc, packet);
+      break;
+    case XFA_Element::Boolean:
+      node = pdfium::MakeUnique<CXFA_Boolean>(doc, packet);
+      break;
+    case XFA_Element::Message:
+      node = pdfium::MakeUnique<CXFA_Message>(doc, packet);
+      break;
+    case XFA_Element::Output:
+      node = pdfium::MakeUnique<CXFA_Output>(doc, packet);
+      break;
+    case XFA_Element::PsMap:
+      node = pdfium::MakeUnique<CXFA_PsMap>(doc, packet);
+      break;
+    case XFA_Element::ExcludeNS:
+      node = pdfium::MakeUnique<CXFA_ExcludeNS>(doc, packet);
+      break;
+    case XFA_Element::Assist:
+      node = pdfium::MakeUnique<CXFA_Assist>(doc, packet);
+      break;
+    case XFA_Element::Picture:
+      node = pdfium::MakeUnique<CXFA_Picture>(doc, packet);
+      break;
+    case XFA_Element::Traversal:
+      node = pdfium::MakeUnique<CXFA_Traversal>(doc, packet);
+      break;
+    case XFA_Element::SilentPrint:
+      node = pdfium::MakeUnique<CXFA_SilentPrint>(doc, packet);
+      break;
+    case XFA_Element::WebClient:
+      node = pdfium::MakeUnique<CXFA_WebClient>(doc, packet);
+      break;
+    case XFA_Element::Producer:
+      node = pdfium::MakeUnique<CXFA_Producer>(doc, packet);
+      break;
+    case XFA_Element::Corner:
+      node = pdfium::MakeUnique<CXFA_Corner>(doc, packet);
+      break;
+    case XFA_Element::MsgId:
+      node = pdfium::MakeUnique<CXFA_MsgId>(doc, packet);
+      break;
+    case XFA_Element::Color:
+      node = pdfium::MakeUnique<CXFA_Color>(doc, packet);
+      break;
+    case XFA_Element::Keep:
+      node = pdfium::MakeUnique<CXFA_Keep>(doc, packet);
+      break;
+    case XFA_Element::Query:
+      node = pdfium::MakeUnique<CXFA_Query>(doc, packet);
+      break;
+    case XFA_Element::Insert:
+      node = pdfium::MakeUnique<CXFA_Insert>(doc, packet);
+      break;
+    case XFA_Element::ImageEdit:
+      node = pdfium::MakeUnique<CXFA_ImageEdit>(doc, packet);
+      break;
+    case XFA_Element::Validate:
+      node = pdfium::MakeUnique<CXFA_Validate>(doc, packet);
+      break;
+    case XFA_Element::DigestMethods:
+      node = pdfium::MakeUnique<CXFA_DigestMethods>(doc, packet);
+      break;
+    case XFA_Element::NumberPatterns:
+      node = pdfium::MakeUnique<CXFA_NumberPatterns>(doc, packet);
+      break;
+    case XFA_Element::PageSet:
+      node = pdfium::MakeUnique<CXFA_PageSet>(doc, packet);
+      break;
+    case XFA_Element::Integer:
+      node = pdfium::MakeUnique<CXFA_Integer>(doc, packet);
+      break;
+    case XFA_Element::SoapAddress:
+      node = pdfium::MakeUnique<CXFA_SoapAddress>(doc, packet);
+      break;
+    case XFA_Element::Equate:
+      node = pdfium::MakeUnique<CXFA_Equate>(doc, packet);
+      break;
+    case XFA_Element::FormFieldFilling:
+      node = pdfium::MakeUnique<CXFA_FormFieldFilling>(doc, packet);
+      break;
+    case XFA_Element::PageRange:
+      node = pdfium::MakeUnique<CXFA_PageRange>(doc, packet);
+      break;
+    case XFA_Element::Update:
+      node = pdfium::MakeUnique<CXFA_Update>(doc, packet);
+      break;
+    case XFA_Element::ConnectString:
+      node = pdfium::MakeUnique<CXFA_ConnectString>(doc, packet);
+      break;
+    case XFA_Element::Mode:
+      node = pdfium::MakeUnique<CXFA_Mode>(doc, packet);
+      break;
+    case XFA_Element::Layout:
+      node = pdfium::MakeUnique<CXFA_Layout>(doc, packet);
+      break;
+    case XFA_Element::Sharpxml:
+      node = pdfium::MakeUnique<CXFA_Sharpxml>(doc, packet);
+      break;
+    case XFA_Element::XsdConnection:
+      node = pdfium::MakeUnique<CXFA_XsdConnection>(doc, packet);
+      break;
+    case XFA_Element::Traverse:
+      node = pdfium::MakeUnique<CXFA_Traverse>(doc, packet);
+      break;
+    case XFA_Element::Encodings:
+      node = pdfium::MakeUnique<CXFA_Encodings>(doc, packet);
+      break;
+    case XFA_Element::Template:
+      node = pdfium::MakeUnique<CXFA_Template>(doc, packet);
+      break;
+    case XFA_Element::Acrobat:
+      node = pdfium::MakeUnique<CXFA_Acrobat>(doc, packet);
+      break;
+    case XFA_Element::ValidationMessaging:
+      node = pdfium::MakeUnique<CXFA_ValidationMessaging>(doc, packet);
+      break;
+    case XFA_Element::Signing:
+      node = pdfium::MakeUnique<CXFA_Signing>(doc, packet);
+      break;
+    case XFA_Element::Script:
+      node = pdfium::MakeUnique<CXFA_Script>(doc, packet);
+      break;
+    case XFA_Element::AddViewerPreferences:
+      node = pdfium::MakeUnique<CXFA_AddViewerPreferences>(doc, packet);
+      break;
+    case XFA_Element::AlwaysEmbed:
+      node = pdfium::MakeUnique<CXFA_AlwaysEmbed>(doc, packet);
+      break;
+    case XFA_Element::PasswordEdit:
+      node = pdfium::MakeUnique<CXFA_PasswordEdit>(doc, packet);
+      break;
+    case XFA_Element::NumericEdit:
+      node = pdfium::MakeUnique<CXFA_NumericEdit>(doc, packet);
+      break;
+    case XFA_Element::EncryptionMethod:
+      node = pdfium::MakeUnique<CXFA_EncryptionMethod>(doc, packet);
+      break;
+    case XFA_Element::Change:
+      node = pdfium::MakeUnique<CXFA_Change>(doc, packet);
+      break;
+    case XFA_Element::PageArea:
+      node = pdfium::MakeUnique<CXFA_PageArea>(doc, packet);
+      break;
+    case XFA_Element::SubmitUrl:
+      node = pdfium::MakeUnique<CXFA_SubmitUrl>(doc, packet);
+      break;
+    case XFA_Element::Oids:
+      node = pdfium::MakeUnique<CXFA_Oids>(doc, packet);
+      break;
+    case XFA_Element::Signature:
+      node = pdfium::MakeUnique<CXFA_Signature>(doc, packet);
+      break;
+    case XFA_Element::ADBE_JSConsole:
+      node = pdfium::MakeUnique<CXFA_ADBE_JSConsole>(doc, packet);
+      break;
+    case XFA_Element::Caption:
+      node = pdfium::MakeUnique<CXFA_Caption>(doc, packet);
+      break;
+    case XFA_Element::Relevant:
+      node = pdfium::MakeUnique<CXFA_Relevant>(doc, packet);
+      break;
+    case XFA_Element::FlipLabel:
+      node = pdfium::MakeUnique<CXFA_FlipLabel>(doc, packet);
+      break;
+    case XFA_Element::ExData:
+      node = pdfium::MakeUnique<CXFA_ExData>(doc, packet);
+      break;
+    case XFA_Element::DayNames:
+      node = pdfium::MakeUnique<CXFA_DayNames>(doc, packet);
+      break;
+    case XFA_Element::SoapAction:
+      node = pdfium::MakeUnique<CXFA_SoapAction>(doc, packet);
+      break;
+    case XFA_Element::DefaultTypeface:
+      node = pdfium::MakeUnique<CXFA_DefaultTypeface>(doc, packet);
+      break;
+    case XFA_Element::Manifest:
+      node = pdfium::MakeUnique<CXFA_Manifest>(doc, packet);
+      break;
+    case XFA_Element::Overflow:
+      node = pdfium::MakeUnique<CXFA_Overflow>(doc, packet);
+      break;
+    case XFA_Element::Linear:
+      node = pdfium::MakeUnique<CXFA_Linear>(doc, packet);
+      break;
+    case XFA_Element::CurrencySymbol:
+      node = pdfium::MakeUnique<CXFA_CurrencySymbol>(doc, packet);
+      break;
+    case XFA_Element::Delete:
+      node = pdfium::MakeUnique<CXFA_Delete>(doc, packet);
+      break;
+    case XFA_Element::DigestMethod:
+      node = pdfium::MakeUnique<CXFA_DigestMethod>(doc, packet);
+      break;
+    case XFA_Element::InstanceManager:
+      node = pdfium::MakeUnique<CXFA_InstanceManager>(doc, packet);
+      break;
+    case XFA_Element::EquateRange:
+      node = pdfium::MakeUnique<CXFA_EquateRange>(doc, packet);
+      break;
+    case XFA_Element::Medium:
+      node = pdfium::MakeUnique<CXFA_Medium>(doc, packet);
+      break;
+    case XFA_Element::TextEdit:
+      node = pdfium::MakeUnique<CXFA_TextEdit>(doc, packet);
+      break;
+    case XFA_Element::TemplateCache:
+      node = pdfium::MakeUnique<CXFA_TemplateCache>(doc, packet);
+      break;
+    case XFA_Element::CompressObjectStream:
+      node = pdfium::MakeUnique<CXFA_CompressObjectStream>(doc, packet);
+      break;
+    case XFA_Element::DataValue:
+      node = pdfium::MakeUnique<CXFA_DataValue>(doc, packet);
+      break;
+    case XFA_Element::AccessibleContent:
+      node = pdfium::MakeUnique<CXFA_AccessibleContent>(doc, packet);
+      break;
+    case XFA_Element::IncludeXDPContent:
+      node = pdfium::MakeUnique<CXFA_IncludeXDPContent>(doc, packet);
+      break;
+    case XFA_Element::XmlConnection:
+      node = pdfium::MakeUnique<CXFA_XmlConnection>(doc, packet);
+      break;
+    case XFA_Element::ValidateApprovalSignatures:
+      node = pdfium::MakeUnique<CXFA_ValidateApprovalSignatures>(doc, packet);
+      break;
+    case XFA_Element::SignData:
+      node = pdfium::MakeUnique<CXFA_SignData>(doc, packet);
+      break;
+    case XFA_Element::Packets:
+      node = pdfium::MakeUnique<CXFA_Packets>(doc, packet);
+      break;
+    case XFA_Element::DatePattern:
+      node = pdfium::MakeUnique<CXFA_DatePattern>(doc, packet);
+      break;
+    case XFA_Element::DuplexOption:
+      node = pdfium::MakeUnique<CXFA_DuplexOption>(doc, packet);
+      break;
+    case XFA_Element::Base:
+      node = pdfium::MakeUnique<CXFA_Base>(doc, packet);
+      break;
+    case XFA_Element::Bind:
+      node = pdfium::MakeUnique<CXFA_Bind>(doc, packet);
+      break;
+    case XFA_Element::Compression:
+      node = pdfium::MakeUnique<CXFA_Compression>(doc, packet);
+      break;
+    case XFA_Element::User:
+      node = pdfium::MakeUnique<CXFA_User>(doc, packet);
+      break;
+    case XFA_Element::Rectangle:
+      node = pdfium::MakeUnique<CXFA_Rectangle>(doc, packet);
+      break;
+    case XFA_Element::EffectiveOutputPolicy:
+      node = pdfium::MakeUnique<CXFA_EffectiveOutputPolicy>(doc, packet);
+      break;
+    case XFA_Element::ADBE_JSDebugger:
+      node = pdfium::MakeUnique<CXFA_ADBE_JSDebugger>(doc, packet);
+      break;
+    case XFA_Element::Acrobat7:
+      node = pdfium::MakeUnique<CXFA_Acrobat7>(doc, packet);
+      break;
+    case XFA_Element::Interactive:
+      node = pdfium::MakeUnique<CXFA_Interactive>(doc, packet);
+      break;
+    case XFA_Element::Locale:
+      node = pdfium::MakeUnique<CXFA_Locale>(doc, packet);
+      break;
+    case XFA_Element::CurrentPage:
+      node = pdfium::MakeUnique<CXFA_CurrentPage>(doc, packet);
+      break;
+    case XFA_Element::Data:
+      node = pdfium::MakeUnique<CXFA_Data>(doc, packet);
+      break;
+    case XFA_Element::Date:
+      node = pdfium::MakeUnique<CXFA_Date>(doc, packet);
+      break;
+    case XFA_Element::Desc:
+      node = pdfium::MakeUnique<CXFA_Desc>(doc, packet);
+      break;
+    case XFA_Element::Encrypt:
+      node = pdfium::MakeUnique<CXFA_Encrypt>(doc, packet);
+      break;
+    case XFA_Element::Draw:
+      node = pdfium::MakeUnique<CXFA_Draw>(doc, packet);
+      break;
+    case XFA_Element::Encryption:
+      node = pdfium::MakeUnique<CXFA_Encryption>(doc, packet);
+      break;
+    case XFA_Element::MeridiemNames:
+      node = pdfium::MakeUnique<CXFA_MeridiemNames>(doc, packet);
+      break;
+    case XFA_Element::Messaging:
+      node = pdfium::MakeUnique<CXFA_Messaging>(doc, packet);
+      break;
+    case XFA_Element::Speak:
+      node = pdfium::MakeUnique<CXFA_Speak>(doc, packet);
+      break;
+    case XFA_Element::DataGroup:
+      node = pdfium::MakeUnique<CXFA_DataGroup>(doc, packet);
+      break;
+    case XFA_Element::Common:
+      node = pdfium::MakeUnique<CXFA_Common>(doc, packet);
+      break;
+    case XFA_Element::Sharptext:
+      node = pdfium::MakeUnique<CXFA_Sharptext>(doc, packet);
+      break;
+    case XFA_Element::PaginationOverride:
+      node = pdfium::MakeUnique<CXFA_PaginationOverride>(doc, packet);
+      break;
+    case XFA_Element::Reasons:
+      node = pdfium::MakeUnique<CXFA_Reasons>(doc, packet);
+      break;
+    case XFA_Element::SignatureProperties:
+      node = pdfium::MakeUnique<CXFA_SignatureProperties>(doc, packet);
+      break;
+    case XFA_Element::Threshold:
+      node = pdfium::MakeUnique<CXFA_Threshold>(doc, packet);
+      break;
+    case XFA_Element::AppearanceFilter:
+      node = pdfium::MakeUnique<CXFA_AppearanceFilter>(doc, packet);
+      break;
+    case XFA_Element::Fill:
+      node = pdfium::MakeUnique<CXFA_Fill>(doc, packet);
+      break;
+    case XFA_Element::Font:
+      node = pdfium::MakeUnique<CXFA_Font>(doc, packet);
+      break;
+    case XFA_Element::Form:
+      node = pdfium::MakeUnique<CXFA_Form>(doc, packet);
+      break;
+    case XFA_Element::MediumInfo:
+      node = pdfium::MakeUnique<CXFA_MediumInfo>(doc, packet);
+      break;
+    case XFA_Element::Certificate:
+      node = pdfium::MakeUnique<CXFA_Certificate>(doc, packet);
+      break;
+    case XFA_Element::Password:
+      node = pdfium::MakeUnique<CXFA_Password>(doc, packet);
+      break;
+    case XFA_Element::RunScripts:
+      node = pdfium::MakeUnique<CXFA_RunScripts>(doc, packet);
+      break;
+    case XFA_Element::Trace:
+      node = pdfium::MakeUnique<CXFA_Trace>(doc, packet);
+      break;
+    case XFA_Element::Float:
+      node = pdfium::MakeUnique<CXFA_Float>(doc, packet);
+      break;
+    case XFA_Element::RenderPolicy:
+      node = pdfium::MakeUnique<CXFA_RenderPolicy>(doc, packet);
+      break;
+    case XFA_Element::Destination:
+      node = pdfium::MakeUnique<CXFA_Destination>(doc, packet);
+      break;
+    case XFA_Element::Value:
+      node = pdfium::MakeUnique<CXFA_Value>(doc, packet);
+      break;
+    case XFA_Element::Bookend:
+      node = pdfium::MakeUnique<CXFA_Bookend>(doc, packet);
+      break;
+    case XFA_Element::ExObject:
+      node = pdfium::MakeUnique<CXFA_ExObject>(doc, packet);
+      break;
+    case XFA_Element::OpenAction:
+      node = pdfium::MakeUnique<CXFA_OpenAction>(doc, packet);
+      break;
+    case XFA_Element::NeverEmbed:
+      node = pdfium::MakeUnique<CXFA_NeverEmbed>(doc, packet);
+      break;
+    case XFA_Element::BindItems:
+      node = pdfium::MakeUnique<CXFA_BindItems>(doc, packet);
+      break;
+    case XFA_Element::Calculate:
+      node = pdfium::MakeUnique<CXFA_Calculate>(doc, packet);
+      break;
+    case XFA_Element::Print:
+      node = pdfium::MakeUnique<CXFA_Print>(doc, packet);
+      break;
+    case XFA_Element::Extras:
+      node = pdfium::MakeUnique<CXFA_Extras>(doc, packet);
+      break;
+    case XFA_Element::Proto:
+      node = pdfium::MakeUnique<CXFA_Proto>(doc, packet);
+      break;
+    case XFA_Element::DSigData:
+      node = pdfium::MakeUnique<CXFA_DSigData>(doc, packet);
+      break;
+    case XFA_Element::Creator:
+      node = pdfium::MakeUnique<CXFA_Creator>(doc, packet);
+      break;
+    case XFA_Element::Connect:
+      node = pdfium::MakeUnique<CXFA_Connect>(doc, packet);
+      break;
+    case XFA_Element::Permissions:
+      node = pdfium::MakeUnique<CXFA_Permissions>(doc, packet);
+      break;
+    case XFA_Element::ConnectionSet:
+      node = pdfium::MakeUnique<CXFA_ConnectionSet>(doc, packet);
+      break;
+    case XFA_Element::Submit:
+      node = pdfium::MakeUnique<CXFA_Submit>(doc, packet);
+      break;
+    case XFA_Element::Range:
+      node = pdfium::MakeUnique<CXFA_Range>(doc, packet);
+      break;
+    case XFA_Element::Linearized:
+      node = pdfium::MakeUnique<CXFA_Linearized>(doc, packet);
+      break;
+    case XFA_Element::Packet:
+      node = pdfium::MakeUnique<CXFA_Packet>(doc, packet);
+      break;
+    case XFA_Element::RootElement:
+      node = pdfium::MakeUnique<CXFA_RootElement>(doc, packet);
+      break;
+    case XFA_Element::PlaintextMetadata:
+      node = pdfium::MakeUnique<CXFA_PlaintextMetadata>(doc, packet);
+      break;
+    case XFA_Element::NumberSymbols:
+      node = pdfium::MakeUnique<CXFA_NumberSymbols>(doc, packet);
+      break;
+    case XFA_Element::PrintHighQuality:
+      node = pdfium::MakeUnique<CXFA_PrintHighQuality>(doc, packet);
+      break;
+    case XFA_Element::Driver:
+      node = pdfium::MakeUnique<CXFA_Driver>(doc, packet);
+      break;
+    case XFA_Element::IncrementalLoad:
+      node = pdfium::MakeUnique<CXFA_IncrementalLoad>(doc, packet);
+      break;
+    case XFA_Element::SubjectDN:
+      node = pdfium::MakeUnique<CXFA_SubjectDN>(doc, packet);
+      break;
+    case XFA_Element::CompressLogicalStructure:
+      node = pdfium::MakeUnique<CXFA_CompressLogicalStructure>(doc, packet);
+      break;
+    case XFA_Element::IncrementalMerge:
+      node = pdfium::MakeUnique<CXFA_IncrementalMerge>(doc, packet);
+      break;
+    case XFA_Element::Radial:
+      node = pdfium::MakeUnique<CXFA_Radial>(doc, packet);
+      break;
+    case XFA_Element::Variables:
+      node = pdfium::MakeUnique<CXFA_Variables>(doc, packet);
+      break;
+    case XFA_Element::TimePatterns:
+      node = pdfium::MakeUnique<CXFA_TimePatterns>(doc, packet);
+      break;
+    case XFA_Element::EffectiveInputPolicy:
+      node = pdfium::MakeUnique<CXFA_EffectiveInputPolicy>(doc, packet);
+      break;
+    case XFA_Element::NameAttr:
+      node = pdfium::MakeUnique<CXFA_NameAttr>(doc, packet);
+      break;
+    case XFA_Element::Conformance:
+      node = pdfium::MakeUnique<CXFA_Conformance>(doc, packet);
+      break;
+    case XFA_Element::Transform:
+      node = pdfium::MakeUnique<CXFA_Transform>(doc, packet);
+      break;
+    case XFA_Element::LockDocument:
+      node = pdfium::MakeUnique<CXFA_LockDocument>(doc, packet);
+      break;
+    case XFA_Element::BreakAfter:
+      node = pdfium::MakeUnique<CXFA_BreakAfter>(doc, packet);
+      break;
+    case XFA_Element::Line:
+      node = pdfium::MakeUnique<CXFA_Line>(doc, packet);
+      break;
+    case XFA_Element::Source:
+      node = pdfium::MakeUnique<CXFA_Source>(doc, packet);
+      break;
+    case XFA_Element::Occur:
+      node = pdfium::MakeUnique<CXFA_Occur>(doc, packet);
+      break;
+    case XFA_Element::PickTrayByPDFSize:
+      node = pdfium::MakeUnique<CXFA_PickTrayByPDFSize>(doc, packet);
+      break;
+    case XFA_Element::MonthNames:
+      node = pdfium::MakeUnique<CXFA_MonthNames>(doc, packet);
+      break;
+    case XFA_Element::Severity:
+      node = pdfium::MakeUnique<CXFA_Severity>(doc, packet);
+      break;
+    case XFA_Element::GroupParent:
+      node = pdfium::MakeUnique<CXFA_GroupParent>(doc, packet);
+      break;
+    case XFA_Element::DocumentAssembly:
+      node = pdfium::MakeUnique<CXFA_DocumentAssembly>(doc, packet);
+      break;
+    case XFA_Element::NumberSymbol:
+      node = pdfium::MakeUnique<CXFA_NumberSymbol>(doc, packet);
+      break;
+    case XFA_Element::Tagged:
+      node = pdfium::MakeUnique<CXFA_Tagged>(doc, packet);
+      break;
+    case XFA_Element::Items:
+      node = pdfium::MakeUnique<CXFA_Items>(doc, packet);
+      break;
+    default:
+      NOTREACHED();
+      return nullptr;
+  }
+  if (!node || !node->IsValidInPacket(packet))
+    return nullptr;
+  return node;
 }
diff --git a/xfa/fxfa/parser/cxfa_node.h b/xfa/fxfa/parser/cxfa_node.h
index c08a9af..097a6a1 100644
--- a/xfa/fxfa/parser/cxfa_node.h
+++ b/xfa/fxfa/parser/cxfa_node.h
@@ -7,17 +7,22 @@
 #ifndef XFA_FXFA_PARSER_CXFA_NODE_H_
 #define XFA_FXFA_PARSER_CXFA_NODE_H_
 
-#include <map>
 #include <memory>
 #include <utility>
 #include <vector>
 
 #include "core/fxcrt/fx_string.h"
+#include "core/fxcrt/tree_node.h"
 #include "core/fxge/fx_dib.h"
-#include "fxbarcode/BC_Library.h"
 #include "third_party/base/optional.h"
+#include "third_party/base/span.h"
+#include "xfa/fxfa/cxfa_ffwidget_type.h"
+#include "xfa/fxfa/fxfa.h"
 #include "xfa/fxfa/parser/cxfa_object.h"
 
+class CFGAS_GEFont;
+class CFX_DIBitmap;
+class CFX_XMLDocument;
 class CFX_XMLNode;
 class CXFA_Bind;
 class CXFA_Border;
@@ -25,21 +30,38 @@
 class CXFA_Caption;
 class CXFA_Event;
 class CXFA_EventParam;
+class CXFA_FFDoc;
 class CXFA_FFDocView;
 class CXFA_Font;
+class CXFA_Keep;
 class CXFA_Margin;
 class CXFA_Occur;
 class CXFA_Para;
 class CXFA_Script;
+class CXFA_TextLayout;
+class CXFA_Ui;
 class CXFA_Validate;
 class CXFA_Value;
-class CXFA_WidgetAcc;
-class IFX_Locale;
+class CXFA_WidgetLayoutData;
+class LocaleIface;
 
 #define XFA_NODEFILTER_Children 0x01
 #define XFA_NODEFILTER_Properties 0x02
 #define XFA_NODEFILTER_OneOfProperty 0x04
 
+enum XFA_CHECKSTATE {
+  XFA_CHECKSTATE_On = 0,
+  XFA_CHECKSTATE_Off = 1,
+  XFA_CHECKSTATE_Neutral = 2,
+};
+
+enum XFA_VALUEPICTURE {
+  XFA_VALUEPICTURE_Raw = 0,
+  XFA_VALUEPICTURE_Display,
+  XFA_VALUEPICTURE_Edit,
+  XFA_VALUEPICTURE_DataBind,
+};
+
 enum XFA_NodeFlag {
   XFA_NodeFlag_None = 0,
   XFA_NodeFlag_Initialized = 1 << 0,
@@ -47,13 +69,11 @@
   XFA_NodeFlag_NeedsInitApp = 1 << 2,
   XFA_NodeFlag_BindFormItems = 1 << 3,
   XFA_NodeFlag_UserInteractive = 1 << 4,
-  XFA_NodeFlag_SkipDataBinding = 1 << 5,
-  XFA_NodeFlag_OwnXMLNode = 1 << 6,
-  XFA_NodeFlag_UnusedNode = 1 << 7,
-  XFA_NodeFlag_LayoutGeneratedNode = 1 << 8
+  XFA_NodeFlag_UnusedNode = 1 << 5,
+  XFA_NodeFlag_LayoutGeneratedNode = 1 << 6
 };
 
-class CXFA_Node : public CXFA_Object {
+class CXFA_Node : public CXFA_Object, public TreeNode<CXFA_Node> {
  public:
   struct PropertyData {
     XFA_Element property;
@@ -67,37 +87,32 @@
     void* default_value;
   };
 
-#ifndef NDEBUG
-  static WideString ElementToName(XFA_Element elem);
-#endif  // NDEBUG
-
-  static WideString AttributeEnumToName(XFA_AttributeEnum item);
-  static Optional<XFA_AttributeEnum> NameToAttributeEnum(
-      const WideStringView& name);
-  static XFA_Attribute NameToAttribute(const WideStringView& name);
-  static WideString AttributeToName(XFA_Attribute attr);
-  static XFA_Element NameToElement(const WideString& name);
   static std::unique_ptr<CXFA_Node> Create(CXFA_Document* doc,
                                            XFA_Element element,
                                            XFA_PacketType packet);
 
   ~CXFA_Node() override;
 
-  bool IsValidInPacket(XFA_PacketType packet) const;
-
   bool HasProperty(XFA_Element property) const;
   bool HasPropertyFlags(XFA_Element property, uint8_t flags) const;
   uint8_t PropertyOccuranceCount(XFA_Element property) const;
 
+  std::pair<CXFA_Node*, int32_t> GetProperty(int32_t index,
+                                             XFA_Element eProperty) const;
+  CXFA_Node* GetOrCreateProperty(int32_t index, XFA_Element eProperty);
+
   void SendAttributeChangeMessage(XFA_Attribute eAttribute, bool bScriptModify);
 
   bool HasAttribute(XFA_Attribute attr) const;
-  XFA_Attribute GetAttribute(size_t i) const;
   XFA_AttributeType GetAttributeType(XFA_Attribute type) const;
 
+  // Note: returns XFA_Attribute::Unknown for invalid indicies.
+  XFA_Attribute GetAttribute(size_t i) const;
+
   XFA_PacketType GetPacketType() const { return m_ePacket; }
 
-  void SetFlag(uint32_t dwFlag, bool bNotify);
+  void SetFlag(uint32_t dwFlag);
+  void SetFlagAndNotify(uint32_t dwFlag);
   void ClearFlag(uint32_t dwFlag);
 
   CXFA_Node* CreateInstanceIfPossible(bool bDataMerge);
@@ -110,7 +125,6 @@
                   bool bMoveDataBindingNodes);
 
   bool IsInitialized() const { return HasFlag(XFA_NodeFlag_Initialized); }
-  bool IsOwnXMLNode() const { return HasFlag(XFA_NodeFlag_OwnXMLNode); }
   bool IsUserInteractive() const {
     return HasFlag(XFA_NodeFlag_UserInteractive);
   }
@@ -119,40 +133,26 @@
     return HasFlag(XFA_NodeFlag_LayoutGeneratedNode);
   }
 
-  void SetBindingNodes(std::vector<UnownedPtr<CXFA_Node>> nodes) {
-    binding_nodes_ = std::move(nodes);
-  }
-  std::vector<UnownedPtr<CXFA_Node>>* GetBindingNodes() {
-    return &binding_nodes_;
-  }
-  void SetBindingNode(CXFA_Node* node) {
-    binding_nodes_.clear();
-    if (node)
-      binding_nodes_.emplace_back(node);
-  }
-  CXFA_Node* GetBindingNode() const {
-    if (binding_nodes_.empty())
-      return nullptr;
-    return binding_nodes_[0].Get();
-  }
-  // TODO(dsinclair): This should not be needed. Nodes should get un-bound when
-  // they're deleted instead of us pointing to bad objects.
-  void ReleaseBindingNodes();
+  bool PresenceRequiresSpace() const;
+  void SetBindingNode(CXFA_Node* node);
+  void SetNodeAndDescendantsUnused();
 
-  bool BindsFormItems() const { return HasFlag(XFA_NodeFlag_BindFormItems); }
   bool HasRemovedChildren() const {
     return HasFlag(XFA_NodeFlag_HasRemovedChildren);
   }
-  bool NeedsInitApp() const { return HasFlag(XFA_NodeFlag_NeedsInitApp); }
 
   bool IsAttributeInXML();
   bool IsFormContainer() const {
     return m_ePacket == XFA_PacketType::Form && IsContainerNode();
   }
-  void SetXMLMappingNode(CFX_XMLNode* pXMLNode) { m_pXMLNode = pXMLNode; }
-  CFX_XMLNode* GetXMLMappingNode() const { return m_pXMLNode; }
+
+  void SetXMLMappingNode(CFX_XMLNode* node) { xml_node_ = node; }
+  CFX_XMLNode* GetXMLMappingNode() const { return xml_node_.Get(); }
   CFX_XMLNode* CreateXMLMappingNode();
-  bool IsNeedSavingXMLNode();
+  bool IsNeedSavingXMLNode() const;
+
+  void SetToXML(const WideString& value);
+
   uint32_t GetNameHash() const { return m_dwNameHash; }
   bool IsUnnamed() const { return m_dwNameHash == 0; }
   CXFA_Node* GetModelNode();
@@ -165,24 +165,19 @@
     return static_cast<T*>(GetChildInternal(index, eType, bOnlyChild));
   }
 
-  int32_t InsertChild(int32_t index, CXFA_Node* pNode);
-  bool InsertChild(CXFA_Node* pNode, CXFA_Node* pBeforeNode);
-  bool RemoveChild(CXFA_Node* pNode, bool bNotify);
+  void InsertChildAndNotify(int32_t index, CXFA_Node* pNode);
+  void InsertChildAndNotify(CXFA_Node* pNode, CXFA_Node* pBeforeNode);
+  void RemoveChildAndNotify(CXFA_Node* pNode, bool bNotify);
 
   CXFA_Node* Clone(bool bRecursive);
 
-  CXFA_Node* GetNextSibling() const { return m_pNext; }
-  CXFA_Node* GetPrevSibling() const;
-  CXFA_Node* GetFirstChild() const { return m_pChild; }
-  CXFA_Node* GetParent() const { return m_pParent; }
-
   CXFA_Node* GetNextContainerSibling() const;
   CXFA_Node* GetPrevContainerSibling() const;
   CXFA_Node* GetFirstContainerChild() const;
   CXFA_Node* GetContainerParent() const;
 
-  std::vector<CXFA_Node*> GetNodeList(uint32_t dwTypeFilter,
-                                      XFA_Element eTypeFilter);
+  std::vector<CXFA_Node*> GetNodeListForType(XFA_Element eTypeFilter);
+  std::vector<CXFA_Node*> GetNodeListWithFilter(uint32_t dwTypeFilter);
   CXFA_Node* CreateSamePacketNode(XFA_Element eType);
   CXFA_Node* CloneTemplateToForm(bool bRecursive);
   CXFA_Node* GetTemplateNodeIfExists() const;
@@ -190,16 +185,18 @@
   CXFA_Node* GetDataDescriptionNode();
   void SetDataDescriptionNode(CXFA_Node* pDataDescriptionNode);
   CXFA_Node* GetBindData();
-  std::vector<UnownedPtr<CXFA_Node>>* GetBindItems();
+  bool HasBindItems() const { return !binding_nodes_.empty(); }
+  std::vector<CXFA_Node*> GetBindItemsCopy() { return binding_nodes_; }
   int32_t AddBindItem(CXFA_Node* pFormNode);
   int32_t RemoveBindItem(CXFA_Node* pFormNode);
-  bool HasBindItem();
-  CXFA_WidgetAcc* GetContainerWidgetAcc();
-  IFX_Locale* GetLocale();
+  bool HasBindItem() const;
+  CXFA_Node* GetContainerNode();
+  LocaleIface* GetLocale();
   Optional<WideString> GetLocaleName();
-  XFA_AttributeEnum GetIntact();
+  XFA_AttributeValue GetIntact();
+  WideString GetNameExpression();
 
-  CXFA_Node* GetFirstChildByName(const WideStringView& wsNodeName) const;
+  CXFA_Node* GetFirstChildByName(WideStringView wsNodeName) const;
   CXFA_Node* GetFirstChildByName(uint32_t dwNodeNameHash) const;
   template <typename T>
   T* GetFirstChildByClass(XFA_Element eType) const {
@@ -207,7 +204,7 @@
   }
   CXFA_Node* GetNextSameNameSibling(uint32_t dwNodeNameHash) const;
   template <typename T>
-  T* GetNextSameNameSibling(const WideStringView& wsNodeName) const {
+  T* GetNextSameNameSibling(WideStringView wsNodeName) const {
     return static_cast<T*>(GetNextSameNameSiblingInternal(wsNodeName));
   }
   template <typename T>
@@ -215,28 +212,31 @@
     return static_cast<T*>(GetNextSameClassSiblingInternal(eType));
   }
 
-  int32_t GetNodeSameNameIndex() const;
-  int32_t GetNodeSameClassIndex() const;
-  CXFA_Node* GetInstanceMgrOfSubform();
+  CXFA_Node* GetOneChildNamed(WideStringView wsName);
+  CXFA_Node* GetOneChildOfClass(WideStringView wsClass);
 
-  CXFA_Occur* GetOccurIfExists();
+  std::vector<CXFA_Node*> GetSiblings(bool bIsClassName);
+  size_t GetIndex(bool bIsProperty, bool bIsClassIndex);
+  size_t GetIndexByName();
+  size_t GetIndexByClassName();
+
+  CXFA_Node* GetInstanceMgrOfSubform();
 
   Optional<bool> GetDefaultBoolean(XFA_Attribute attr) const;
   Optional<int32_t> GetDefaultInteger(XFA_Attribute attr) const;
   Optional<CXFA_Measurement> GetDefaultMeasurement(XFA_Attribute attr) const;
   Optional<WideString> GetDefaultCData(XFA_Attribute attr) const;
-  Optional<XFA_AttributeEnum> GetDefaultEnum(XFA_Attribute attr) const;
+  Optional<XFA_AttributeValue> GetDefaultEnum(XFA_Attribute attr) const;
 
-  void SyncValue(const WideString& wsValue, bool bNotify);
+  bool IsOpenAccess() const;
 
-  bool IsOpenAccess();
-
+  CXFA_Occur* GetOccurIfExists();
   CXFA_Border* GetBorderIfExists() const;
   CXFA_Border* GetOrCreateBorderIfPossible();
   CXFA_Caption* GetCaptionIfExists() const;
-
   CXFA_Font* GetFontIfExists() const;
   CXFA_Font* GetOrCreateFontIfPossible();
+
   float GetFontSize() const;
   FX_ARGB GetTextColor() const;
   float GetLineHeight() const;
@@ -247,52 +247,141 @@
   CXFA_Validate* GetValidateIfExists() const;
   CXFA_Validate* GetOrCreateValidateIfPossible();
 
-  CXFA_Value* GetDefaultValueIfExists();
   CXFA_Value* GetFormValueIfExists() const;
   WideString GetRawValue();
-  int32_t GetRotate();
 
-  CXFA_Bind* GetBindIfExists() const;
-
+  int32_t GetRotate() const;
   Optional<float> TryWidth();
-  Optional<float> TryHeight();
-  Optional<float> TryMinWidth();
-  Optional<float> TryMinHeight();
-  Optional<float> TryMaxWidth();
-  Optional<float> TryMaxHeight();
 
   CXFA_Node* GetExclGroupIfExists();
 
-  int32_t ProcessEvent(CXFA_FFDocView* docView,
-                       XFA_AttributeEnum iActivity,
-                       CXFA_EventParam* pEventParam);
-  int32_t ProcessEvent(CXFA_FFDocView* docView,
-                       CXFA_Event* event,
-                       CXFA_EventParam* pEventParam);
-  int32_t ProcessCalculate(CXFA_FFDocView* docView);
-  int32_t ProcessValidate(CXFA_FFDocView* docView, int32_t iFlags);
+  XFA_EventError ProcessEvent(CXFA_FFDocView* pDocView,
+                              XFA_AttributeValue iActivity,
+                              CXFA_EventParam* pEventParam);
+  XFA_EventError ProcessCalculate(CXFA_FFDocView* pDocView);
+  XFA_EventError ProcessValidate(CXFA_FFDocView* pDocView, int32_t iFlags);
+  XFA_EventError ExecuteScript(CXFA_FFDocView* pDocView,
+                               CXFA_Script* script,
+                               CXFA_EventParam* pEventParam);
+  std::pair<XFA_EventError, bool> ExecuteBoolScript(
+      CXFA_FFDocView* pDocView,
+      CXFA_Script* script,
+      CXFA_EventParam* pEventParam);
 
-  int32_t ExecuteScript(CXFA_FFDocView* docView,
-                        CXFA_Script* script,
-                        CXFA_EventParam* pEventParam);
-  std::pair<int32_t, bool> ExecuteBoolScript(CXFA_FFDocView* docView,
-                                             CXFA_Script* script,
-                                             CXFA_EventParam* pEventParam);
+  CXFA_Node* GetUIChildNode();
 
-  // TODO(dsinclair): Figure out how to move this to cxfa_barcode.
-  WideString GetBarcodeType();
-  Optional<BC_CHAR_ENCODING> GetBarcodeAttribute_CharEncoding();
-  Optional<bool> GetBarcodeAttribute_Checksum();
-  Optional<int32_t> GetBarcodeAttribute_DataLength();
-  Optional<char> GetBarcodeAttribute_StartChar();
-  Optional<char> GetBarcodeAttribute_EndChar();
-  Optional<int32_t> GetBarcodeAttribute_ECLevel();
-  Optional<int32_t> GetBarcodeAttribute_ModuleWidth();
-  Optional<int32_t> GetBarcodeAttribute_ModuleHeight();
-  Optional<bool> GetBarcodeAttribute_PrintChecksum();
-  Optional<BC_TEXT_LOC> GetBarcodeAttribute_TextLocation();
-  Optional<bool> GetBarcodeAttribute_Truncate();
-  Optional<int8_t> GetBarcodeAttribute_WideNarrowRatio();
+  // NOTE: value returned is often determined by child UI node, and
+  // can't be used to infer anything about this particual node itself.
+  XFA_FFWidgetType GetFFWidgetType();
+
+  CFX_RectF GetUIMargin();
+  CXFA_Border* GetUIBorder();
+
+  void SetPreNull(bool val) { m_bPreNull = val; }
+  bool IsNull() const { return m_bIsNull; }
+  void SetIsNull(bool val) { m_bIsNull = val; }
+
+  void SetWidgetReady() { is_widget_ready_ = true; }
+  bool IsWidgetReady() const { return is_widget_ready_; }
+  std::vector<CXFA_Event*> GetEventByActivity(XFA_AttributeValue iActivity,
+                                              bool bIsFormReady);
+
+  void ResetData();
+  void StartWidgetLayout(CXFA_FFDoc* doc,
+                         float* pCalcWidth,
+                         float* pCalcHeight);
+  Optional<float> FindSplitPos(CXFA_FFDocView* pDocView,
+                               size_t szBlockIndex,
+                               float fCalcHeight);
+
+  bool LoadCaption(CXFA_FFDoc* doc);
+  CXFA_TextLayout* GetCaptionTextLayout();
+  CXFA_TextLayout* GetTextLayout();
+
+  bool LoadImageImage(CXFA_FFDoc* doc);
+  bool LoadImageEditImage(CXFA_FFDoc* doc);
+  CFX_Size GetImageDpi() const;
+  CFX_Size GetImageEditDpi() const;
+
+  RetainPtr<CFX_DIBitmap> GetImageImage();
+  RetainPtr<CFX_DIBitmap> GetImageEditImage();
+  void SetImageImage(const RetainPtr<CFX_DIBitmap>& newImage);
+  void SetImageEditImage(const RetainPtr<CFX_DIBitmap>& newImage);
+
+  RetainPtr<CFGAS_GEFont> GetFDEFont(CXFA_FFDoc* doc);
+
+  bool IsListBox();
+  bool IsRadioButton();
+  bool IsMultiLine();
+
+  bool HasButtonRollover();
+  bool HasButtonDown();
+
+  float GetCheckButtonSize();
+
+  XFA_CHECKSTATE GetCheckState();
+  void SetCheckState(XFA_CHECKSTATE eCheckState, bool bNotify);
+
+  CXFA_Node* GetSelectedMember();
+  CXFA_Node* SetSelectedMember(WideStringView wsName, bool bNotify);
+  void SetSelectedMemberByValue(WideStringView wsValue,
+                                bool bNotify,
+                                bool bScriptModify,
+                                bool bSyncData);
+
+  CXFA_Node* GetExclGroupFirstMember();
+  CXFA_Node* GetExclGroupNextMember(CXFA_Node* pNode);
+
+  bool IsChoiceListAllowTextEntry();
+  int32_t CountChoiceListItems(bool bSaveValue);
+  Optional<WideString> GetChoiceListItem(int32_t nIndex, bool bSaveValue);
+  bool IsChoiceListMultiSelect();
+  bool IsChoiceListCommitOnSelect();
+  std::vector<WideString> GetChoiceListItems(bool bSaveValue);
+
+  int32_t CountSelectedItems();
+  int32_t GetSelectedItem(int32_t nIndex);
+  std::vector<int32_t> GetSelectedItems();
+  std::vector<WideString> GetSelectedItemsValue();
+  void SetSelectedItems(const std::vector<int32_t>& iSelArray,
+                        bool bNotify,
+                        bool bScriptModify,
+                        bool bSyncData);
+  void InsertItem(const WideString& wsLabel,
+                  const WideString& wsValue,
+                  bool bNotify);
+  bool DeleteItem(int32_t nIndex, bool bNotify, bool bScriptModify);
+  void ClearAllSelections();
+
+  bool GetItemState(int32_t nIndex);
+  void SetItemState(int32_t nIndex,
+                    bool bSelected,
+                    bool bNotify,
+                    bool bScriptModify,
+                    bool bSyncData);
+
+  WideString GetItemValue(WideStringView wsLabel);
+
+  bool IsHorizontalScrollPolicyOff();
+  bool IsVerticalScrollPolicyOff();
+  Optional<int32_t> GetNumberOfCells();
+
+  bool SetValue(XFA_VALUEPICTURE eValueType, const WideString& wsValue);
+  WideString GetValue(XFA_VALUEPICTURE eValueType);
+
+  WideString GetPictureContent(XFA_VALUEPICTURE ePicture);
+  WideString GetNormalizeDataValue(const WideString& wsValue);
+  WideString GetFormatDataValue(const WideString& wsValue);
+  WideString NormalizeNumStr(const WideString& wsValue);
+
+  std::pair<XFA_Element, int32_t> GetMaxChars();
+  int32_t GetFracDigits();
+  int32_t GetLeadDigits();
+
+  WideString NumericLimit(const WideString& wsValue);
+
+  bool IsTransparent() const;
+  bool IsProperty() const;
 
  protected:
   CXFA_Node(CXFA_Document* pDoc,
@@ -300,63 +389,117 @@
             uint32_t validPackets,
             XFA_ObjectType oType,
             XFA_Element eType,
-            const PropertyData* properties,
-            const AttributeData* attributes,
-            const WideStringView& elementName,
-            std::unique_ptr<CJX_Object> js_node);
-  CXFA_Node(CXFA_Document* pDoc,
-            XFA_PacketType ePacket,
-            uint32_t validPackets,
-            XFA_ObjectType oType,
-            XFA_Element eType,
-            const PropertyData* properties,
-            const AttributeData* attributes,
-            const WideStringView& elementName);
+            pdfium::span<const PropertyData> properties,
+            pdfium::span<const AttributeData> attributes,
+            std::unique_ptr<CJX_Object> js_object);
+
+  virtual XFA_Element GetValueNodeType() const;
+  virtual XFA_FFWidgetType GetDefaultFFWidgetType() const;
 
  private:
-  void ProcessScriptTestValidate(CXFA_FFDocView* docView,
+  void ProcessScriptTestValidate(CXFA_FFDocView* pDocView,
                                  CXFA_Validate* validate,
-                                 int32_t iRet,
+                                 XFA_EventError iRet,
                                  bool pRetValue,
                                  bool bVersionFlag);
-  int32_t ProcessFormatTestValidate(CXFA_FFDocView* docView,
-                                    CXFA_Validate* validate,
-                                    bool bVersionFlag);
-  int32_t ProcessNullTestValidate(CXFA_FFDocView* docView,
-                                  CXFA_Validate* validate,
-                                  int32_t iFlags,
-                                  bool bVersionFlag);
+  XFA_EventError ProcessFormatTestValidate(CXFA_FFDocView* pDocView,
+                                           CXFA_Validate* validate,
+                                           bool bVersionFlag);
+  XFA_EventError ProcessNullTestValidate(CXFA_FFDocView* pDocView,
+                                         CXFA_Validate* validate,
+                                         int32_t iFlags,
+                                         bool bVersionFlag);
   WideString GetValidateCaptionName(bool bVersionFlag);
   WideString GetValidateMessage(bool bError, bool bVersionFlag);
 
   bool HasFlag(XFA_NodeFlag dwFlag) const;
-  CXFA_Node* Deprecated_GetPrevSibling();
   const PropertyData* GetPropertyData(XFA_Element property) const;
   const AttributeData* GetAttributeData(XFA_Attribute attr) const;
-  Optional<XFA_Element> GetFirstPropertyWithFlag(uint8_t flag);
-  void OnRemoved(bool bNotify);
+  Optional<XFA_Element> GetFirstPropertyWithFlag(uint8_t flag) const;
+  void OnRemoved(bool bNotify) const;
   Optional<void*> GetDefaultValue(XFA_Attribute attr,
                                   XFA_AttributeType eType) const;
-  CXFA_Node* GetChildInternal(size_t index, XFA_Element eType, bool bOnlyChild);
+  CXFA_Node* GetChildInternal(size_t index,
+                              XFA_Element eType,
+                              bool bOnlyChild) const;
   CXFA_Node* GetFirstChildByClassInternal(XFA_Element eType) const;
-  CXFA_Node* GetNextSameNameSiblingInternal(
-      const WideStringView& wsNodeName) const;
+  CXFA_Node* GetNextSameNameSiblingInternal(WideStringView wsNodeName) const;
   CXFA_Node* GetNextSameClassSiblingInternal(XFA_Element eType) const;
+  void CalcCaptionSize(CXFA_FFDoc* doc, CFX_SizeF* pszCap);
+  bool CalculateFieldAutoSize(CXFA_FFDoc* doc, CFX_SizeF* pSize);
+  bool CalculateWidgetAutoSize(CFX_SizeF* pSize);
+  bool CalculateTextEditAutoSize(CXFA_FFDoc* doc, CFX_SizeF* pSize);
+  bool CalculateCheckButtonAutoSize(CXFA_FFDoc* doc, CFX_SizeF* pSize);
+  bool CalculatePushButtonAutoSize(CXFA_FFDoc* doc, CFX_SizeF* pSize);
+  CFX_SizeF CalculateImageSize(float img_width,
+                               float img_height,
+                               const CFX_Size& dpi);
+  bool CalculateImageEditAutoSize(CXFA_FFDoc* doc, CFX_SizeF* pSize);
+  bool CalculateImageAutoSize(CXFA_FFDoc* doc, CFX_SizeF* pSize);
+  float CalculateWidgetAutoHeight(float fHeightCalc);
+  float CalculateWidgetAutoWidth(float fWidthCalc);
+  float GetWidthWithoutMargin(float fWidthCalc) const;
+  float GetHeightWithoutMargin(float fHeightCalc) const;
+  void CalculateTextContentSize(CXFA_FFDoc* doc, CFX_SizeF* pSize);
+  CFX_SizeF CalculateAccWidthAndHeight(CXFA_FFDoc* doc, float fWidth);
+  void InitLayoutData();
+  void StartTextLayout(CXFA_FFDoc* doc, float* pCalcWidth, float* pCalcHeight);
 
-  const PropertyData* const m_Properties;
-  const AttributeData* const m_Attributes;
+  void InsertListTextItem(CXFA_Node* pItems,
+                          const WideString& wsText,
+                          int32_t nIndex);
+  WideString GetItemLabel(WideStringView wsValue) const;
+
+  std::pair<XFA_FFWidgetType, CXFA_Ui*> CreateChildUIAndValueNodesIfNeeded();
+  void CreateValueNodeIfNeeded(CXFA_Value* value, CXFA_Node* pUIChild);
+  CXFA_Node* CreateUINodeIfNeeded(CXFA_Ui* ui, XFA_Element type);
+  bool IsValidInPacket(XFA_PacketType packet) const;
+  void SetImageEdit(const WideString& wsContentType,
+                    const WideString& wsHref,
+                    const WideString& wsData);
+  CXFA_Node* GetBindingNode() const {
+    if (binding_nodes_.empty())
+      return nullptr;
+    return binding_nodes_[0];
+  }
+  bool BindsFormItems() const { return HasFlag(XFA_NodeFlag_BindFormItems); }
+  bool NeedsInitApp() const { return HasFlag(XFA_NodeFlag_NeedsInitApp); }
+  void SyncValue(const WideString& wsValue, bool bNotify);
+  CXFA_Value* GetDefaultValueIfExists();
+  CXFA_Bind* GetBindIfExists() const;
+  Optional<XFA_AttributeValue> GetIntactFromKeep(
+      const CXFA_Keep* pKeep,
+      XFA_AttributeValue eLayoutType) const;
+  CXFA_Node* GetTransparentParent();
+
+  Optional<float> TryHeight();
+  Optional<float> TryMinWidth();
+  Optional<float> TryMinHeight();
+  Optional<float> TryMaxWidth();
+  Optional<float> TryMaxHeight();
+  XFA_EventError ProcessEventInternal(CXFA_FFDocView* pDocView,
+                                      XFA_AttributeValue iActivity,
+                                      CXFA_Event* event,
+                                      CXFA_EventParam* pEventParam);
+
+  CFX_XMLDocument* GetXMLDocument() const;
+
+  const pdfium::span<const PropertyData> m_Properties;
+  const pdfium::span<const AttributeData> m_Attributes;
   const uint32_t m_ValidPackets;
-  CXFA_Node* m_pNext;
-  CXFA_Node* m_pChild;
-  CXFA_Node* m_pLastChild;
-  CXFA_Node* m_pParent;
-  CFX_XMLNode* m_pXMLNode;
+  UnownedPtr<CFX_XMLNode> xml_node_;
   const XFA_PacketType m_ePacket;
   uint8_t m_ExecuteRecursionDepth = 0;
-  uint16_t m_uNodeFlags;
-  uint32_t m_dwNameHash;
-  CXFA_Node* m_pAuxNode;
-  std::vector<UnownedPtr<CXFA_Node>> binding_nodes_;
+  uint16_t m_uNodeFlags = XFA_NodeFlag_None;
+  uint32_t m_dwNameHash = 0;
+  CXFA_Node* m_pAuxNode = nullptr;         // Raw, node tree cleanup order.
+  std::vector<CXFA_Node*> binding_nodes_;  // Raw, node tree cleanup order.
+  bool m_bIsNull = true;
+  bool m_bPreNull = true;
+  bool is_widget_ready_ = false;
+  std::unique_ptr<CXFA_WidgetLayoutData> m_pLayoutData;
+  CXFA_Ui* ui_ = nullptr;
+  XFA_FFWidgetType ff_widget_type_ = XFA_FFWidgetType::kNone;
 };
 
 #endif  // XFA_FXFA_PARSER_CXFA_NODE_H_
diff --git a/xfa/fxfa/parser/cxfa_node_statics.cpp b/xfa/fxfa/parser/cxfa_node_statics.cpp
deleted file mode 100644
index 93860c6..0000000
--- a/xfa/fxfa/parser/cxfa_node_statics.cpp
+++ /dev/null
@@ -1,2948 +0,0 @@
-// 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
-
-#include <memory>
-
-#include "third_party/base/ptr_util.h"
-#include "xfa/fxfa/parser/cxfa_accessiblecontent.h"
-#include "xfa/fxfa/parser/cxfa_acrobat.h"
-#include "xfa/fxfa/parser/cxfa_acrobat7.h"
-#include "xfa/fxfa/parser/cxfa_adbe_jsconsole.h"
-#include "xfa/fxfa/parser/cxfa_adbe_jsdebugger.h"
-#include "xfa/fxfa/parser/cxfa_addsilentprint.h"
-#include "xfa/fxfa/parser/cxfa_addviewerpreferences.h"
-#include "xfa/fxfa/parser/cxfa_adjustdata.h"
-#include "xfa/fxfa/parser/cxfa_adobeextensionlevel.h"
-#include "xfa/fxfa/parser/cxfa_agent.h"
-#include "xfa/fxfa/parser/cxfa_alwaysembed.h"
-#include "xfa/fxfa/parser/cxfa_amd.h"
-#include "xfa/fxfa/parser/cxfa_appearancefilter.h"
-#include "xfa/fxfa/parser/cxfa_arc.h"
-#include "xfa/fxfa/parser/cxfa_area.h"
-#include "xfa/fxfa/parser/cxfa_assist.h"
-#include "xfa/fxfa/parser/cxfa_attributes.h"
-#include "xfa/fxfa/parser/cxfa_autosave.h"
-#include "xfa/fxfa/parser/cxfa_barcode.h"
-#include "xfa/fxfa/parser/cxfa_base.h"
-#include "xfa/fxfa/parser/cxfa_batchoutput.h"
-#include "xfa/fxfa/parser/cxfa_behavioroverride.h"
-#include "xfa/fxfa/parser/cxfa_bind.h"
-#include "xfa/fxfa/parser/cxfa_binditems.h"
-#include "xfa/fxfa/parser/cxfa_bookend.h"
-#include "xfa/fxfa/parser/cxfa_boolean.h"
-#include "xfa/fxfa/parser/cxfa_border.h"
-#include "xfa/fxfa/parser/cxfa_break.h"
-#include "xfa/fxfa/parser/cxfa_breakafter.h"
-#include "xfa/fxfa/parser/cxfa_breakbefore.h"
-#include "xfa/fxfa/parser/cxfa_button.h"
-#include "xfa/fxfa/parser/cxfa_cache.h"
-#include "xfa/fxfa/parser/cxfa_calculate.h"
-#include "xfa/fxfa/parser/cxfa_calendarsymbols.h"
-#include "xfa/fxfa/parser/cxfa_caption.h"
-#include "xfa/fxfa/parser/cxfa_certificate.h"
-#include "xfa/fxfa/parser/cxfa_certificates.h"
-#include "xfa/fxfa/parser/cxfa_change.h"
-#include "xfa/fxfa/parser/cxfa_checkbutton.h"
-#include "xfa/fxfa/parser/cxfa_choicelist.h"
-#include "xfa/fxfa/parser/cxfa_color.h"
-#include "xfa/fxfa/parser/cxfa_comb.h"
-#include "xfa/fxfa/parser/cxfa_command.h"
-#include "xfa/fxfa/parser/cxfa_common.h"
-#include "xfa/fxfa/parser/cxfa_compress.h"
-#include "xfa/fxfa/parser/cxfa_compression.h"
-#include "xfa/fxfa/parser/cxfa_compresslogicalstructure.h"
-#include "xfa/fxfa/parser/cxfa_compressobjectstream.h"
-#include "xfa/fxfa/parser/cxfa_config.h"
-#include "xfa/fxfa/parser/cxfa_conformance.h"
-#include "xfa/fxfa/parser/cxfa_connect.h"
-#include "xfa/fxfa/parser/cxfa_connectionset.h"
-#include "xfa/fxfa/parser/cxfa_connectstring.h"
-#include "xfa/fxfa/parser/cxfa_contentarea.h"
-#include "xfa/fxfa/parser/cxfa_contentcopy.h"
-#include "xfa/fxfa/parser/cxfa_copies.h"
-#include "xfa/fxfa/parser/cxfa_corner.h"
-#include "xfa/fxfa/parser/cxfa_creator.h"
-#include "xfa/fxfa/parser/cxfa_currencysymbol.h"
-#include "xfa/fxfa/parser/cxfa_currencysymbols.h"
-#include "xfa/fxfa/parser/cxfa_currentpage.h"
-#include "xfa/fxfa/parser/cxfa_data.h"
-#include "xfa/fxfa/parser/cxfa_datagroup.h"
-#include "xfa/fxfa/parser/cxfa_datamodel.h"
-#include "xfa/fxfa/parser/cxfa_datavalue.h"
-#include "xfa/fxfa/parser/cxfa_date.h"
-#include "xfa/fxfa/parser/cxfa_datepattern.h"
-#include "xfa/fxfa/parser/cxfa_datepatterns.h"
-#include "xfa/fxfa/parser/cxfa_datetime.h"
-#include "xfa/fxfa/parser/cxfa_datetimeedit.h"
-#include "xfa/fxfa/parser/cxfa_datetimesymbols.h"
-#include "xfa/fxfa/parser/cxfa_day.h"
-#include "xfa/fxfa/parser/cxfa_daynames.h"
-#include "xfa/fxfa/parser/cxfa_debug.h"
-#include "xfa/fxfa/parser/cxfa_decimal.h"
-#include "xfa/fxfa/parser/cxfa_defaulttypeface.h"
-#include "xfa/fxfa/parser/cxfa_defaultui.h"
-#include "xfa/fxfa/parser/cxfa_delete.h"
-#include "xfa/fxfa/parser/cxfa_delta.h"
-#include "xfa/fxfa/parser/cxfa_deltas.h"
-#include "xfa/fxfa/parser/cxfa_desc.h"
-#include "xfa/fxfa/parser/cxfa_destination.h"
-#include "xfa/fxfa/parser/cxfa_digestmethod.h"
-#include "xfa/fxfa/parser/cxfa_digestmethods.h"
-#include "xfa/fxfa/parser/cxfa_documentassembly.h"
-#include "xfa/fxfa/parser/cxfa_draw.h"
-#include "xfa/fxfa/parser/cxfa_driver.h"
-#include "xfa/fxfa/parser/cxfa_dsigdata.h"
-#include "xfa/fxfa/parser/cxfa_duplexoption.h"
-#include "xfa/fxfa/parser/cxfa_dynamicrender.h"
-#include "xfa/fxfa/parser/cxfa_edge.h"
-#include "xfa/fxfa/parser/cxfa_effectiveinputpolicy.h"
-#include "xfa/fxfa/parser/cxfa_effectiveoutputpolicy.h"
-#include "xfa/fxfa/parser/cxfa_embed.h"
-#include "xfa/fxfa/parser/cxfa_encoding.h"
-#include "xfa/fxfa/parser/cxfa_encodings.h"
-#include "xfa/fxfa/parser/cxfa_encrypt.h"
-#include "xfa/fxfa/parser/cxfa_encryption.h"
-#include "xfa/fxfa/parser/cxfa_encryptionlevel.h"
-#include "xfa/fxfa/parser/cxfa_encryptionmethod.h"
-#include "xfa/fxfa/parser/cxfa_encryptionmethods.h"
-#include "xfa/fxfa/parser/cxfa_enforce.h"
-#include "xfa/fxfa/parser/cxfa_equate.h"
-#include "xfa/fxfa/parser/cxfa_equaterange.h"
-#include "xfa/fxfa/parser/cxfa_era.h"
-#include "xfa/fxfa/parser/cxfa_eranames.h"
-#include "xfa/fxfa/parser/cxfa_event.h"
-#include "xfa/fxfa/parser/cxfa_exclgroup.h"
-#include "xfa/fxfa/parser/cxfa_exclude.h"
-#include "xfa/fxfa/parser/cxfa_excludens.h"
-#include "xfa/fxfa/parser/cxfa_exdata.h"
-#include "xfa/fxfa/parser/cxfa_execute.h"
-#include "xfa/fxfa/parser/cxfa_exobject.h"
-#include "xfa/fxfa/parser/cxfa_extras.h"
-#include "xfa/fxfa/parser/cxfa_field.h"
-#include "xfa/fxfa/parser/cxfa_fill.h"
-#include "xfa/fxfa/parser/cxfa_filter.h"
-#include "xfa/fxfa/parser/cxfa_fliplabel.h"
-#include "xfa/fxfa/parser/cxfa_float.h"
-#include "xfa/fxfa/parser/cxfa_font.h"
-#include "xfa/fxfa/parser/cxfa_fontinfo.h"
-#include "xfa/fxfa/parser/cxfa_form.h"
-#include "xfa/fxfa/parser/cxfa_format.h"
-#include "xfa/fxfa/parser/cxfa_formfieldfilling.h"
-#include "xfa/fxfa/parser/cxfa_groupparent.h"
-#include "xfa/fxfa/parser/cxfa_handler.h"
-#include "xfa/fxfa/parser/cxfa_hyphenation.h"
-#include "xfa/fxfa/parser/cxfa_ifempty.h"
-#include "xfa/fxfa/parser/cxfa_image.h"
-#include "xfa/fxfa/parser/cxfa_imageedit.h"
-#include "xfa/fxfa/parser/cxfa_includexdpcontent.h"
-#include "xfa/fxfa/parser/cxfa_incrementalload.h"
-#include "xfa/fxfa/parser/cxfa_incrementalmerge.h"
-#include "xfa/fxfa/parser/cxfa_insert.h"
-#include "xfa/fxfa/parser/cxfa_instancemanager.h"
-#include "xfa/fxfa/parser/cxfa_integer.h"
-#include "xfa/fxfa/parser/cxfa_interactive.h"
-#include "xfa/fxfa/parser/cxfa_issuers.h"
-#include "xfa/fxfa/parser/cxfa_items.h"
-#include "xfa/fxfa/parser/cxfa_jog.h"
-#include "xfa/fxfa/parser/cxfa_keep.h"
-#include "xfa/fxfa/parser/cxfa_keyusage.h"
-#include "xfa/fxfa/parser/cxfa_labelprinter.h"
-#include "xfa/fxfa/parser/cxfa_layout.h"
-#include "xfa/fxfa/parser/cxfa_level.h"
-#include "xfa/fxfa/parser/cxfa_line.h"
-#include "xfa/fxfa/parser/cxfa_linear.h"
-#include "xfa/fxfa/parser/cxfa_linearized.h"
-#include "xfa/fxfa/parser/cxfa_locale.h"
-#include "xfa/fxfa/parser/cxfa_localeset.h"
-#include "xfa/fxfa/parser/cxfa_lockdocument.h"
-#include "xfa/fxfa/parser/cxfa_log.h"
-#include "xfa/fxfa/parser/cxfa_manifest.h"
-#include "xfa/fxfa/parser/cxfa_map.h"
-#include "xfa/fxfa/parser/cxfa_margin.h"
-#include "xfa/fxfa/parser/cxfa_mdp.h"
-#include "xfa/fxfa/parser/cxfa_medium.h"
-#include "xfa/fxfa/parser/cxfa_mediuminfo.h"
-#include "xfa/fxfa/parser/cxfa_meridiem.h"
-#include "xfa/fxfa/parser/cxfa_meridiemnames.h"
-#include "xfa/fxfa/parser/cxfa_message.h"
-#include "xfa/fxfa/parser/cxfa_messaging.h"
-#include "xfa/fxfa/parser/cxfa_mode.h"
-#include "xfa/fxfa/parser/cxfa_modifyannots.h"
-#include "xfa/fxfa/parser/cxfa_month.h"
-#include "xfa/fxfa/parser/cxfa_monthnames.h"
-#include "xfa/fxfa/parser/cxfa_msgid.h"
-#include "xfa/fxfa/parser/cxfa_nameattr.h"
-#include "xfa/fxfa/parser/cxfa_neverembed.h"
-#include "xfa/fxfa/parser/cxfa_node.h"
-#include "xfa/fxfa/parser/cxfa_numberofcopies.h"
-#include "xfa/fxfa/parser/cxfa_numberpattern.h"
-#include "xfa/fxfa/parser/cxfa_numberpatterns.h"
-#include "xfa/fxfa/parser/cxfa_numbersymbol.h"
-#include "xfa/fxfa/parser/cxfa_numbersymbols.h"
-#include "xfa/fxfa/parser/cxfa_numericedit.h"
-#include "xfa/fxfa/parser/cxfa_occur.h"
-#include "xfa/fxfa/parser/cxfa_oid.h"
-#include "xfa/fxfa/parser/cxfa_oids.h"
-#include "xfa/fxfa/parser/cxfa_openaction.h"
-#include "xfa/fxfa/parser/cxfa_operation.h"
-#include "xfa/fxfa/parser/cxfa_output.h"
-#include "xfa/fxfa/parser/cxfa_outputbin.h"
-#include "xfa/fxfa/parser/cxfa_outputxsl.h"
-#include "xfa/fxfa/parser/cxfa_overflow.h"
-#include "xfa/fxfa/parser/cxfa_overprint.h"
-#include "xfa/fxfa/parser/cxfa_packet.h"
-#include "xfa/fxfa/parser/cxfa_packets.h"
-#include "xfa/fxfa/parser/cxfa_pagearea.h"
-#include "xfa/fxfa/parser/cxfa_pageoffset.h"
-#include "xfa/fxfa/parser/cxfa_pagerange.h"
-#include "xfa/fxfa/parser/cxfa_pageset.h"
-#include "xfa/fxfa/parser/cxfa_pagination.h"
-#include "xfa/fxfa/parser/cxfa_paginationoverride.h"
-#include "xfa/fxfa/parser/cxfa_para.h"
-#include "xfa/fxfa/parser/cxfa_part.h"
-#include "xfa/fxfa/parser/cxfa_password.h"
-#include "xfa/fxfa/parser/cxfa_passwordedit.h"
-#include "xfa/fxfa/parser/cxfa_pattern.h"
-#include "xfa/fxfa/parser/cxfa_pcl.h"
-#include "xfa/fxfa/parser/cxfa_pdf.h"
-#include "xfa/fxfa/parser/cxfa_pdfa.h"
-#include "xfa/fxfa/parser/cxfa_permissions.h"
-#include "xfa/fxfa/parser/cxfa_picktraybypdfsize.h"
-#include "xfa/fxfa/parser/cxfa_picture.h"
-#include "xfa/fxfa/parser/cxfa_plaintextmetadata.h"
-#include "xfa/fxfa/parser/cxfa_presence.h"
-#include "xfa/fxfa/parser/cxfa_present.h"
-#include "xfa/fxfa/parser/cxfa_print.h"
-#include "xfa/fxfa/parser/cxfa_printername.h"
-#include "xfa/fxfa/parser/cxfa_printhighquality.h"
-#include "xfa/fxfa/parser/cxfa_printscaling.h"
-#include "xfa/fxfa/parser/cxfa_producer.h"
-#include "xfa/fxfa/parser/cxfa_proto.h"
-#include "xfa/fxfa/parser/cxfa_ps.h"
-#include "xfa/fxfa/parser/cxfa_psmap.h"
-#include "xfa/fxfa/parser/cxfa_query.h"
-#include "xfa/fxfa/parser/cxfa_radial.h"
-#include "xfa/fxfa/parser/cxfa_range.h"
-#include "xfa/fxfa/parser/cxfa_reason.h"
-#include "xfa/fxfa/parser/cxfa_reasons.h"
-#include "xfa/fxfa/parser/cxfa_record.h"
-#include "xfa/fxfa/parser/cxfa_recordset.h"
-#include "xfa/fxfa/parser/cxfa_rectangle.h"
-#include "xfa/fxfa/parser/cxfa_ref.h"
-#include "xfa/fxfa/parser/cxfa_relevant.h"
-#include "xfa/fxfa/parser/cxfa_rename.h"
-#include "xfa/fxfa/parser/cxfa_renderpolicy.h"
-#include "xfa/fxfa/parser/cxfa_rootelement.h"
-#include "xfa/fxfa/parser/cxfa_runscripts.h"
-#include "xfa/fxfa/parser/cxfa_script.h"
-#include "xfa/fxfa/parser/cxfa_scriptmodel.h"
-#include "xfa/fxfa/parser/cxfa_select.h"
-#include "xfa/fxfa/parser/cxfa_setproperty.h"
-#include "xfa/fxfa/parser/cxfa_severity.h"
-#include "xfa/fxfa/parser/cxfa_sharptext.h"
-#include "xfa/fxfa/parser/cxfa_sharpxhtml.h"
-#include "xfa/fxfa/parser/cxfa_sharpxml.h"
-#include "xfa/fxfa/parser/cxfa_signature.h"
-#include "xfa/fxfa/parser/cxfa_signatureproperties.h"
-#include "xfa/fxfa/parser/cxfa_signdata.h"
-#include "xfa/fxfa/parser/cxfa_signing.h"
-#include "xfa/fxfa/parser/cxfa_silentprint.h"
-#include "xfa/fxfa/parser/cxfa_soapaction.h"
-#include "xfa/fxfa/parser/cxfa_soapaddress.h"
-#include "xfa/fxfa/parser/cxfa_solid.h"
-#include "xfa/fxfa/parser/cxfa_source.h"
-#include "xfa/fxfa/parser/cxfa_sourceset.h"
-#include "xfa/fxfa/parser/cxfa_speak.h"
-#include "xfa/fxfa/parser/cxfa_staple.h"
-#include "xfa/fxfa/parser/cxfa_startnode.h"
-#include "xfa/fxfa/parser/cxfa_startpage.h"
-#include "xfa/fxfa/parser/cxfa_stipple.h"
-#include "xfa/fxfa/parser/cxfa_subform.h"
-#include "xfa/fxfa/parser/cxfa_subformset.h"
-#include "xfa/fxfa/parser/cxfa_subjectdn.h"
-#include "xfa/fxfa/parser/cxfa_subjectdns.h"
-#include "xfa/fxfa/parser/cxfa_submit.h"
-#include "xfa/fxfa/parser/cxfa_submitformat.h"
-#include "xfa/fxfa/parser/cxfa_submiturl.h"
-#include "xfa/fxfa/parser/cxfa_subsetbelow.h"
-#include "xfa/fxfa/parser/cxfa_suppressbanner.h"
-#include "xfa/fxfa/parser/cxfa_tagged.h"
-#include "xfa/fxfa/parser/cxfa_template.h"
-#include "xfa/fxfa/parser/cxfa_templatecache.h"
-#include "xfa/fxfa/parser/cxfa_text.h"
-#include "xfa/fxfa/parser/cxfa_textedit.h"
-#include "xfa/fxfa/parser/cxfa_threshold.h"
-#include "xfa/fxfa/parser/cxfa_time.h"
-#include "xfa/fxfa/parser/cxfa_timepattern.h"
-#include "xfa/fxfa/parser/cxfa_timepatterns.h"
-#include "xfa/fxfa/parser/cxfa_timestamp.h"
-#include "xfa/fxfa/parser/cxfa_to.h"
-#include "xfa/fxfa/parser/cxfa_tooltip.h"
-#include "xfa/fxfa/parser/cxfa_trace.h"
-#include "xfa/fxfa/parser/cxfa_transform.h"
-#include "xfa/fxfa/parser/cxfa_traversal.h"
-#include "xfa/fxfa/parser/cxfa_traverse.h"
-#include "xfa/fxfa/parser/cxfa_type.h"
-#include "xfa/fxfa/parser/cxfa_typeface.h"
-#include "xfa/fxfa/parser/cxfa_typefaces.h"
-#include "xfa/fxfa/parser/cxfa_ui.h"
-#include "xfa/fxfa/parser/cxfa_update.h"
-#include "xfa/fxfa/parser/cxfa_uri.h"
-#include "xfa/fxfa/parser/cxfa_user.h"
-#include "xfa/fxfa/parser/cxfa_validate.h"
-#include "xfa/fxfa/parser/cxfa_validateapprovalsignatures.h"
-#include "xfa/fxfa/parser/cxfa_validationmessaging.h"
-#include "xfa/fxfa/parser/cxfa_value.h"
-#include "xfa/fxfa/parser/cxfa_variables.h"
-#include "xfa/fxfa/parser/cxfa_version.h"
-#include "xfa/fxfa/parser/cxfa_versioncontrol.h"
-#include "xfa/fxfa/parser/cxfa_viewerpreferences.h"
-#include "xfa/fxfa/parser/cxfa_webclient.h"
-#include "xfa/fxfa/parser/cxfa_whitespace.h"
-#include "xfa/fxfa/parser/cxfa_window.h"
-#include "xfa/fxfa/parser/cxfa_wsdladdress.h"
-#include "xfa/fxfa/parser/cxfa_wsdlconnection.h"
-#include "xfa/fxfa/parser/cxfa_xdc.h"
-#include "xfa/fxfa/parser/cxfa_xdp.h"
-#include "xfa/fxfa/parser/cxfa_xfa.h"
-#include "xfa/fxfa/parser/cxfa_xmlconnection.h"
-#include "xfa/fxfa/parser/cxfa_xsdconnection.h"
-#include "xfa/fxfa/parser/cxfa_xsl.h"
-#include "xfa/fxfa/parser/cxfa_zpl.h"
-
-namespace {
-
-struct ElementNameInfo {
-  uint32_t hash;
-  XFA_Element element;
-} ElementNameToEnum[] = {
-    {0x23ee3 /* ps */, XFA_Element::Ps},
-    {0x25363 /* to */, XFA_Element::To},
-    {0x2587e /* ui */, XFA_Element::Ui},
-    {0x1c648b /* recordSet */, XFA_Element::RecordSet},
-    {0x171428f /* subsetBelow */, XFA_Element::SubsetBelow},
-    {0x1a0776a /* subformSet */, XFA_Element::SubformSet},
-    {0x2340d70 /* adobeExtensionLevel */, XFA_Element::AdobeExtensionLevel},
-    {0x2c1c7f1 /* typeface */, XFA_Element::Typeface},
-    {0x5518c25 /* break */, XFA_Element::Break},
-    {0x5fff523 /* fontInfo */, XFA_Element::FontInfo},
-    {0x653a227 /* numberPattern */, XFA_Element::NumberPattern},
-    {0x65b4a05 /* dynamicRender */, XFA_Element::DynamicRender},
-    {0x7e4362e /* printScaling */, XFA_Element::PrintScaling},
-    {0x7fe6d3a /* checkButton */, XFA_Element::CheckButton},
-    {0x80cf58f /* datePatterns */, XFA_Element::DatePatterns},
-    {0x811929d /* sourceSet */, XFA_Element::SourceSet},
-    {0x9f9d612 /* amd */, XFA_Element::Amd},
-    {0x9f9efb6 /* arc */, XFA_Element::Arc},
-    {0xa48835e /* day */, XFA_Element::Day},
-    {0xa6328b8 /* era */, XFA_Element::Era},
-    {0xae6a0a0 /* jog */, XFA_Element::Jog},
-    {0xb1b3d22 /* log */, XFA_Element::Log},
-    {0xb35439e /* map */, XFA_Element::Map},
-    {0xb355301 /* mdp */, XFA_Element::Mdp},
-    {0xb420438 /* breakBefore */, XFA_Element::BreakBefore},
-    {0xb6a091c /* oid */, XFA_Element::Oid},
-    {0xb84389f /* pcl */, XFA_Element::Pcl},
-    {0xb843dba /* pdf */, XFA_Element::Pdf},
-    {0xbb8df5d /* ref */, XFA_Element::Ref},
-    {0xc080cd0 /* uri */, XFA_Element::Uri},
-    {0xc56afbf /* xdc */, XFA_Element::Xdc},
-    {0xc56afcc /* xdp */, XFA_Element::Xdp},
-    {0xc56b9ff /* xfa */, XFA_Element::Xfa},
-    {0xc56fcb7 /* xsl */, XFA_Element::Xsl},
-    {0xc8b89d6 /* zpl */, XFA_Element::Zpl},
-    {0xc9bae94 /* cache */, XFA_Element::Cache},
-    {0xcb016be /* margin */, XFA_Element::Margin},
-    {0xe1378fe /* keyUsage */, XFA_Element::KeyUsage},
-    {0xfe3596a /* exclude */, XFA_Element::Exclude},
-    {0x10395ac7 /* choiceList */, XFA_Element::ChoiceList},
-    {0x1059ec18 /* level */, XFA_Element::Level},
-    {0x10874804 /* labelPrinter */, XFA_Element::LabelPrinter},
-    {0x10c40e03 /* calendarSymbols */, XFA_Element::CalendarSymbols},
-    {0x10f1ea24 /* para */, XFA_Element::Para},
-    {0x10f1ea37 /* part */, XFA_Element::Part},
-    {0x1140975b /* pdfa */, XFA_Element::Pdfa},
-    {0x1154efe6 /* filter */, XFA_Element::Filter},
-    {0x13f41de1 /* present */, XFA_Element::Present},
-    {0x1827e6ea /* pagination */, XFA_Element::Pagination},
-    {0x18463707 /* encoding */, XFA_Element::Encoding},
-    {0x185e41e2 /* event */, XFA_Element::Event},
-    {0x1adb142d /* whitespace */, XFA_Element::Whitespace},
-    {0x1f3f64c3 /* defaultUi */, XFA_Element::DefaultUi},
-    {0x204e87cb /* dataModel */, XFA_Element::DataModel},
-    {0x2057b350 /* barcode */, XFA_Element::Barcode},
-    {0x20596bad /* timePattern */, XFA_Element::TimePattern},
-    {0x210b74d3 /* batchOutput */, XFA_Element::BatchOutput},
-    {0x212ff0e2 /* enforce */, XFA_Element::Enforce},
-    {0x21d351b4 /* currencySymbols */, XFA_Element::CurrencySymbols},
-    {0x21db83c5 /* addSilentPrint */, XFA_Element::AddSilentPrint},
-    {0x22266258 /* rename */, XFA_Element::Rename},
-    {0x226ca8f1 /* operation */, XFA_Element::Operation},
-    {0x23e27b84 /* typefaces */, XFA_Element::Typefaces},
-    {0x23f4aa75 /* subjectDNs */, XFA_Element::SubjectDNs},
-    {0x240d5e8e /* issuers */, XFA_Element::Issuers},
-    {0x24a52f8a /* wsdlConnection */, XFA_Element::WsdlConnection},
-    {0x254ebd07 /* debug */, XFA_Element::Debug},
-    {0x2655c66a /* delta */, XFA_Element::Delta},
-    {0x26c0daec /* eraNames */, XFA_Element::EraNames},
-    {0x273ab03b /* modifyAnnots */, XFA_Element::ModifyAnnots},
-    {0x27875bb4 /* startNode */, XFA_Element::StartNode},
-    {0x285d0dbc /* button */, XFA_Element::Button},
-    {0x28dee6e9 /* format */, XFA_Element::Format},
-    {0x2a23349e /* border */, XFA_Element::Border},
-    {0x2ae67f19 /* area */, XFA_Element::Area},
-    {0x2c3c4c67 /* hyphenation */, XFA_Element::Hyphenation},
-    {0x2d08af85 /* text */, XFA_Element::Text},
-    {0x2d71b00f /* time */, XFA_Element::Time},
-    {0x2f16a382 /* type */, XFA_Element::Type},
-    {0x2fe057e9 /* overprint */, XFA_Element::Overprint},
-    {0x302aee16 /* certificates */, XFA_Element::Certificates},
-    {0x30b227df /* encryptionMethods */, XFA_Element::EncryptionMethods},
-    {0x32b900d1 /* setProperty */, XFA_Element::SetProperty},
-    {0x337d9e45 /* printerName */, XFA_Element::PrinterName},
-    {0x33edda4b /* startPage */, XFA_Element::StartPage},
-    {0x381943e4 /* pageOffset */, XFA_Element::PageOffset},
-    {0x382106cd /* dateTime */, XFA_Element::DateTime},
-    {0x386e7421 /* comb */, XFA_Element::Comb},
-    {0x390acd9e /* pattern */, XFA_Element::Pattern},
-    {0x3942163e /* ifEmpty */, XFA_Element::IfEmpty},
-    {0x39944a7b /* suppressBanner */, XFA_Element::SuppressBanner},
-    {0x3b3c3dca /* outputBin */, XFA_Element::OutputBin},
-    {0x3b8a4024 /* field */, XFA_Element::Field},
-    {0x3c15352f /* agent */, XFA_Element::Agent},
-    {0x3d7e8668 /* outputXSL */, XFA_Element::OutputXSL},
-    {0x3e1c91c5 /* adjustData */, XFA_Element::AdjustData},
-    {0x3e7a9408 /* autoSave */, XFA_Element::AutoSave},
-    {0x3ecead94 /* contentArea */, XFA_Element::ContentArea},
-    {0x3fadaec0 /* wsdlAddress */, XFA_Element::WsdlAddress},
-    {0x40623b5b /* solid */, XFA_Element::Solid},
-    {0x41f0bd76 /* dateTimeSymbols */, XFA_Element::DateTimeSymbols},
-    {0x444e7523 /* encryptionLevel */, XFA_Element::EncryptionLevel},
-    {0x4523af55 /* edge */, XFA_Element::Edge},
-    {0x45d5e3c1 /* stipple */, XFA_Element::Stipple},
-    {0x475e4e87 /* attributes */, XFA_Element::Attributes},
-    {0x487a8c87 /* versionControl */, XFA_Element::VersionControl},
-    {0x48e5248c /* meridiem */, XFA_Element::Meridiem},
-    {0x48f36719 /* exclGroup */, XFA_Element::ExclGroup},
-    {0x4977356b /* toolTip */, XFA_Element::ToolTip},
-    {0x499afecc /* compress */, XFA_Element::Compress},
-    {0x4a0c4948 /* reason */, XFA_Element::Reason},
-    {0x4bdcce13 /* execute */, XFA_Element::Execute},
-    {0x4c56b216 /* contentCopy */, XFA_Element::ContentCopy},
-    {0x4cc176d3 /* dateTimeEdit */, XFA_Element::DateTimeEdit},
-    {0x4e1e39b6 /* config */, XFA_Element::Config},
-    {0x4e2d6083 /* image */, XFA_Element::Image},
-    {0x4e814150 /* #xHTML */, XFA_Element::SharpxHTML},
-    {0x4f2388c1 /* numberOfCopies */, XFA_Element::NumberOfCopies},
-    {0x4f512e30 /* behaviorOverride */, XFA_Element::BehaviorOverride},
-    {0x4fdc3454 /* timeStamp */, XFA_Element::TimeStamp},
-    {0x51d90546 /* month */, XFA_Element::Month},
-    {0x523437e4 /* viewerPreferences */, XFA_Element::ViewerPreferences},
-    {0x53abc1c6 /* scriptModel */, XFA_Element::ScriptModel},
-    {0x54034c2f /* decimal */, XFA_Element::Decimal},
-    {0x54202c9e /* subform */, XFA_Element::Subform},
-    {0x542c7300 /* select */, XFA_Element::Select},
-    {0x5436d198 /* window */, XFA_Element::Window},
-    {0x5473b6dc /* localeSet */, XFA_Element::LocaleSet},
-    {0x56ae179e /* handler */, XFA_Element::Handler},
-    {0x570ce835 /* presence */, XFA_Element::Presence},
-    {0x5779d65f /* record */, XFA_Element::Record},
-    {0x59c8f27d /* embed */, XFA_Element::Embed},
-    {0x5a50e9e6 /* version */, XFA_Element::Version},
-    {0x5b8383df /* command */, XFA_Element::Command},
-    {0x5c43c6c3 /* copies */, XFA_Element::Copies},
-    {0x5e0c2c49 /* staple */, XFA_Element::Staple},
-    {0x5e5083dd /* submitFormat */, XFA_Element::SubmitFormat},
-    {0x5e8c5d20 /* boolean */, XFA_Element::Boolean},
-    {0x60490a85 /* message */, XFA_Element::Message},
-    {0x60d4c8b1 /* output */, XFA_Element::Output},
-    {0x61810081 /* psMap */, XFA_Element::PsMap},
-    {0x62bd904b /* excludeNS */, XFA_Element::ExcludeNS},
-    {0x669d4f77 /* assist */, XFA_Element::Assist},
-    {0x67334a1c /* picture */, XFA_Element::Picture},
-    {0x67fe7334 /* traversal */, XFA_Element::Traversal},
-    {0x6894589c /* silentPrint */, XFA_Element::SilentPrint},
-    {0x68a16bbd /* webClient */, XFA_Element::WebClient},
-    {0x6a4bc084 /* producer */, XFA_Element::Producer},
-    {0x6a9e04c9 /* corner */, XFA_Element::Corner},
-    {0x6ccd7274 /* msgId */, XFA_Element::MsgId},
-    {0x6e67921f /* color */, XFA_Element::Color},
-    {0x6ec217a5 /* keep */, XFA_Element::Keep},
-    {0x6eef1116 /* query */, XFA_Element::Query},
-    {0x7033bfd5 /* insert */, XFA_Element::Insert},
-    {0x704af389 /* imageEdit */, XFA_Element::ImageEdit},
-    {0x7233018a /* validate */, XFA_Element::Validate},
-    {0x72ba47b4 /* digestMethods */, XFA_Element::DigestMethods},
-    {0x72f2aa7a /* numberPatterns */, XFA_Element::NumberPatterns},
-    {0x74caed29 /* pageSet */, XFA_Element::PageSet},
-    {0x7568e6ae /* integer */, XFA_Element::Integer},
-    {0x76182db9 /* soapAddress */, XFA_Element::SoapAddress},
-    {0x773146c5 /* equate */, XFA_Element::Equate},
-    {0x77d449dd /* formFieldFilling */, XFA_Element::FormFieldFilling},
-    {0x7889d68a /* pageRange */, XFA_Element::PageRange},
-    {0x7baca2e3 /* update */, XFA_Element::Update},
-    {0x7ce89001 /* connectString */, XFA_Element::ConnectString},
-    {0x7d9fd7c5 /* mode */, XFA_Element::Mode},
-    {0x7e7e845e /* layout */, XFA_Element::Layout},
-    {0x7e845c34 /* #xml */, XFA_Element::Sharpxml},
-    {0x7fb341df /* xsdConnection */, XFA_Element::XsdConnection},
-    {0x7ffb51cc /* traverse */, XFA_Element::Traverse},
-    {0x80203b5a /* encodings */, XFA_Element::Encodings},
-    {0x803550fc /* template */, XFA_Element::Template},
-    {0x803d5bbc /* acrobat */, XFA_Element::Acrobat},
-    {0x821d6569 /* validationMessaging */, XFA_Element::ValidationMessaging},
-    {0x830e688f /* signing */, XFA_Element::Signing},
-    {0x83dab9f5 /* script */, XFA_Element::Script},
-    {0x8411ebcd /* addViewerPreferences */, XFA_Element::AddViewerPreferences},
-    {0x8777642e /* alwaysEmbed */, XFA_Element::AlwaysEmbed},
-    {0x877a6b39 /* passwordEdit */, XFA_Element::PasswordEdit},
-    {0x87e84c99 /* numericEdit */, XFA_Element::NumericEdit},
-    {0x8852cdec /* encryptionMethod */, XFA_Element::EncryptionMethod},
-    {0x891f4606 /* change */, XFA_Element::Change},
-    {0x89939f36 /* pageArea */, XFA_Element::PageArea},
-    {0x8a9d6247 /* submitUrl */, XFA_Element::SubmitUrl},
-    {0x8ad8b90f /* oids */, XFA_Element::Oids},
-    {0x8b036f32 /* signature */, XFA_Element::Signature},
-    {0x8b128efb /* ADBE_JSConsole */, XFA_Element::ADBE_JSConsole},
-    {0x8bcfe96e /* caption */, XFA_Element::Caption},
-    {0x8e1c2921 /* relevant */, XFA_Element::Relevant},
-    {0x8e3f0a4b /* flipLabel */, XFA_Element::FlipLabel},
-    {0x900280b7 /* exData */, XFA_Element::ExData},
-    {0x91e80352 /* dayNames */, XFA_Element::DayNames},
-    {0x93113b11 /* soapAction */, XFA_Element::SoapAction},
-    {0x938b09f6 /* defaultTypeface */, XFA_Element::DefaultTypeface},
-    {0x95b37897 /* manifest */, XFA_Element::Manifest},
-    {0x97b76b54 /* overflow */, XFA_Element::Overflow},
-    {0x9a57861b /* linear */, XFA_Element::Linear},
-    {0x9ad5a821 /* currencySymbol */, XFA_Element::CurrencySymbol},
-    {0x9c6471b3 /* delete */, XFA_Element::Delete},
-    {0x9deea61d /* deltas */, XFA_Element::Deltas},
-    {0x9e67de21 /* digestMethod */, XFA_Element::DigestMethod},
-    {0x9f3e9510 /* instanceManager */, XFA_Element::InstanceManager},
-    {0xa0799892 /* equateRange */, XFA_Element::EquateRange},
-    {0xa084a381 /* medium */, XFA_Element::Medium},
-    {0xa1211b8b /* textEdit */, XFA_Element::TextEdit},
-    {0xa17008f0 /* templateCache */, XFA_Element::TemplateCache},
-    {0xa4f7b88f /* compressObjectStream */, XFA_Element::CompressObjectStream},
-    {0xa65f5d17 /* dataValue */, XFA_Element::DataValue},
-    {0xa6caaa89 /* accessibleContent */, XFA_Element::AccessibleContent},
-    {0xa94cc00b /* includeXDPContent */, XFA_Element::IncludeXDPContent},
-    {0xa9b081a1 /* xmlConnection */, XFA_Element::XmlConnection},
-    {0xab2a3b74 /* validateApprovalSignatures */,
-     XFA_Element::ValidateApprovalSignatures},
-    {0xab8c5a2b /* signData */, XFA_Element::SignData},
-    {0xabaa2ceb /* packets */, XFA_Element::Packets},
-    {0xadba359c /* datePattern */, XFA_Element::DatePattern},
-    {0xae222b2b /* duplexOption */, XFA_Element::DuplexOption},
-    {0xb012effb /* base */, XFA_Element::Base},
-    {0xb0e5485d /* bind */, XFA_Element::Bind},
-    {0xb45d61b2 /* compression */, XFA_Element::Compression},
-    {0xb563f0ff /* user */, XFA_Element::User},
-    {0xb5848ad5 /* rectangle */, XFA_Element::Rectangle},
-    {0xb6dacb72 /* effectiveOutputPolicy */,
-     XFA_Element::EffectiveOutputPolicy},
-    {0xb7d7654d /* ADBE_JSDebugger */, XFA_Element::ADBE_JSDebugger},
-    {0xbab37f73 /* acrobat7 */, XFA_Element::Acrobat7},
-    {0xbc70081e /* interactive */, XFA_Element::Interactive},
-    {0xbc8fa350 /* locale */, XFA_Element::Locale},
-    {0xbcd44940 /* currentPage */, XFA_Element::CurrentPage},
-    {0xbde9abda /* data */, XFA_Element::Data},
-    {0xbde9abde /* date */, XFA_Element::Date},
-    {0xbe52dfbf /* desc */, XFA_Element::Desc},
-    {0xbf4b6405 /* encrypt */, XFA_Element::Encrypt},
-    {0xbfa87cce /* draw */, XFA_Element::Draw},
-    {0xc181ff4b /* encryption */, XFA_Element::Encryption},
-    {0xc1970f40 /* meridiemNames */, XFA_Element::MeridiemNames},
-    {0xc5ad9f5e /* messaging */, XFA_Element::Messaging},
-    {0xc69549f4 /* speak */, XFA_Element::Speak},
-    {0xc7743dc7 /* dataGroup */, XFA_Element::DataGroup},
-    {0xc7eb20e9 /* common */, XFA_Element::Common},
-    {0xc85d4528 /* #text */, XFA_Element::Sharptext},
-    {0xc861556a /* paginationOverride */, XFA_Element::PaginationOverride},
-    {0xc903dabb /* reasons */, XFA_Element::Reasons},
-    {0xc9a8127f /* signatureProperties */, XFA_Element::SignatureProperties},
-    {0xca010c2d /* threshold */, XFA_Element::Threshold},
-    {0xcb4c5e96 /* appearanceFilter */, XFA_Element::AppearanceFilter},
-    {0xcc92aba7 /* fill */, XFA_Element::Fill},
-    {0xcd308b77 /* font */, XFA_Element::Font},
-    {0xcd309ff4 /* form */, XFA_Element::Form},
-    {0xcebcca2d /* mediumInfo */, XFA_Element::MediumInfo},
-    {0xcfe0d643 /* certificate */, XFA_Element::Certificate},
-    {0xd012c033 /* password */, XFA_Element::Password},
-    {0xd01604bd /* runScripts */, XFA_Element::RunScripts},
-    {0xd1227e6f /* trace */, XFA_Element::Trace},
-    {0xd1532876 /* float */, XFA_Element::Float},
-    {0xd17a6c30 /* renderPolicy */, XFA_Element::RenderPolicy},
-    {0xd58aa962 /* destination */, XFA_Element::Destination},
-    {0xd6e27f1d /* value */, XFA_Element::Value},
-    {0xd7a14462 /* bookend */, XFA_Element::Bookend},
-    {0xd8c31254 /* exObject */, XFA_Element::ExObject},
-    {0xda6a8590 /* openAction */, XFA_Element::OpenAction},
-    {0xdab4fb7d /* neverEmbed */, XFA_Element::NeverEmbed},
-    {0xdb98475f /* bindItems */, XFA_Element::BindItems},
-    {0xdbfbe02e /* calculate */, XFA_Element::Calculate},
-    {0xdd7676ed /* print */, XFA_Element::Print},
-    {0xdde273d7 /* extras */, XFA_Element::Extras},
-    {0xde146b34 /* proto */, XFA_Element::Proto},
-    {0xdf059321 /* dSigData */, XFA_Element::DSigData},
-    {0xdfccf030 /* creator */, XFA_Element::Creator},
-    {0xdff78c6a /* connect */, XFA_Element::Connect},
-    {0xe11a2cbc /* permissions */, XFA_Element::Permissions},
-    {0xe14c801c /* connectionSet */, XFA_Element::ConnectionSet},
-    {0xe1c83a14 /* submit */, XFA_Element::Submit},
-    {0xe29821cd /* range */, XFA_Element::Range},
-    {0xe38d83c7 /* linearized */, XFA_Element::Linearized},
-    {0xe3aa2578 /* packet */, XFA_Element::Packet},
-    {0xe3aa860e /* rootElement */, XFA_Element::RootElement},
-    {0xe3e553fa /* plaintextMetadata */, XFA_Element::PlaintextMetadata},
-    {0xe3e6e4f2 /* numberSymbols */, XFA_Element::NumberSymbols},
-    {0xe3f067f6 /* printHighQuality */, XFA_Element::PrintHighQuality},
-    {0xe3fd078c /* driver */, XFA_Element::Driver},
-    {0xe48b34f2 /* incrementalLoad */, XFA_Element::IncrementalLoad},
-    {0xe550e7c2 /* subjectDN */, XFA_Element::SubjectDN},
-    {0xe6669a78 /* compressLogicalStructure */,
-     XFA_Element::CompressLogicalStructure},
-    {0xe7a7ea02 /* incrementalMerge */, XFA_Element::IncrementalMerge},
-    {0xe948530d /* radial */, XFA_Element::Radial},
-    {0xea8d6999 /* variables */, XFA_Element::Variables},
-    {0xeaa142c0 /* timePatterns */, XFA_Element::TimePatterns},
-    {0xeb943a71 /* effectiveInputPolicy */, XFA_Element::EffectiveInputPolicy},
-    {0xef04a2bc /* nameAttr */, XFA_Element::NameAttr},
-    {0xf07222ab /* conformance */, XFA_Element::Conformance},
-    {0xf0aaaadc /* transform */, XFA_Element::Transform},
-    {0xf1433e88 /* lockDocument */, XFA_Element::LockDocument},
-    {0xf54eb997 /* breakAfter */, XFA_Element::BreakAfter},
-    {0xf616da28 /* line */, XFA_Element::Line},
-    {0xf7055fb1 /* source */, XFA_Element::Source},
-    {0xf7eebe1c /* occur */, XFA_Element::Occur},
-    {0xf8d10d97 /* pickTrayByPDFSize */, XFA_Element::PickTrayByPDFSize},
-    {0xf8f19e3a /* monthNames */, XFA_Element::MonthNames},
-    {0xf984149b /* severity */, XFA_Element::Severity},
-    {0xf9bcb037 /* groupParent */, XFA_Element::GroupParent},
-    {0xfbc42fff /* documentAssembly */, XFA_Element::DocumentAssembly},
-    {0xfc78159f /* numberSymbol */, XFA_Element::NumberSymbol},
-    {0xfcbd606c /* tagged */, XFA_Element::Tagged},
-    {0xff063802 /* items */, XFA_Element::Items},
-};
-
-struct AttributeNameInfo {
-  uint32_t hash;
-  XFA_Attribute attribute;
-} AttributeNameInfoToEnum[] = {
-    {0x68 /* h */, XFA_Attribute::H},
-    {0x77 /* w */, XFA_Attribute::W},
-    {0x78 /* x */, XFA_Attribute::X},
-    {0x79 /* y */, XFA_Attribute::Y},
-    {0x21aed /* id */, XFA_Attribute::Id},
-    {0x25363 /* to */, XFA_Attribute::To},
-    {0xcb0ac9 /* lineThrough */, XFA_Attribute::LineThrough},
-    {0x2282c73 /* hAlign */, XFA_Attribute::HAlign},
-    {0x2c1c7f1 /* typeface */, XFA_Attribute::Typeface},
-    {0x3106c3a /* beforeTarget */, XFA_Attribute::BeforeTarget},
-    {0x31b19c1 /* name */, XFA_Attribute::Name},
-    {0x3848b3f /* next */, XFA_Attribute::Next},
-    {0x43e349b /* dataRowCount */, XFA_Attribute::DataRowCount},
-    {0x5518c25 /* break */, XFA_Attribute::Break},
-    {0x5ce6195 /* vScrollPolicy */, XFA_Attribute::VScrollPolicy},
-    {0x8c74ae9 /* fontHorizontalScale */, XFA_Attribute::FontHorizontalScale},
-    {0x8d4f1c7 /* textIndent */, XFA_Attribute::TextIndent},
-    {0x97c1c65 /* context */, XFA_Attribute::Context},
-    {0x9876578 /* trayOut */, XFA_Attribute::TrayOut},
-    {0xa2e3514 /* cap */, XFA_Attribute::Cap},
-    {0xb3543a6 /* max */, XFA_Attribute::Max},
-    {0xb356ca4 /* min */, XFA_Attribute::Min},
-    {0xbb8df5d /* ref */, XFA_Attribute::Ref},
-    {0xbb8f3df /* rid */, XFA_Attribute::Rid},
-    {0xc080cd3 /* url */, XFA_Attribute::Url},
-    {0xc0811ed /* use */, XFA_Attribute::Use},
-    {0xcfea02e /* leftInset */, XFA_Attribute::LeftInset},
-    {0x1026c59d /* widows */, XFA_Attribute::Widows},
-    {0x1059ec18 /* level */, XFA_Attribute::Level},
-    {0x1356caf8 /* bottomInset */, XFA_Attribute::BottomInset},
-    {0x13a08bdb /* overflowTarget */, XFA_Attribute::OverflowTarget},
-    {0x1414d431 /* allowMacro */, XFA_Attribute::AllowMacro},
-    {0x14a32d52 /* pagePosition */, XFA_Attribute::PagePosition},
-    {0x1517dfa1 /* columnWidths */, XFA_Attribute::ColumnWidths},
-    {0x169134a1 /* overflowLeader */, XFA_Attribute::OverflowLeader},
-    {0x1b8dce3e /* action */, XFA_Attribute::Action},
-    {0x1e459b8f /* nonRepudiation */, XFA_Attribute::NonRepudiation},
-    {0x1ec8ab2c /* rate */, XFA_Attribute::Rate},
-    {0x1ef3a64a /* allowRichText */, XFA_Attribute::AllowRichText},
-    {0x2038c9b2 /* role */, XFA_Attribute::Role},
-    {0x20914367 /* overflowTrailer */, XFA_Attribute::OverflowTrailer},
-    {0x226ca8f1 /* operation */, XFA_Attribute::Operation},
-    {0x24d85167 /* timeout */, XFA_Attribute::Timeout},
-    {0x25764436 /* topInset */, XFA_Attribute::TopInset},
-    {0x25839852 /* access */, XFA_Attribute::Access},
-    {0x268b7ec1 /* commandType */, XFA_Attribute::CommandType},
-    {0x28dee6e9 /* format */, XFA_Attribute::Format},
-    {0x28e17e91 /* dataPrep */, XFA_Attribute::DataPrep},
-    {0x292b88fe /* widgetData */, XFA_Attribute::WidgetData},
-    {0x29418bb7 /* abbr */, XFA_Attribute::Abbr},
-    {0x2a82d99c /* marginRight */, XFA_Attribute::MarginRight},
-    {0x2b5df51e /* dataDescription */, XFA_Attribute::DataDescription},
-    {0x2bb3f470 /* encipherOnly */, XFA_Attribute::EncipherOnly},
-    {0x2cd79033 /* kerningMode */, XFA_Attribute::KerningMode},
-    {0x2ee7678f /* rotate */, XFA_Attribute::Rotate},
-    {0x2f105f72 /* wordCharacterCount */, XFA_Attribute::WordCharacterCount},
-    {0x2f16a382 /* type */, XFA_Attribute::Type},
-    {0x34ae103c /* reserve */, XFA_Attribute::Reserve},
-    {0x3650557e /* textLocation */, XFA_Attribute::TextLocation},
-    {0x39cdb0a2 /* priority */, XFA_Attribute::Priority},
-    {0x3a0273a6 /* underline */, XFA_Attribute::Underline},
-    {0x3b582286 /* moduleWidth */, XFA_Attribute::ModuleWidth},
-    {0x3d123c26 /* hyphenate */, XFA_Attribute::Hyphenate},
-    {0x3e7af94f /* listen */, XFA_Attribute::Listen},
-    {0x4156ee3f /* delimiter */, XFA_Attribute::Delimiter},
-    {0x42fed1fd /* contentType */, XFA_Attribute::ContentType},
-    {0x453eaf38 /* startNew */, XFA_Attribute::StartNew},
-    {0x45a6daf8 /* eofAction */, XFA_Attribute::EofAction},
-    {0x47cfa43a /* allowNeutral */, XFA_Attribute::AllowNeutral},
-    {0x47d03490 /* connection */, XFA_Attribute::Connection},
-    {0x4873c601 /* baselineShift */, XFA_Attribute::BaselineShift},
-    {0x4b319767 /* overlinePeriod */, XFA_Attribute::OverlinePeriod},
-    {0x4b8bc840 /* fracDigits */, XFA_Attribute::FracDigits},
-    {0x4ef3d02c /* orientation */, XFA_Attribute::Orientation},
-    {0x4fdc3454 /* timeStamp */, XFA_Attribute::TimeStamp},
-    {0x52666f1c /* printCheckDigit */, XFA_Attribute::PrintCheckDigit},
-    {0x534729c9 /* marginLeft */, XFA_Attribute::MarginLeft},
-    {0x5392ea58 /* stroke */, XFA_Attribute::Stroke},
-    {0x5404d6df /* moduleHeight */, XFA_Attribute::ModuleHeight},
-    {0x54fa722c /* transferEncoding */, XFA_Attribute::TransferEncoding},
-    {0x552d9ad5 /* usage */, XFA_Attribute::Usage},
-    {0x570ce835 /* presence */, XFA_Attribute::Presence},
-    {0x5739d1ff /* radixOffset */, XFA_Attribute::RadixOffset},
-    {0x577682ac /* preserve */, XFA_Attribute::Preserve},
-    {0x58be2870 /* aliasNode */, XFA_Attribute::AliasNode},
-    {0x5a32e493 /* multiLine */, XFA_Attribute::MultiLine},
-    {0x5a50e9e6 /* version */, XFA_Attribute::Version},
-    {0x5ab23b6c /* startChar */, XFA_Attribute::StartChar},
-    {0x5b707a35 /* scriptTest */, XFA_Attribute::ScriptTest},
-    {0x5c054755 /* startAngle */, XFA_Attribute::StartAngle},
-    {0x5ec958c0 /* cursorType */, XFA_Attribute::CursorType},
-    {0x5f760b50 /* digitalSignature */, XFA_Attribute::DigitalSignature},
-    {0x60a61edd /* codeType */, XFA_Attribute::CodeType},
-    {0x60d4c8b1 /* output */, XFA_Attribute::Output},
-    {0x64110ab5 /* bookendTrailer */, XFA_Attribute::BookendTrailer},
-    {0x65e30c67 /* imagingBBox */, XFA_Attribute::ImagingBBox},
-    {0x66539c48 /* excludeInitialCap */, XFA_Attribute::ExcludeInitialCap},
-    {0x66642f8f /* force */, XFA_Attribute::Force},
-    {0x69aa2292 /* crlSign */, XFA_Attribute::CrlSign},
-    {0x6a3405dd /* previous */, XFA_Attribute::Previous},
-    {0x6a95c976 /* pushCharacterCount */, XFA_Attribute::PushCharacterCount},
-    {0x6b6ddcfb /* nullTest */, XFA_Attribute::NullTest},
-    {0x6cfa828a /* runAt */, XFA_Attribute::RunAt},
-    {0x731e0665 /* spaceBelow */, XFA_Attribute::SpaceBelow},
-    {0x74788f8b /* sweepAngle */, XFA_Attribute::SweepAngle},
-    {0x78bff531 /* numberOfCells */, XFA_Attribute::NumberOfCells},
-    {0x79543055 /* letterSpacing */, XFA_Attribute::LetterSpacing},
-    {0x79975f2b /* lockType */, XFA_Attribute::LockType},
-    {0x7a0cc471 /* passwordChar */, XFA_Attribute::PasswordChar},
-    {0x7a7cc341 /* vAlign */, XFA_Attribute::VAlign},
-    {0x7b29630a /* sourceBelow */, XFA_Attribute::SourceBelow},
-    {0x7b95e661 /* inverted */, XFA_Attribute::Inverted},
-    {0x7c2fd80b /* mark */, XFA_Attribute::Mark},
-    {0x7c2ff6ae /* maxH */, XFA_Attribute::MaxH},
-    {0x7c2ff6bd /* maxW */, XFA_Attribute::MaxW},
-    {0x7c732a66 /* truncate */, XFA_Attribute::Truncate},
-    {0x7d02356c /* minH */, XFA_Attribute::MinH},
-    {0x7d02357b /* minW */, XFA_Attribute::MinW},
-    {0x7d0b5fca /* initial */, XFA_Attribute::Initial},
-    {0x7d9fd7c5 /* mode */, XFA_Attribute::Mode},
-    {0x7e7e845e /* layout */, XFA_Attribute::Layout},
-    {0x7f6fd3d7 /* server */, XFA_Attribute::Server},
-    {0x824f21b7 /* embedPDF */, XFA_Attribute::EmbedPDF},
-    {0x8340ea66 /* oddOrEven */, XFA_Attribute::OddOrEven},
-    {0x836d4d7c /* tabDefault */, XFA_Attribute::TabDefault},
-    {0x8855805f /* contains */, XFA_Attribute::Contains},
-    {0x8a692521 /* rightInset */, XFA_Attribute::RightInset},
-    {0x8af2e657 /* maxChars */, XFA_Attribute::MaxChars},
-    {0x8b90e1f2 /* open */, XFA_Attribute::Open},
-    {0x8c99377e /* relation */, XFA_Attribute::Relation},
-    {0x8d181d61 /* wideNarrowRatio */, XFA_Attribute::WideNarrowRatio},
-    {0x8e1c2921 /* relevant */, XFA_Attribute::Relevant},
-    {0x8e29d794 /* signatureType */, XFA_Attribute::SignatureType},
-    {0x8ec6204c /* lineThroughPeriod */, XFA_Attribute::LineThroughPeriod},
-    {0x8ed182d1 /* shape */, XFA_Attribute::Shape},
-    {0x8fa01790 /* tabStops */, XFA_Attribute::TabStops},
-    {0x8fc36c0a /* outputBelow */, XFA_Attribute::OutputBelow},
-    {0x9041d4b0 /* short */, XFA_Attribute::Short},
-    {0x907c7719 /* fontVerticalScale */, XFA_Attribute::FontVerticalScale},
-    {0x94446dcc /* thickness */, XFA_Attribute::Thickness},
-    {0x957fa006 /* commitOn */, XFA_Attribute::CommitOn},
-    {0x982bd892 /* remainCharacterCount */,
-     XFA_Attribute::RemainCharacterCount},
-    {0x98fd4d81 /* keyAgreement */, XFA_Attribute::KeyAgreement},
-    {0x99800d7a /* errorCorrectionLevel */,
-     XFA_Attribute::ErrorCorrectionLevel},
-    {0x9a63da3d /* upsMode */, XFA_Attribute::UpsMode},
-    {0x9cc17d75 /* mergeMode */, XFA_Attribute::MergeMode},
-    {0x9d833d75 /* circular */, XFA_Attribute::Circular},
-    {0x9d8ee204 /* psName */, XFA_Attribute::PsName},
-    {0x9dcc3ab3 /* trailer */, XFA_Attribute::Trailer},
-    {0xa0933954 /* unicodeRange */, XFA_Attribute::UnicodeRange},
-    {0xa1b0d2f5 /* executeType */, XFA_Attribute::ExecuteType},
-    {0xa25a883d /* duplexImposition */, XFA_Attribute::DuplexImposition},
-    {0xa42ca1b7 /* trayIn */, XFA_Attribute::TrayIn},
-    {0xa433f001 /* bindingNode */, XFA_Attribute::BindingNode},
-    {0xa5340ff5 /* bofAction */, XFA_Attribute::BofAction},
-    {0xa5b410cf /* save */, XFA_Attribute::Save},
-    {0xa6118c89 /* targetType */, XFA_Attribute::TargetType},
-    {0xa66404cb /* keyEncipherment */, XFA_Attribute::KeyEncipherment},
-    {0xa6710262 /* credentialServerPolicy */,
-     XFA_Attribute::CredentialServerPolicy},
-    {0xa686975b /* size */, XFA_Attribute::Size},
-    {0xa85e74f3 /* initialNumber */, XFA_Attribute::InitialNumber},
-    {0xabef37e3 /* slope */, XFA_Attribute::Slope},
-    {0xabfa6c4f /* cSpace */, XFA_Attribute::CSpace},
-    {0xac06e2b0 /* colSpan */, XFA_Attribute::ColSpan},
-    {0xadc4c77b /* binding */, XFA_Attribute::Binding},
-    {0xaf754613 /* checksum */, XFA_Attribute::Checksum},
-    {0xb045fbc5 /* charEncoding */, XFA_Attribute::CharEncoding},
-    {0xb0e5485d /* bind */, XFA_Attribute::Bind},
-    {0xb12128b7 /* textEntry */, XFA_Attribute::TextEntry},
-    {0xb373a862 /* archive */, XFA_Attribute::Archive},
-    {0xb598a1f7 /* uuid */, XFA_Attribute::Uuid},
-    {0xb5e49bf2 /* posture */, XFA_Attribute::Posture},
-    {0xb6b44172 /* after */, XFA_Attribute::After},
-    {0xb716467b /* orphans */, XFA_Attribute::Orphans},
-    {0xbc0c4695 /* qualifiedName */, XFA_Attribute::QualifiedName},
-    {0xbc254332 /* usehref */, XFA_Attribute::Usehref},
-    {0xbc8fa350 /* locale */, XFA_Attribute::Locale},
-    {0xbd6e1d88 /* weight */, XFA_Attribute::Weight},
-    {0xbd96a0e9 /* underlinePeriod */, XFA_Attribute::UnderlinePeriod},
-    {0xbde9abda /* data */, XFA_Attribute::Data},
-    {0xbe52dfbf /* desc */, XFA_Attribute::Desc},
-    {0xbe9ba472 /* numbered */, XFA_Attribute::Numbered},
-    {0xc035c6b1 /* dataColumnCount */, XFA_Attribute::DataColumnCount},
-    {0xc0ec9fa4 /* overline */, XFA_Attribute::Overline},
-    {0xc2ba0923 /* urlPolicy */, XFA_Attribute::UrlPolicy},
-    {0xc2bd40fd /* anchorType */, XFA_Attribute::AnchorType},
-    {0xc39a88bd /* labelRef */, XFA_Attribute::LabelRef},
-    {0xc3c1442f /* bookendLeader */, XFA_Attribute::BookendLeader},
-    {0xc4547a08 /* maxLength */, XFA_Attribute::MaxLength},
-    {0xc4fed09b /* accessKey */, XFA_Attribute::AccessKey},
-    {0xc5762157 /* cursorLocation */, XFA_Attribute::CursorLocation},
-    {0xc860f30a /* delayedOpen */, XFA_Attribute::DelayedOpen},
-    {0xc8da4da7 /* target */, XFA_Attribute::Target},
-    {0xca5dc27c /* dataEncipherment */, XFA_Attribute::DataEncipherment},
-    {0xcb150479 /* afterTarget */, XFA_Attribute::AfterTarget},
-    {0xcbcaf66d /* leader */, XFA_Attribute::Leader},
-    {0xcca7897e /* picker */, XFA_Attribute::Picker},
-    {0xcd7f7b54 /* from */, XFA_Attribute::From},
-    {0xcea5e62c /* baseProfile */, XFA_Attribute::BaseProfile},
-    {0xd171b240 /* aspect */, XFA_Attribute::Aspect},
-    {0xd3c84d25 /* rowColumnRatio */, XFA_Attribute::RowColumnRatio},
-    {0xd4b01921 /* lineHeight */, XFA_Attribute::LineHeight},
-    {0xd4cc53f8 /* highlight */, XFA_Attribute::Highlight},
-    {0xd50f903a /* valueRef */, XFA_Attribute::ValueRef},
-    {0xd52482e0 /* maxEntries */, XFA_Attribute::MaxEntries},
-    {0xd57c513c /* dataLength */, XFA_Attribute::DataLength},
-    {0xd6128d8d /* activity */, XFA_Attribute::Activity},
-    {0xd6a39990 /* input */, XFA_Attribute::Input},
-    {0xd6e27f1d /* value */, XFA_Attribute::Value},
-    {0xd70798c2 /* blankOrNotBlank */, XFA_Attribute::BlankOrNotBlank},
-    {0xd861f8af /* addRevocationInfo */, XFA_Attribute::AddRevocationInfo},
-    {0xd8f982bf /* genericFamily */, XFA_Attribute::GenericFamily},
-    {0xd996fa9b /* hand */, XFA_Attribute::Hand},
-    {0xdb55fec5 /* href */, XFA_Attribute::Href},
-    {0xdc75676c /* textEncoding */, XFA_Attribute::TextEncoding},
-    {0xde7f92ba /* leadDigits */, XFA_Attribute::LeadDigits},
-    {0xe11a2cbc /* permissions */, XFA_Attribute::Permissions},
-    {0xe18b5659 /* spaceAbove */, XFA_Attribute::SpaceAbove},
-    {0xe1a26b56 /* codeBase */, XFA_Attribute::CodeBase},
-    {0xe349d044 /* stock */, XFA_Attribute::Stock},
-    {0xe372ae97 /* isNull */, XFA_Attribute::IsNull},
-    {0xe4c3a5e5 /* restoreState */, XFA_Attribute::RestoreState},
-    {0xe5c96d6a /* excludeAllCaps */, XFA_Attribute::ExcludeAllCaps},
-    {0xe64b1129 /* formatTest */, XFA_Attribute::FormatTest},
-    {0xe6f99487 /* hScrollPolicy */, XFA_Attribute::HScrollPolicy},
-    {0xe8dddf50 /* join */, XFA_Attribute::Join},
-    {0xe8f118a8 /* keyCertSign */, XFA_Attribute::KeyCertSign},
-    {0xe948b9a8 /* radius */, XFA_Attribute::Radius},
-    {0xe996b2fe /* sourceAbove */, XFA_Attribute::SourceAbove},
-    {0xea7090a0 /* override */, XFA_Attribute::Override},
-    {0xeb091003 /* classId */, XFA_Attribute::ClassId},
-    {0xeb511b54 /* disable */, XFA_Attribute::Disable},
-    {0xeda9017a /* scope */, XFA_Attribute::Scope},
-    {0xf197844d /* match */, XFA_Attribute::Match},
-    {0xf2009339 /* placement */, XFA_Attribute::Placement},
-    {0xf4ffce73 /* before */, XFA_Attribute::Before},
-    {0xf531b059 /* writingScript */, XFA_Attribute::WritingScript},
-    {0xf575ca75 /* endChar */, XFA_Attribute::EndChar},
-    {0xf6b47749 /* lock */, XFA_Attribute::Lock},
-    {0xf6b4afb0 /* long */, XFA_Attribute::Long},
-    {0xf6b59543 /* intact */, XFA_Attribute::Intact},
-    {0xf889e747 /* xdpContent */, XFA_Attribute::XdpContent},
-    {0xfea53ec6 /* decipherOnly */, XFA_Attribute::DecipherOnly},
-};
-
-}  // namespace
-
-// static
-XFA_Element CXFA_Node::NameToElement(const WideString& name) {
-  uint32_t hash = FX_HashCode_GetW(name.AsStringView(), false);
-  auto* elem = std::lower_bound(
-      std::begin(ElementNameToEnum), std::end(ElementNameToEnum), hash,
-      [](const ElementNameInfo& a, uint32_t hash) { return a.hash < hash; });
-  if (elem != std::end(ElementNameToEnum) && elem->hash == hash)
-    return elem->element;
-  return XFA_Element::Unknown;
-}
-
-// static
-XFA_Attribute CXFA_Node::NameToAttribute(const WideStringView& name) {
-  uint32_t hash = FX_HashCode_GetW(name, false);
-  auto* elem = std::lower_bound(
-      std::begin(AttributeNameInfoToEnum), std::end(AttributeNameInfoToEnum),
-      hash,
-      [](const AttributeNameInfo& a, uint32_t hash) { return a.hash < hash; });
-  if (elem != std::end(AttributeNameInfoToEnum) && elem->hash == hash)
-    return elem->attribute;
-  return XFA_Attribute::Unknown;
-}
-
-// static
-std::unique_ptr<CXFA_Node> CXFA_Node::Create(CXFA_Document* doc,
-                                             XFA_Element element,
-                                             XFA_PacketType packet) {
-  std::unique_ptr<CXFA_Node> node;
-  switch (element) {
-    case XFA_Element::Ps:
-      node = pdfium::MakeUnique<CXFA_Ps>(doc, packet);
-      break;
-    case XFA_Element::To:
-      node = pdfium::MakeUnique<CXFA_To>(doc, packet);
-      break;
-    case XFA_Element::Ui:
-      node = pdfium::MakeUnique<CXFA_Ui>(doc, packet);
-      break;
-    case XFA_Element::RecordSet:
-      node = pdfium::MakeUnique<CXFA_RecordSet>(doc, packet);
-      break;
-    case XFA_Element::SubsetBelow:
-      node = pdfium::MakeUnique<CXFA_SubsetBelow>(doc, packet);
-      break;
-    case XFA_Element::SubformSet:
-      node = pdfium::MakeUnique<CXFA_SubformSet>(doc, packet);
-      break;
-    case XFA_Element::AdobeExtensionLevel:
-      node = pdfium::MakeUnique<CXFA_AdobeExtensionLevel>(doc, packet);
-      break;
-    case XFA_Element::Typeface:
-      node = pdfium::MakeUnique<CXFA_Typeface>(doc, packet);
-      break;
-    case XFA_Element::Break:
-      node = pdfium::MakeUnique<CXFA_Break>(doc, packet);
-      break;
-    case XFA_Element::FontInfo:
-      node = pdfium::MakeUnique<CXFA_FontInfo>(doc, packet);
-      break;
-    case XFA_Element::NumberPattern:
-      node = pdfium::MakeUnique<CXFA_NumberPattern>(doc, packet);
-      break;
-    case XFA_Element::DynamicRender:
-      node = pdfium::MakeUnique<CXFA_DynamicRender>(doc, packet);
-      break;
-    case XFA_Element::PrintScaling:
-      node = pdfium::MakeUnique<CXFA_PrintScaling>(doc, packet);
-      break;
-    case XFA_Element::CheckButton:
-      node = pdfium::MakeUnique<CXFA_CheckButton>(doc, packet);
-      break;
-    case XFA_Element::DatePatterns:
-      node = pdfium::MakeUnique<CXFA_DatePatterns>(doc, packet);
-      break;
-    case XFA_Element::SourceSet:
-      node = pdfium::MakeUnique<CXFA_SourceSet>(doc, packet);
-      break;
-    case XFA_Element::Amd:
-      node = pdfium::MakeUnique<CXFA_Amd>(doc, packet);
-      break;
-    case XFA_Element::Arc:
-      node = pdfium::MakeUnique<CXFA_Arc>(doc, packet);
-      break;
-    case XFA_Element::Day:
-      node = pdfium::MakeUnique<CXFA_Day>(doc, packet);
-      break;
-    case XFA_Element::Era:
-      node = pdfium::MakeUnique<CXFA_Era>(doc, packet);
-      break;
-    case XFA_Element::Jog:
-      node = pdfium::MakeUnique<CXFA_Jog>(doc, packet);
-      break;
-    case XFA_Element::Log:
-      node = pdfium::MakeUnique<CXFA_Log>(doc, packet);
-      break;
-    case XFA_Element::Map:
-      node = pdfium::MakeUnique<CXFA_Map>(doc, packet);
-      break;
-    case XFA_Element::Mdp:
-      node = pdfium::MakeUnique<CXFA_Mdp>(doc, packet);
-      break;
-    case XFA_Element::BreakBefore:
-      node = pdfium::MakeUnique<CXFA_BreakBefore>(doc, packet);
-      break;
-    case XFA_Element::Oid:
-      node = pdfium::MakeUnique<CXFA_Oid>(doc, packet);
-      break;
-    case XFA_Element::Pcl:
-      node = pdfium::MakeUnique<CXFA_Pcl>(doc, packet);
-      break;
-    case XFA_Element::Pdf:
-      node = pdfium::MakeUnique<CXFA_Pdf>(doc, packet);
-      break;
-    case XFA_Element::Ref:
-      node = pdfium::MakeUnique<CXFA_Ref>(doc, packet);
-      break;
-    case XFA_Element::Uri:
-      node = pdfium::MakeUnique<CXFA_Uri>(doc, packet);
-      break;
-    case XFA_Element::Xdc:
-      node = pdfium::MakeUnique<CXFA_Xdc>(doc, packet);
-      break;
-    case XFA_Element::Xdp:
-      node = pdfium::MakeUnique<CXFA_Xdp>(doc, packet);
-      break;
-    case XFA_Element::Xfa:
-      node = pdfium::MakeUnique<CXFA_Xfa>(doc, packet);
-      break;
-    case XFA_Element::Xsl:
-      node = pdfium::MakeUnique<CXFA_Xsl>(doc, packet);
-      break;
-    case XFA_Element::Zpl:
-      node = pdfium::MakeUnique<CXFA_Zpl>(doc, packet);
-      break;
-    case XFA_Element::Cache:
-      node = pdfium::MakeUnique<CXFA_Cache>(doc, packet);
-      break;
-    case XFA_Element::Margin:
-      node = pdfium::MakeUnique<CXFA_Margin>(doc, packet);
-      break;
-    case XFA_Element::KeyUsage:
-      node = pdfium::MakeUnique<CXFA_KeyUsage>(doc, packet);
-      break;
-    case XFA_Element::Exclude:
-      node = pdfium::MakeUnique<CXFA_Exclude>(doc, packet);
-      break;
-    case XFA_Element::ChoiceList:
-      node = pdfium::MakeUnique<CXFA_ChoiceList>(doc, packet);
-      break;
-    case XFA_Element::Level:
-      node = pdfium::MakeUnique<CXFA_Level>(doc, packet);
-      break;
-    case XFA_Element::LabelPrinter:
-      node = pdfium::MakeUnique<CXFA_LabelPrinter>(doc, packet);
-      break;
-    case XFA_Element::CalendarSymbols:
-      node = pdfium::MakeUnique<CXFA_CalendarSymbols>(doc, packet);
-      break;
-    case XFA_Element::Para:
-      node = pdfium::MakeUnique<CXFA_Para>(doc, packet);
-      break;
-    case XFA_Element::Part:
-      node = pdfium::MakeUnique<CXFA_Part>(doc, packet);
-      break;
-    case XFA_Element::Pdfa:
-      node = pdfium::MakeUnique<CXFA_Pdfa>(doc, packet);
-      break;
-    case XFA_Element::Filter:
-      node = pdfium::MakeUnique<CXFA_Filter>(doc, packet);
-      break;
-    case XFA_Element::Present:
-      node = pdfium::MakeUnique<CXFA_Present>(doc, packet);
-      break;
-    case XFA_Element::Pagination:
-      node = pdfium::MakeUnique<CXFA_Pagination>(doc, packet);
-      break;
-    case XFA_Element::Encoding:
-      node = pdfium::MakeUnique<CXFA_Encoding>(doc, packet);
-      break;
-    case XFA_Element::Event:
-      node = pdfium::MakeUnique<CXFA_Event>(doc, packet);
-      break;
-    case XFA_Element::Whitespace:
-      node = pdfium::MakeUnique<CXFA_Whitespace>(doc, packet);
-      break;
-    case XFA_Element::DefaultUi:
-      node = pdfium::MakeUnique<CXFA_DefaultUi>(doc, packet);
-      break;
-    case XFA_Element::DataModel:
-      node = pdfium::MakeUnique<CXFA_DataModel>(doc, packet);
-      break;
-    case XFA_Element::Barcode:
-      node = pdfium::MakeUnique<CXFA_Barcode>(doc, packet);
-      break;
-    case XFA_Element::TimePattern:
-      node = pdfium::MakeUnique<CXFA_TimePattern>(doc, packet);
-      break;
-    case XFA_Element::BatchOutput:
-      node = pdfium::MakeUnique<CXFA_BatchOutput>(doc, packet);
-      break;
-    case XFA_Element::Enforce:
-      node = pdfium::MakeUnique<CXFA_Enforce>(doc, packet);
-      break;
-    case XFA_Element::CurrencySymbols:
-      node = pdfium::MakeUnique<CXFA_CurrencySymbols>(doc, packet);
-      break;
-    case XFA_Element::AddSilentPrint:
-      node = pdfium::MakeUnique<CXFA_AddSilentPrint>(doc, packet);
-      break;
-    case XFA_Element::Rename:
-      node = pdfium::MakeUnique<CXFA_Rename>(doc, packet);
-      break;
-    case XFA_Element::Operation:
-      node = pdfium::MakeUnique<CXFA_Operation>(doc, packet);
-      break;
-    case XFA_Element::Typefaces:
-      node = pdfium::MakeUnique<CXFA_Typefaces>(doc, packet);
-      break;
-    case XFA_Element::SubjectDNs:
-      node = pdfium::MakeUnique<CXFA_SubjectDNs>(doc, packet);
-      break;
-    case XFA_Element::Issuers:
-      node = pdfium::MakeUnique<CXFA_Issuers>(doc, packet);
-      break;
-    case XFA_Element::WsdlConnection:
-      node = pdfium::MakeUnique<CXFA_WsdlConnection>(doc, packet);
-      break;
-    case XFA_Element::Debug:
-      node = pdfium::MakeUnique<CXFA_Debug>(doc, packet);
-      break;
-    case XFA_Element::Delta:
-      node = pdfium::MakeUnique<CXFA_Delta>(doc, packet);
-      break;
-    case XFA_Element::EraNames:
-      node = pdfium::MakeUnique<CXFA_EraNames>(doc, packet);
-      break;
-    case XFA_Element::ModifyAnnots:
-      node = pdfium::MakeUnique<CXFA_ModifyAnnots>(doc, packet);
-      break;
-    case XFA_Element::StartNode:
-      node = pdfium::MakeUnique<CXFA_StartNode>(doc, packet);
-      break;
-    case XFA_Element::Button:
-      node = pdfium::MakeUnique<CXFA_Button>(doc, packet);
-      break;
-    case XFA_Element::Format:
-      node = pdfium::MakeUnique<CXFA_Format>(doc, packet);
-      break;
-    case XFA_Element::Border:
-      node = pdfium::MakeUnique<CXFA_Border>(doc, packet);
-      break;
-    case XFA_Element::Area:
-      node = pdfium::MakeUnique<CXFA_Area>(doc, packet);
-      break;
-    case XFA_Element::Hyphenation:
-      node = pdfium::MakeUnique<CXFA_Hyphenation>(doc, packet);
-      break;
-    case XFA_Element::Text:
-      node = pdfium::MakeUnique<CXFA_Text>(doc, packet);
-      break;
-    case XFA_Element::Time:
-      node = pdfium::MakeUnique<CXFA_Time>(doc, packet);
-      break;
-    case XFA_Element::Type:
-      node = pdfium::MakeUnique<CXFA_Type>(doc, packet);
-      break;
-    case XFA_Element::Overprint:
-      node = pdfium::MakeUnique<CXFA_Overprint>(doc, packet);
-      break;
-    case XFA_Element::Certificates:
-      node = pdfium::MakeUnique<CXFA_Certificates>(doc, packet);
-      break;
-    case XFA_Element::EncryptionMethods:
-      node = pdfium::MakeUnique<CXFA_EncryptionMethods>(doc, packet);
-      break;
-    case XFA_Element::SetProperty:
-      node = pdfium::MakeUnique<CXFA_SetProperty>(doc, packet);
-      break;
-    case XFA_Element::PrinterName:
-      node = pdfium::MakeUnique<CXFA_PrinterName>(doc, packet);
-      break;
-    case XFA_Element::StartPage:
-      node = pdfium::MakeUnique<CXFA_StartPage>(doc, packet);
-      break;
-    case XFA_Element::PageOffset:
-      node = pdfium::MakeUnique<CXFA_PageOffset>(doc, packet);
-      break;
-    case XFA_Element::DateTime:
-      node = pdfium::MakeUnique<CXFA_DateTime>(doc, packet);
-      break;
-    case XFA_Element::Comb:
-      node = pdfium::MakeUnique<CXFA_Comb>(doc, packet);
-      break;
-    case XFA_Element::Pattern:
-      node = pdfium::MakeUnique<CXFA_Pattern>(doc, packet);
-      break;
-    case XFA_Element::IfEmpty:
-      node = pdfium::MakeUnique<CXFA_IfEmpty>(doc, packet);
-      break;
-    case XFA_Element::SuppressBanner:
-      node = pdfium::MakeUnique<CXFA_SuppressBanner>(doc, packet);
-      break;
-    case XFA_Element::OutputBin:
-      node = pdfium::MakeUnique<CXFA_OutputBin>(doc, packet);
-      break;
-    case XFA_Element::Field:
-      node = pdfium::MakeUnique<CXFA_Field>(doc, packet);
-      break;
-    case XFA_Element::Agent:
-      node = pdfium::MakeUnique<CXFA_Agent>(doc, packet);
-      break;
-    case XFA_Element::OutputXSL:
-      node = pdfium::MakeUnique<CXFA_OutputXSL>(doc, packet);
-      break;
-    case XFA_Element::AdjustData:
-      node = pdfium::MakeUnique<CXFA_AdjustData>(doc, packet);
-      break;
-    case XFA_Element::AutoSave:
-      node = pdfium::MakeUnique<CXFA_AutoSave>(doc, packet);
-      break;
-    case XFA_Element::ContentArea:
-      node = pdfium::MakeUnique<CXFA_ContentArea>(doc, packet);
-      break;
-    case XFA_Element::WsdlAddress:
-      node = pdfium::MakeUnique<CXFA_WsdlAddress>(doc, packet);
-      break;
-    case XFA_Element::Solid:
-      node = pdfium::MakeUnique<CXFA_Solid>(doc, packet);
-      break;
-    case XFA_Element::DateTimeSymbols:
-      node = pdfium::MakeUnique<CXFA_DateTimeSymbols>(doc, packet);
-      break;
-    case XFA_Element::EncryptionLevel:
-      node = pdfium::MakeUnique<CXFA_EncryptionLevel>(doc, packet);
-      break;
-    case XFA_Element::Edge:
-      node = pdfium::MakeUnique<CXFA_Edge>(doc, packet);
-      break;
-    case XFA_Element::Stipple:
-      node = pdfium::MakeUnique<CXFA_Stipple>(doc, packet);
-      break;
-    case XFA_Element::Attributes:
-      node = pdfium::MakeUnique<CXFA_Attributes>(doc, packet);
-      break;
-    case XFA_Element::VersionControl:
-      node = pdfium::MakeUnique<CXFA_VersionControl>(doc, packet);
-      break;
-    case XFA_Element::Meridiem:
-      node = pdfium::MakeUnique<CXFA_Meridiem>(doc, packet);
-      break;
-    case XFA_Element::ExclGroup:
-      node = pdfium::MakeUnique<CXFA_ExclGroup>(doc, packet);
-      break;
-    case XFA_Element::ToolTip:
-      node = pdfium::MakeUnique<CXFA_ToolTip>(doc, packet);
-      break;
-    case XFA_Element::Compress:
-      node = pdfium::MakeUnique<CXFA_Compress>(doc, packet);
-      break;
-    case XFA_Element::Reason:
-      node = pdfium::MakeUnique<CXFA_Reason>(doc, packet);
-      break;
-    case XFA_Element::Execute:
-      node = pdfium::MakeUnique<CXFA_Execute>(doc, packet);
-      break;
-    case XFA_Element::ContentCopy:
-      node = pdfium::MakeUnique<CXFA_ContentCopy>(doc, packet);
-      break;
-    case XFA_Element::DateTimeEdit:
-      node = pdfium::MakeUnique<CXFA_DateTimeEdit>(doc, packet);
-      break;
-    case XFA_Element::Config:
-      node = pdfium::MakeUnique<CXFA_Config>(doc, packet);
-      break;
-    case XFA_Element::Image:
-      node = pdfium::MakeUnique<CXFA_Image>(doc, packet);
-      break;
-    case XFA_Element::SharpxHTML:
-      node = pdfium::MakeUnique<CXFA_SharpxHTML>(doc, packet);
-      break;
-    case XFA_Element::NumberOfCopies:
-      node = pdfium::MakeUnique<CXFA_NumberOfCopies>(doc, packet);
-      break;
-    case XFA_Element::BehaviorOverride:
-      node = pdfium::MakeUnique<CXFA_BehaviorOverride>(doc, packet);
-      break;
-    case XFA_Element::TimeStamp:
-      node = pdfium::MakeUnique<CXFA_TimeStamp>(doc, packet);
-      break;
-    case XFA_Element::Month:
-      node = pdfium::MakeUnique<CXFA_Month>(doc, packet);
-      break;
-    case XFA_Element::ViewerPreferences:
-      node = pdfium::MakeUnique<CXFA_ViewerPreferences>(doc, packet);
-      break;
-    case XFA_Element::ScriptModel:
-      node = pdfium::MakeUnique<CXFA_ScriptModel>(doc, packet);
-      break;
-    case XFA_Element::Decimal:
-      node = pdfium::MakeUnique<CXFA_Decimal>(doc, packet);
-      break;
-    case XFA_Element::Subform:
-      node = pdfium::MakeUnique<CXFA_Subform>(doc, packet);
-      break;
-    case XFA_Element::Select:
-      node = pdfium::MakeUnique<CXFA_Select>(doc, packet);
-      break;
-    case XFA_Element::Window:
-      node = pdfium::MakeUnique<CXFA_Window>(doc, packet);
-      break;
-    case XFA_Element::LocaleSet:
-      node = pdfium::MakeUnique<CXFA_LocaleSet>(doc, packet);
-      break;
-    case XFA_Element::Handler:
-      node = pdfium::MakeUnique<CXFA_Handler>(doc, packet);
-      break;
-    case XFA_Element::Presence:
-      node = pdfium::MakeUnique<CXFA_Presence>(doc, packet);
-      break;
-    case XFA_Element::Record:
-      node = pdfium::MakeUnique<CXFA_Record>(doc, packet);
-      break;
-    case XFA_Element::Embed:
-      node = pdfium::MakeUnique<CXFA_Embed>(doc, packet);
-      break;
-    case XFA_Element::Version:
-      node = pdfium::MakeUnique<CXFA_Version>(doc, packet);
-      break;
-    case XFA_Element::Command:
-      node = pdfium::MakeUnique<CXFA_Command>(doc, packet);
-      break;
-    case XFA_Element::Copies:
-      node = pdfium::MakeUnique<CXFA_Copies>(doc, packet);
-      break;
-    case XFA_Element::Staple:
-      node = pdfium::MakeUnique<CXFA_Staple>(doc, packet);
-      break;
-    case XFA_Element::SubmitFormat:
-      node = pdfium::MakeUnique<CXFA_SubmitFormat>(doc, packet);
-      break;
-    case XFA_Element::Boolean:
-      node = pdfium::MakeUnique<CXFA_Boolean>(doc, packet);
-      break;
-    case XFA_Element::Message:
-      node = pdfium::MakeUnique<CXFA_Message>(doc, packet);
-      break;
-    case XFA_Element::Output:
-      node = pdfium::MakeUnique<CXFA_Output>(doc, packet);
-      break;
-    case XFA_Element::PsMap:
-      node = pdfium::MakeUnique<CXFA_PsMap>(doc, packet);
-      break;
-    case XFA_Element::ExcludeNS:
-      node = pdfium::MakeUnique<CXFA_ExcludeNS>(doc, packet);
-      break;
-    case XFA_Element::Assist:
-      node = pdfium::MakeUnique<CXFA_Assist>(doc, packet);
-      break;
-    case XFA_Element::Picture:
-      node = pdfium::MakeUnique<CXFA_Picture>(doc, packet);
-      break;
-    case XFA_Element::Traversal:
-      node = pdfium::MakeUnique<CXFA_Traversal>(doc, packet);
-      break;
-    case XFA_Element::SilentPrint:
-      node = pdfium::MakeUnique<CXFA_SilentPrint>(doc, packet);
-      break;
-    case XFA_Element::WebClient:
-      node = pdfium::MakeUnique<CXFA_WebClient>(doc, packet);
-      break;
-    case XFA_Element::Producer:
-      node = pdfium::MakeUnique<CXFA_Producer>(doc, packet);
-      break;
-    case XFA_Element::Corner:
-      node = pdfium::MakeUnique<CXFA_Corner>(doc, packet);
-      break;
-    case XFA_Element::MsgId:
-      node = pdfium::MakeUnique<CXFA_MsgId>(doc, packet);
-      break;
-    case XFA_Element::Color:
-      node = pdfium::MakeUnique<CXFA_Color>(doc, packet);
-      break;
-    case XFA_Element::Keep:
-      node = pdfium::MakeUnique<CXFA_Keep>(doc, packet);
-      break;
-    case XFA_Element::Query:
-      node = pdfium::MakeUnique<CXFA_Query>(doc, packet);
-      break;
-    case XFA_Element::Insert:
-      node = pdfium::MakeUnique<CXFA_Insert>(doc, packet);
-      break;
-    case XFA_Element::ImageEdit:
-      node = pdfium::MakeUnique<CXFA_ImageEdit>(doc, packet);
-      break;
-    case XFA_Element::Validate:
-      node = pdfium::MakeUnique<CXFA_Validate>(doc, packet);
-      break;
-    case XFA_Element::DigestMethods:
-      node = pdfium::MakeUnique<CXFA_DigestMethods>(doc, packet);
-      break;
-    case XFA_Element::NumberPatterns:
-      node = pdfium::MakeUnique<CXFA_NumberPatterns>(doc, packet);
-      break;
-    case XFA_Element::PageSet:
-      node = pdfium::MakeUnique<CXFA_PageSet>(doc, packet);
-      break;
-    case XFA_Element::Integer:
-      node = pdfium::MakeUnique<CXFA_Integer>(doc, packet);
-      break;
-    case XFA_Element::SoapAddress:
-      node = pdfium::MakeUnique<CXFA_SoapAddress>(doc, packet);
-      break;
-    case XFA_Element::Equate:
-      node = pdfium::MakeUnique<CXFA_Equate>(doc, packet);
-      break;
-    case XFA_Element::FormFieldFilling:
-      node = pdfium::MakeUnique<CXFA_FormFieldFilling>(doc, packet);
-      break;
-    case XFA_Element::PageRange:
-      node = pdfium::MakeUnique<CXFA_PageRange>(doc, packet);
-      break;
-    case XFA_Element::Update:
-      node = pdfium::MakeUnique<CXFA_Update>(doc, packet);
-      break;
-    case XFA_Element::ConnectString:
-      node = pdfium::MakeUnique<CXFA_ConnectString>(doc, packet);
-      break;
-    case XFA_Element::Mode:
-      node = pdfium::MakeUnique<CXFA_Mode>(doc, packet);
-      break;
-    case XFA_Element::Layout:
-      node = pdfium::MakeUnique<CXFA_Layout>(doc, packet);
-      break;
-    case XFA_Element::Sharpxml:
-      node = pdfium::MakeUnique<CXFA_Sharpxml>(doc, packet);
-      break;
-    case XFA_Element::XsdConnection:
-      node = pdfium::MakeUnique<CXFA_XsdConnection>(doc, packet);
-      break;
-    case XFA_Element::Traverse:
-      node = pdfium::MakeUnique<CXFA_Traverse>(doc, packet);
-      break;
-    case XFA_Element::Encodings:
-      node = pdfium::MakeUnique<CXFA_Encodings>(doc, packet);
-      break;
-    case XFA_Element::Template:
-      node = pdfium::MakeUnique<CXFA_Template>(doc, packet);
-      break;
-    case XFA_Element::Acrobat:
-      node = pdfium::MakeUnique<CXFA_Acrobat>(doc, packet);
-      break;
-    case XFA_Element::ValidationMessaging:
-      node = pdfium::MakeUnique<CXFA_ValidationMessaging>(doc, packet);
-      break;
-    case XFA_Element::Signing:
-      node = pdfium::MakeUnique<CXFA_Signing>(doc, packet);
-      break;
-    case XFA_Element::Script:
-      node = pdfium::MakeUnique<CXFA_Script>(doc, packet);
-      break;
-    case XFA_Element::AddViewerPreferences:
-      node = pdfium::MakeUnique<CXFA_AddViewerPreferences>(doc, packet);
-      break;
-    case XFA_Element::AlwaysEmbed:
-      node = pdfium::MakeUnique<CXFA_AlwaysEmbed>(doc, packet);
-      break;
-    case XFA_Element::PasswordEdit:
-      node = pdfium::MakeUnique<CXFA_PasswordEdit>(doc, packet);
-      break;
-    case XFA_Element::NumericEdit:
-      node = pdfium::MakeUnique<CXFA_NumericEdit>(doc, packet);
-      break;
-    case XFA_Element::EncryptionMethod:
-      node = pdfium::MakeUnique<CXFA_EncryptionMethod>(doc, packet);
-      break;
-    case XFA_Element::Change:
-      node = pdfium::MakeUnique<CXFA_Change>(doc, packet);
-      break;
-    case XFA_Element::PageArea:
-      node = pdfium::MakeUnique<CXFA_PageArea>(doc, packet);
-      break;
-    case XFA_Element::SubmitUrl:
-      node = pdfium::MakeUnique<CXFA_SubmitUrl>(doc, packet);
-      break;
-    case XFA_Element::Oids:
-      node = pdfium::MakeUnique<CXFA_Oids>(doc, packet);
-      break;
-    case XFA_Element::Signature:
-      node = pdfium::MakeUnique<CXFA_Signature>(doc, packet);
-      break;
-    case XFA_Element::ADBE_JSConsole:
-      node = pdfium::MakeUnique<CXFA_aDBE_JSConsole>(doc, packet);
-      break;
-    case XFA_Element::Caption:
-      node = pdfium::MakeUnique<CXFA_Caption>(doc, packet);
-      break;
-    case XFA_Element::Relevant:
-      node = pdfium::MakeUnique<CXFA_Relevant>(doc, packet);
-      break;
-    case XFA_Element::FlipLabel:
-      node = pdfium::MakeUnique<CXFA_FlipLabel>(doc, packet);
-      break;
-    case XFA_Element::ExData:
-      node = pdfium::MakeUnique<CXFA_ExData>(doc, packet);
-      break;
-    case XFA_Element::DayNames:
-      node = pdfium::MakeUnique<CXFA_DayNames>(doc, packet);
-      break;
-    case XFA_Element::SoapAction:
-      node = pdfium::MakeUnique<CXFA_SoapAction>(doc, packet);
-      break;
-    case XFA_Element::DefaultTypeface:
-      node = pdfium::MakeUnique<CXFA_DefaultTypeface>(doc, packet);
-      break;
-    case XFA_Element::Manifest:
-      node = pdfium::MakeUnique<CXFA_Manifest>(doc, packet);
-      break;
-    case XFA_Element::Overflow:
-      node = pdfium::MakeUnique<CXFA_Overflow>(doc, packet);
-      break;
-    case XFA_Element::Linear:
-      node = pdfium::MakeUnique<CXFA_Linear>(doc, packet);
-      break;
-    case XFA_Element::CurrencySymbol:
-      node = pdfium::MakeUnique<CXFA_CurrencySymbol>(doc, packet);
-      break;
-    case XFA_Element::Delete:
-      node = pdfium::MakeUnique<CXFA_Delete>(doc, packet);
-      break;
-    case XFA_Element::DigestMethod:
-      node = pdfium::MakeUnique<CXFA_DigestMethod>(doc, packet);
-      break;
-    case XFA_Element::InstanceManager:
-      node = pdfium::MakeUnique<CXFA_InstanceManager>(doc, packet);
-      break;
-    case XFA_Element::EquateRange:
-      node = pdfium::MakeUnique<CXFA_EquateRange>(doc, packet);
-      break;
-    case XFA_Element::Medium:
-      node = pdfium::MakeUnique<CXFA_Medium>(doc, packet);
-      break;
-    case XFA_Element::TextEdit:
-      node = pdfium::MakeUnique<CXFA_TextEdit>(doc, packet);
-      break;
-    case XFA_Element::TemplateCache:
-      node = pdfium::MakeUnique<CXFA_TemplateCache>(doc, packet);
-      break;
-    case XFA_Element::CompressObjectStream:
-      node = pdfium::MakeUnique<CXFA_CompressObjectStream>(doc, packet);
-      break;
-    case XFA_Element::DataValue:
-      node = pdfium::MakeUnique<CXFA_DataValue>(doc, packet);
-      break;
-    case XFA_Element::AccessibleContent:
-      node = pdfium::MakeUnique<CXFA_AccessibleContent>(doc, packet);
-      break;
-    case XFA_Element::IncludeXDPContent:
-      node = pdfium::MakeUnique<CXFA_IncludeXDPContent>(doc, packet);
-      break;
-    case XFA_Element::XmlConnection:
-      node = pdfium::MakeUnique<CXFA_XmlConnection>(doc, packet);
-      break;
-    case XFA_Element::ValidateApprovalSignatures:
-      node = pdfium::MakeUnique<CXFA_ValidateApprovalSignatures>(doc, packet);
-      break;
-    case XFA_Element::SignData:
-      node = pdfium::MakeUnique<CXFA_SignData>(doc, packet);
-      break;
-    case XFA_Element::Packets:
-      node = pdfium::MakeUnique<CXFA_Packets>(doc, packet);
-      break;
-    case XFA_Element::DatePattern:
-      node = pdfium::MakeUnique<CXFA_DatePattern>(doc, packet);
-      break;
-    case XFA_Element::DuplexOption:
-      node = pdfium::MakeUnique<CXFA_DuplexOption>(doc, packet);
-      break;
-    case XFA_Element::Base:
-      node = pdfium::MakeUnique<CXFA_Base>(doc, packet);
-      break;
-    case XFA_Element::Bind:
-      node = pdfium::MakeUnique<CXFA_Bind>(doc, packet);
-      break;
-    case XFA_Element::Compression:
-      node = pdfium::MakeUnique<CXFA_Compression>(doc, packet);
-      break;
-    case XFA_Element::User:
-      node = pdfium::MakeUnique<CXFA_User>(doc, packet);
-      break;
-    case XFA_Element::Rectangle:
-      node = pdfium::MakeUnique<CXFA_Rectangle>(doc, packet);
-      break;
-    case XFA_Element::EffectiveOutputPolicy:
-      node = pdfium::MakeUnique<CXFA_EffectiveOutputPolicy>(doc, packet);
-      break;
-    case XFA_Element::ADBE_JSDebugger:
-      node = pdfium::MakeUnique<CXFA_aDBE_JSDebugger>(doc, packet);
-      break;
-    case XFA_Element::Acrobat7:
-      node = pdfium::MakeUnique<CXFA_Acrobat7>(doc, packet);
-      break;
-    case XFA_Element::Interactive:
-      node = pdfium::MakeUnique<CXFA_Interactive>(doc, packet);
-      break;
-    case XFA_Element::Locale:
-      node = pdfium::MakeUnique<CXFA_Locale>(doc, packet);
-      break;
-    case XFA_Element::CurrentPage:
-      node = pdfium::MakeUnique<CXFA_CurrentPage>(doc, packet);
-      break;
-    case XFA_Element::Data:
-      node = pdfium::MakeUnique<CXFA_Data>(doc, packet);
-      break;
-    case XFA_Element::Date:
-      node = pdfium::MakeUnique<CXFA_Date>(doc, packet);
-      break;
-    case XFA_Element::Desc:
-      node = pdfium::MakeUnique<CXFA_Desc>(doc, packet);
-      break;
-    case XFA_Element::Encrypt:
-      node = pdfium::MakeUnique<CXFA_Encrypt>(doc, packet);
-      break;
-    case XFA_Element::Draw:
-      node = pdfium::MakeUnique<CXFA_Draw>(doc, packet);
-      break;
-    case XFA_Element::Encryption:
-      node = pdfium::MakeUnique<CXFA_Encryption>(doc, packet);
-      break;
-    case XFA_Element::MeridiemNames:
-      node = pdfium::MakeUnique<CXFA_MeridiemNames>(doc, packet);
-      break;
-    case XFA_Element::Messaging:
-      node = pdfium::MakeUnique<CXFA_Messaging>(doc, packet);
-      break;
-    case XFA_Element::Speak:
-      node = pdfium::MakeUnique<CXFA_Speak>(doc, packet);
-      break;
-    case XFA_Element::DataGroup:
-      node = pdfium::MakeUnique<CXFA_DataGroup>(doc, packet);
-      break;
-    case XFA_Element::Common:
-      node = pdfium::MakeUnique<CXFA_Common>(doc, packet);
-      break;
-    case XFA_Element::Sharptext:
-      node = pdfium::MakeUnique<CXFA_Sharptext>(doc, packet);
-      break;
-    case XFA_Element::PaginationOverride:
-      node = pdfium::MakeUnique<CXFA_PaginationOverride>(doc, packet);
-      break;
-    case XFA_Element::Reasons:
-      node = pdfium::MakeUnique<CXFA_Reasons>(doc, packet);
-      break;
-    case XFA_Element::SignatureProperties:
-      node = pdfium::MakeUnique<CXFA_SignatureProperties>(doc, packet);
-      break;
-    case XFA_Element::Threshold:
-      node = pdfium::MakeUnique<CXFA_Threshold>(doc, packet);
-      break;
-    case XFA_Element::AppearanceFilter:
-      node = pdfium::MakeUnique<CXFA_AppearanceFilter>(doc, packet);
-      break;
-    case XFA_Element::Fill:
-      node = pdfium::MakeUnique<CXFA_Fill>(doc, packet);
-      break;
-    case XFA_Element::Font:
-      node = pdfium::MakeUnique<CXFA_Font>(doc, packet);
-      break;
-    case XFA_Element::Form:
-      node = pdfium::MakeUnique<CXFA_Form>(doc, packet);
-      break;
-    case XFA_Element::MediumInfo:
-      node = pdfium::MakeUnique<CXFA_MediumInfo>(doc, packet);
-      break;
-    case XFA_Element::Certificate:
-      node = pdfium::MakeUnique<CXFA_Certificate>(doc, packet);
-      break;
-    case XFA_Element::Password:
-      node = pdfium::MakeUnique<CXFA_Password>(doc, packet);
-      break;
-    case XFA_Element::RunScripts:
-      node = pdfium::MakeUnique<CXFA_RunScripts>(doc, packet);
-      break;
-    case XFA_Element::Trace:
-      node = pdfium::MakeUnique<CXFA_Trace>(doc, packet);
-      break;
-    case XFA_Element::Float:
-      node = pdfium::MakeUnique<CXFA_Float>(doc, packet);
-      break;
-    case XFA_Element::RenderPolicy:
-      node = pdfium::MakeUnique<CXFA_RenderPolicy>(doc, packet);
-      break;
-    case XFA_Element::Destination:
-      node = pdfium::MakeUnique<CXFA_Destination>(doc, packet);
-      break;
-    case XFA_Element::Value:
-      node = pdfium::MakeUnique<CXFA_Value>(doc, packet);
-      break;
-    case XFA_Element::Bookend:
-      node = pdfium::MakeUnique<CXFA_Bookend>(doc, packet);
-      break;
-    case XFA_Element::ExObject:
-      node = pdfium::MakeUnique<CXFA_ExObject>(doc, packet);
-      break;
-    case XFA_Element::OpenAction:
-      node = pdfium::MakeUnique<CXFA_OpenAction>(doc, packet);
-      break;
-    case XFA_Element::NeverEmbed:
-      node = pdfium::MakeUnique<CXFA_NeverEmbed>(doc, packet);
-      break;
-    case XFA_Element::BindItems:
-      node = pdfium::MakeUnique<CXFA_BindItems>(doc, packet);
-      break;
-    case XFA_Element::Calculate:
-      node = pdfium::MakeUnique<CXFA_Calculate>(doc, packet);
-      break;
-    case XFA_Element::Print:
-      node = pdfium::MakeUnique<CXFA_Print>(doc, packet);
-      break;
-    case XFA_Element::Extras:
-      node = pdfium::MakeUnique<CXFA_Extras>(doc, packet);
-      break;
-    case XFA_Element::Proto:
-      node = pdfium::MakeUnique<CXFA_Proto>(doc, packet);
-      break;
-    case XFA_Element::DSigData:
-      node = pdfium::MakeUnique<CXFA_DSigData>(doc, packet);
-      break;
-    case XFA_Element::Creator:
-      node = pdfium::MakeUnique<CXFA_Creator>(doc, packet);
-      break;
-    case XFA_Element::Connect:
-      node = pdfium::MakeUnique<CXFA_Connect>(doc, packet);
-      break;
-    case XFA_Element::Permissions:
-      node = pdfium::MakeUnique<CXFA_Permissions>(doc, packet);
-      break;
-    case XFA_Element::ConnectionSet:
-      node = pdfium::MakeUnique<CXFA_ConnectionSet>(doc, packet);
-      break;
-    case XFA_Element::Submit:
-      node = pdfium::MakeUnique<CXFA_Submit>(doc, packet);
-      break;
-    case XFA_Element::Range:
-      node = pdfium::MakeUnique<CXFA_Range>(doc, packet);
-      break;
-    case XFA_Element::Linearized:
-      node = pdfium::MakeUnique<CXFA_Linearized>(doc, packet);
-      break;
-    case XFA_Element::Packet:
-      node = pdfium::MakeUnique<CXFA_Packet>(doc, packet);
-      break;
-    case XFA_Element::RootElement:
-      node = pdfium::MakeUnique<CXFA_RootElement>(doc, packet);
-      break;
-    case XFA_Element::PlaintextMetadata:
-      node = pdfium::MakeUnique<CXFA_PlaintextMetadata>(doc, packet);
-      break;
-    case XFA_Element::NumberSymbols:
-      node = pdfium::MakeUnique<CXFA_NumberSymbols>(doc, packet);
-      break;
-    case XFA_Element::PrintHighQuality:
-      node = pdfium::MakeUnique<CXFA_PrintHighQuality>(doc, packet);
-      break;
-    case XFA_Element::Driver:
-      node = pdfium::MakeUnique<CXFA_Driver>(doc, packet);
-      break;
-    case XFA_Element::IncrementalLoad:
-      node = pdfium::MakeUnique<CXFA_IncrementalLoad>(doc, packet);
-      break;
-    case XFA_Element::SubjectDN:
-      node = pdfium::MakeUnique<CXFA_SubjectDN>(doc, packet);
-      break;
-    case XFA_Element::CompressLogicalStructure:
-      node = pdfium::MakeUnique<CXFA_CompressLogicalStructure>(doc, packet);
-      break;
-    case XFA_Element::IncrementalMerge:
-      node = pdfium::MakeUnique<CXFA_IncrementalMerge>(doc, packet);
-      break;
-    case XFA_Element::Radial:
-      node = pdfium::MakeUnique<CXFA_Radial>(doc, packet);
-      break;
-    case XFA_Element::Variables:
-      node = pdfium::MakeUnique<CXFA_Variables>(doc, packet);
-      break;
-    case XFA_Element::TimePatterns:
-      node = pdfium::MakeUnique<CXFA_TimePatterns>(doc, packet);
-      break;
-    case XFA_Element::EffectiveInputPolicy:
-      node = pdfium::MakeUnique<CXFA_EffectiveInputPolicy>(doc, packet);
-      break;
-    case XFA_Element::NameAttr:
-      node = pdfium::MakeUnique<CXFA_NameAttr>(doc, packet);
-      break;
-    case XFA_Element::Conformance:
-      node = pdfium::MakeUnique<CXFA_Conformance>(doc, packet);
-      break;
-    case XFA_Element::Transform:
-      node = pdfium::MakeUnique<CXFA_Transform>(doc, packet);
-      break;
-    case XFA_Element::LockDocument:
-      node = pdfium::MakeUnique<CXFA_LockDocument>(doc, packet);
-      break;
-    case XFA_Element::BreakAfter:
-      node = pdfium::MakeUnique<CXFA_BreakAfter>(doc, packet);
-      break;
-    case XFA_Element::Line:
-      node = pdfium::MakeUnique<CXFA_Line>(doc, packet);
-      break;
-    case XFA_Element::Source:
-      node = pdfium::MakeUnique<CXFA_Source>(doc, packet);
-      break;
-    case XFA_Element::Occur:
-      node = pdfium::MakeUnique<CXFA_Occur>(doc, packet);
-      break;
-    case XFA_Element::PickTrayByPDFSize:
-      node = pdfium::MakeUnique<CXFA_PickTrayByPDFSize>(doc, packet);
-      break;
-    case XFA_Element::MonthNames:
-      node = pdfium::MakeUnique<CXFA_MonthNames>(doc, packet);
-      break;
-    case XFA_Element::Severity:
-      node = pdfium::MakeUnique<CXFA_Severity>(doc, packet);
-      break;
-    case XFA_Element::GroupParent:
-      node = pdfium::MakeUnique<CXFA_GroupParent>(doc, packet);
-      break;
-    case XFA_Element::DocumentAssembly:
-      node = pdfium::MakeUnique<CXFA_DocumentAssembly>(doc, packet);
-      break;
-    case XFA_Element::NumberSymbol:
-      node = pdfium::MakeUnique<CXFA_NumberSymbol>(doc, packet);
-      break;
-    case XFA_Element::Tagged:
-      node = pdfium::MakeUnique<CXFA_Tagged>(doc, packet);
-      break;
-    case XFA_Element::Items:
-      node = pdfium::MakeUnique<CXFA_Items>(doc, packet);
-      break;
-    default:
-      NOTREACHED();
-      return nullptr;
-  }
-  if (!node || !node->IsValidInPacket(packet))
-    return nullptr;
-  return node;
-}
-
-// static
-WideString CXFA_Node::AttributeToName(XFA_Attribute attr) {
-  switch (attr) {
-    case XFA_Attribute::H:
-      return L"h";
-    case XFA_Attribute::W:
-      return L"w";
-    case XFA_Attribute::X:
-      return L"x";
-    case XFA_Attribute::Y:
-      return L"y";
-    case XFA_Attribute::Id:
-      return L"id";
-    case XFA_Attribute::To:
-      return L"to";
-    case XFA_Attribute::LineThrough:
-      return L"lineThrough";
-    case XFA_Attribute::HAlign:
-      return L"hAlign";
-    case XFA_Attribute::Typeface:
-      return L"typeface";
-    case XFA_Attribute::BeforeTarget:
-      return L"beforeTarget";
-    case XFA_Attribute::Name:
-      return L"name";
-    case XFA_Attribute::Next:
-      return L"next";
-    case XFA_Attribute::DataRowCount:
-      return L"dataRowCount";
-    case XFA_Attribute::Break:
-      return L"break";
-    case XFA_Attribute::VScrollPolicy:
-      return L"vScrollPolicy";
-    case XFA_Attribute::FontHorizontalScale:
-      return L"fontHorizontalScale";
-    case XFA_Attribute::TextIndent:
-      return L"textIndent";
-    case XFA_Attribute::Context:
-      return L"context";
-    case XFA_Attribute::TrayOut:
-      return L"trayOut";
-    case XFA_Attribute::Cap:
-      return L"cap";
-    case XFA_Attribute::Max:
-      return L"max";
-    case XFA_Attribute::Min:
-      return L"min";
-    case XFA_Attribute::Ref:
-      return L"ref";
-    case XFA_Attribute::Rid:
-      return L"rid";
-    case XFA_Attribute::Url:
-      return L"url";
-    case XFA_Attribute::Use:
-      return L"use";
-    case XFA_Attribute::LeftInset:
-      return L"leftInset";
-    case XFA_Attribute::Widows:
-      return L"widows";
-    case XFA_Attribute::Level:
-      return L"level";
-    case XFA_Attribute::BottomInset:
-      return L"bottomInset";
-    case XFA_Attribute::OverflowTarget:
-      return L"overflowTarget";
-    case XFA_Attribute::AllowMacro:
-      return L"allowMacro";
-    case XFA_Attribute::PagePosition:
-      return L"pagePosition";
-    case XFA_Attribute::ColumnWidths:
-      return L"columnWidths";
-    case XFA_Attribute::OverflowLeader:
-      return L"overflowLeader";
-    case XFA_Attribute::Action:
-      return L"action";
-    case XFA_Attribute::NonRepudiation:
-      return L"nonRepudiation";
-    case XFA_Attribute::Rate:
-      return L"rate";
-    case XFA_Attribute::AllowRichText:
-      return L"allowRichText";
-    case XFA_Attribute::Role:
-      return L"role";
-    case XFA_Attribute::OverflowTrailer:
-      return L"overflowTrailer";
-    case XFA_Attribute::Operation:
-      return L"operation";
-    case XFA_Attribute::Timeout:
-      return L"timeout";
-    case XFA_Attribute::TopInset:
-      return L"topInset";
-    case XFA_Attribute::Access:
-      return L"access";
-    case XFA_Attribute::CommandType:
-      return L"commandType";
-    case XFA_Attribute::Format:
-      return L"format";
-    case XFA_Attribute::DataPrep:
-      return L"dataPrep";
-    case XFA_Attribute::WidgetData:
-      return L"widgetData";
-    case XFA_Attribute::Abbr:
-      return L"abbr";
-    case XFA_Attribute::MarginRight:
-      return L"marginRight";
-    case XFA_Attribute::DataDescription:
-      return L"dataDescription";
-    case XFA_Attribute::EncipherOnly:
-      return L"encipherOnly";
-    case XFA_Attribute::KerningMode:
-      return L"kerningMode";
-    case XFA_Attribute::Rotate:
-      return L"rotate";
-    case XFA_Attribute::WordCharacterCount:
-      return L"wordCharacterCount";
-    case XFA_Attribute::Type:
-      return L"type";
-    case XFA_Attribute::Reserve:
-      return L"reserve";
-    case XFA_Attribute::TextLocation:
-      return L"textLocation";
-    case XFA_Attribute::Priority:
-      return L"priority";
-    case XFA_Attribute::Underline:
-      return L"underline";
-    case XFA_Attribute::ModuleWidth:
-      return L"moduleWidth";
-    case XFA_Attribute::Hyphenate:
-      return L"hyphenate";
-    case XFA_Attribute::Listen:
-      return L"listen";
-    case XFA_Attribute::Delimiter:
-      return L"delimiter";
-    case XFA_Attribute::ContentType:
-      return L"contentType";
-    case XFA_Attribute::StartNew:
-      return L"startNew";
-    case XFA_Attribute::EofAction:
-      return L"eofAction";
-    case XFA_Attribute::AllowNeutral:
-      return L"allowNeutral";
-    case XFA_Attribute::Connection:
-      return L"connection";
-    case XFA_Attribute::BaselineShift:
-      return L"baselineShift";
-    case XFA_Attribute::OverlinePeriod:
-      return L"overlinePeriod";
-    case XFA_Attribute::FracDigits:
-      return L"fracDigits";
-    case XFA_Attribute::Orientation:
-      return L"orientation";
-    case XFA_Attribute::TimeStamp:
-      return L"timeStamp";
-    case XFA_Attribute::PrintCheckDigit:
-      return L"printCheckDigit";
-    case XFA_Attribute::MarginLeft:
-      return L"marginLeft";
-    case XFA_Attribute::Stroke:
-      return L"stroke";
-    case XFA_Attribute::ModuleHeight:
-      return L"moduleHeight";
-    case XFA_Attribute::TransferEncoding:
-      return L"transferEncoding";
-    case XFA_Attribute::Usage:
-      return L"usage";
-    case XFA_Attribute::Presence:
-      return L"presence";
-    case XFA_Attribute::RadixOffset:
-      return L"radixOffset";
-    case XFA_Attribute::Preserve:
-      return L"preserve";
-    case XFA_Attribute::AliasNode:
-      return L"aliasNode";
-    case XFA_Attribute::MultiLine:
-      return L"multiLine";
-    case XFA_Attribute::Version:
-      return L"version";
-    case XFA_Attribute::StartChar:
-      return L"startChar";
-    case XFA_Attribute::ScriptTest:
-      return L"scriptTest";
-    case XFA_Attribute::StartAngle:
-      return L"startAngle";
-    case XFA_Attribute::CursorType:
-      return L"cursorType";
-    case XFA_Attribute::DigitalSignature:
-      return L"digitalSignature";
-    case XFA_Attribute::CodeType:
-      return L"codeType";
-    case XFA_Attribute::Output:
-      return L"output";
-    case XFA_Attribute::BookendTrailer:
-      return L"bookendTrailer";
-    case XFA_Attribute::ImagingBBox:
-      return L"imagingBBox";
-    case XFA_Attribute::ExcludeInitialCap:
-      return L"excludeInitialCap";
-    case XFA_Attribute::Force:
-      return L"force";
-    case XFA_Attribute::CrlSign:
-      return L"crlSign";
-    case XFA_Attribute::Previous:
-      return L"previous";
-    case XFA_Attribute::PushCharacterCount:
-      return L"pushCharacterCount";
-    case XFA_Attribute::NullTest:
-      return L"nullTest";
-    case XFA_Attribute::RunAt:
-      return L"runAt";
-    case XFA_Attribute::SpaceBelow:
-      return L"spaceBelow";
-    case XFA_Attribute::SweepAngle:
-      return L"sweepAngle";
-    case XFA_Attribute::NumberOfCells:
-      return L"numberOfCells";
-    case XFA_Attribute::LetterSpacing:
-      return L"letterSpacing";
-    case XFA_Attribute::LockType:
-      return L"lockType";
-    case XFA_Attribute::PasswordChar:
-      return L"passwordChar";
-    case XFA_Attribute::VAlign:
-      return L"vAlign";
-    case XFA_Attribute::SourceBelow:
-      return L"sourceBelow";
-    case XFA_Attribute::Inverted:
-      return L"inverted";
-    case XFA_Attribute::Mark:
-      return L"mark";
-    case XFA_Attribute::MaxH:
-      return L"maxH";
-    case XFA_Attribute::MaxW:
-      return L"maxW";
-    case XFA_Attribute::Truncate:
-      return L"truncate";
-    case XFA_Attribute::MinH:
-      return L"minH";
-    case XFA_Attribute::MinW:
-      return L"minW";
-    case XFA_Attribute::Initial:
-      return L"initial";
-    case XFA_Attribute::Mode:
-      return L"mode";
-    case XFA_Attribute::Layout:
-      return L"layout";
-    case XFA_Attribute::Server:
-      return L"server";
-    case XFA_Attribute::EmbedPDF:
-      return L"embedPDF";
-    case XFA_Attribute::OddOrEven:
-      return L"oddOrEven";
-    case XFA_Attribute::TabDefault:
-      return L"tabDefault";
-    case XFA_Attribute::Contains:
-      return L"contains";
-    case XFA_Attribute::RightInset:
-      return L"rightInset";
-    case XFA_Attribute::MaxChars:
-      return L"maxChars";
-    case XFA_Attribute::Open:
-      return L"open";
-    case XFA_Attribute::Relation:
-      return L"relation";
-    case XFA_Attribute::WideNarrowRatio:
-      return L"wideNarrowRatio";
-    case XFA_Attribute::Relevant:
-      return L"relevant";
-    case XFA_Attribute::SignatureType:
-      return L"signatureType";
-    case XFA_Attribute::LineThroughPeriod:
-      return L"lineThroughPeriod";
-    case XFA_Attribute::Shape:
-      return L"shape";
-    case XFA_Attribute::TabStops:
-      return L"tabStops";
-    case XFA_Attribute::OutputBelow:
-      return L"outputBelow";
-    case XFA_Attribute::Short:
-      return L"short";
-    case XFA_Attribute::FontVerticalScale:
-      return L"fontVerticalScale";
-    case XFA_Attribute::Thickness:
-      return L"thickness";
-    case XFA_Attribute::CommitOn:
-      return L"commitOn";
-    case XFA_Attribute::RemainCharacterCount:
-      return L"remainCharacterCount";
-    case XFA_Attribute::KeyAgreement:
-      return L"keyAgreement";
-    case XFA_Attribute::ErrorCorrectionLevel:
-      return L"errorCorrectionLevel";
-    case XFA_Attribute::UpsMode:
-      return L"upsMode";
-    case XFA_Attribute::MergeMode:
-      return L"mergeMode";
-    case XFA_Attribute::Circular:
-      return L"circular";
-    case XFA_Attribute::PsName:
-      return L"psName";
-    case XFA_Attribute::Trailer:
-      return L"trailer";
-    case XFA_Attribute::UnicodeRange:
-      return L"unicodeRange";
-    case XFA_Attribute::ExecuteType:
-      return L"executeType";
-    case XFA_Attribute::DuplexImposition:
-      return L"duplexImposition";
-    case XFA_Attribute::TrayIn:
-      return L"trayIn";
-    case XFA_Attribute::BindingNode:
-      return L"bindingNode";
-    case XFA_Attribute::BofAction:
-      return L"bofAction";
-    case XFA_Attribute::Save:
-      return L"save";
-    case XFA_Attribute::TargetType:
-      return L"targetType";
-    case XFA_Attribute::KeyEncipherment:
-      return L"keyEncipherment";
-    case XFA_Attribute::CredentialServerPolicy:
-      return L"credentialServerPolicy";
-    case XFA_Attribute::Size:
-      return L"size";
-    case XFA_Attribute::InitialNumber:
-      return L"initialNumber";
-    case XFA_Attribute::Slope:
-      return L"slope";
-    case XFA_Attribute::CSpace:
-      return L"cSpace";
-    case XFA_Attribute::ColSpan:
-      return L"colSpan";
-    case XFA_Attribute::Binding:
-      return L"binding";
-    case XFA_Attribute::Checksum:
-      return L"checksum";
-    case XFA_Attribute::CharEncoding:
-      return L"charEncoding";
-    case XFA_Attribute::Bind:
-      return L"bind";
-    case XFA_Attribute::TextEntry:
-      return L"textEntry";
-    case XFA_Attribute::Archive:
-      return L"archive";
-    case XFA_Attribute::Uuid:
-      return L"uuid";
-    case XFA_Attribute::Posture:
-      return L"posture";
-    case XFA_Attribute::After:
-      return L"after";
-    case XFA_Attribute::Orphans:
-      return L"orphans";
-    case XFA_Attribute::QualifiedName:
-      return L"qualifiedName";
-    case XFA_Attribute::Usehref:
-      return L"usehref";
-    case XFA_Attribute::Locale:
-      return L"locale";
-    case XFA_Attribute::Weight:
-      return L"weight";
-    case XFA_Attribute::UnderlinePeriod:
-      return L"underlinePeriod";
-    case XFA_Attribute::Data:
-      return L"data";
-    case XFA_Attribute::Desc:
-      return L"desc";
-    case XFA_Attribute::Numbered:
-      return L"numbered";
-    case XFA_Attribute::DataColumnCount:
-      return L"dataColumnCount";
-    case XFA_Attribute::Overline:
-      return L"overline";
-    case XFA_Attribute::UrlPolicy:
-      return L"urlPolicy";
-    case XFA_Attribute::AnchorType:
-      return L"anchorType";
-    case XFA_Attribute::LabelRef:
-      return L"labelRef";
-    case XFA_Attribute::BookendLeader:
-      return L"bookendLeader";
-    case XFA_Attribute::MaxLength:
-      return L"maxLength";
-    case XFA_Attribute::AccessKey:
-      return L"accessKey";
-    case XFA_Attribute::CursorLocation:
-      return L"cursorLocation";
-    case XFA_Attribute::DelayedOpen:
-      return L"delayedOpen";
-    case XFA_Attribute::Target:
-      return L"target";
-    case XFA_Attribute::DataEncipherment:
-      return L"dataEncipherment";
-    case XFA_Attribute::AfterTarget:
-      return L"afterTarget";
-    case XFA_Attribute::Leader:
-      return L"leader";
-    case XFA_Attribute::Picker:
-      return L"picker";
-    case XFA_Attribute::From:
-      return L"from";
-    case XFA_Attribute::BaseProfile:
-      return L"baseProfile";
-    case XFA_Attribute::Aspect:
-      return L"aspect";
-    case XFA_Attribute::RowColumnRatio:
-      return L"rowColumnRatio";
-    case XFA_Attribute::LineHeight:
-      return L"lineHeight";
-    case XFA_Attribute::Highlight:
-      return L"highlight";
-    case XFA_Attribute::ValueRef:
-      return L"valueRef";
-    case XFA_Attribute::MaxEntries:
-      return L"maxEntries";
-    case XFA_Attribute::DataLength:
-      return L"dataLength";
-    case XFA_Attribute::Activity:
-      return L"activity";
-    case XFA_Attribute::Input:
-      return L"input";
-    case XFA_Attribute::Value:
-      return L"value";
-    case XFA_Attribute::BlankOrNotBlank:
-      return L"blankOrNotBlank";
-    case XFA_Attribute::AddRevocationInfo:
-      return L"addRevocationInfo";
-    case XFA_Attribute::GenericFamily:
-      return L"genericFamily";
-    case XFA_Attribute::Hand:
-      return L"hand";
-    case XFA_Attribute::Href:
-      return L"href";
-    case XFA_Attribute::TextEncoding:
-      return L"textEncoding";
-    case XFA_Attribute::LeadDigits:
-      return L"leadDigits";
-    case XFA_Attribute::Permissions:
-      return L"permissions";
-    case XFA_Attribute::SpaceAbove:
-      return L"spaceAbove";
-    case XFA_Attribute::CodeBase:
-      return L"codeBase";
-    case XFA_Attribute::Stock:
-      return L"stock";
-    case XFA_Attribute::IsNull:
-      return L"isNull";
-    case XFA_Attribute::RestoreState:
-      return L"restoreState";
-    case XFA_Attribute::ExcludeAllCaps:
-      return L"excludeAllCaps";
-    case XFA_Attribute::FormatTest:
-      return L"formatTest";
-    case XFA_Attribute::HScrollPolicy:
-      return L"hScrollPolicy";
-    case XFA_Attribute::Join:
-      return L"join";
-    case XFA_Attribute::KeyCertSign:
-      return L"keyCertSign";
-    case XFA_Attribute::Radius:
-      return L"radius";
-    case XFA_Attribute::SourceAbove:
-      return L"sourceAbove";
-    case XFA_Attribute::Override:
-      return L"override";
-    case XFA_Attribute::ClassId:
-      return L"classId";
-    case XFA_Attribute::Disable:
-      return L"disable";
-    case XFA_Attribute::Scope:
-      return L"scope";
-    case XFA_Attribute::Match:
-      return L"match";
-    case XFA_Attribute::Placement:
-      return L"placement";
-    case XFA_Attribute::Before:
-      return L"before";
-    case XFA_Attribute::WritingScript:
-      return L"writingScript";
-    case XFA_Attribute::EndChar:
-      return L"endChar";
-    case XFA_Attribute::Lock:
-      return L"lock";
-    case XFA_Attribute::Long:
-      return L"long";
-    case XFA_Attribute::Intact:
-      return L"intact";
-    case XFA_Attribute::XdpContent:
-      return L"xdpContent";
-    case XFA_Attribute::DecipherOnly:
-      return L"decipherOnly";
-
-    default:
-      NOTREACHED();
-      break;
-  }
-  return L"";
-}
-
-#ifndef NDEBUG
-// static
-WideString CXFA_Node::ElementToName(XFA_Element attr) {
-  switch (attr) {
-    case XFA_Element::Ps:
-      return L"ps";
-    case XFA_Element::To:
-      return L"to";
-    case XFA_Element::Ui:
-      return L"ui";
-    case XFA_Element::RecordSet:
-      return L"recordSet";
-    case XFA_Element::SubsetBelow:
-      return L"subsetBelow";
-    case XFA_Element::SubformSet:
-      return L"subformSet";
-    case XFA_Element::AdobeExtensionLevel:
-      return L"adobeExtensionLevel";
-    case XFA_Element::Typeface:
-      return L"typeface";
-    case XFA_Element::Break:
-      return L"break";
-    case XFA_Element::FontInfo:
-      return L"fontInfo";
-    case XFA_Element::NumberPattern:
-      return L"numberPattern";
-    case XFA_Element::DynamicRender:
-      return L"dynamicRender";
-    case XFA_Element::PrintScaling:
-      return L"printScaling";
-    case XFA_Element::CheckButton:
-      return L"checkButton";
-    case XFA_Element::DatePatterns:
-      return L"datePatterns";
-    case XFA_Element::SourceSet:
-      return L"sourceSet";
-    case XFA_Element::Amd:
-      return L"amd";
-    case XFA_Element::Arc:
-      return L"arc";
-    case XFA_Element::Day:
-      return L"day";
-    case XFA_Element::Era:
-      return L"era";
-    case XFA_Element::Jog:
-      return L"jog";
-    case XFA_Element::Log:
-      return L"log";
-    case XFA_Element::Map:
-      return L"map";
-    case XFA_Element::Mdp:
-      return L"mdp";
-    case XFA_Element::BreakBefore:
-      return L"breakBefore";
-    case XFA_Element::Oid:
-      return L"oid";
-    case XFA_Element::Pcl:
-      return L"pcl";
-    case XFA_Element::Pdf:
-      return L"pdf";
-    case XFA_Element::Ref:
-      return L"ref";
-    case XFA_Element::Uri:
-      return L"uri";
-    case XFA_Element::Xdc:
-      return L"xdc";
-    case XFA_Element::Xdp:
-      return L"xdp";
-    case XFA_Element::Xfa:
-      return L"xfa";
-    case XFA_Element::Xsl:
-      return L"xsl";
-    case XFA_Element::Zpl:
-      return L"zpl";
-    case XFA_Element::Cache:
-      return L"cache";
-    case XFA_Element::Margin:
-      return L"margin";
-    case XFA_Element::KeyUsage:
-      return L"keyUsage";
-    case XFA_Element::Exclude:
-      return L"exclude";
-    case XFA_Element::ChoiceList:
-      return L"choiceList";
-    case XFA_Element::Level:
-      return L"level";
-    case XFA_Element::LabelPrinter:
-      return L"labelPrinter";
-    case XFA_Element::CalendarSymbols:
-      return L"calendarSymbols";
-    case XFA_Element::Para:
-      return L"para";
-    case XFA_Element::Part:
-      return L"part";
-    case XFA_Element::Pdfa:
-      return L"pdfa";
-    case XFA_Element::Filter:
-      return L"filter";
-    case XFA_Element::Present:
-      return L"present";
-    case XFA_Element::Pagination:
-      return L"pagination";
-    case XFA_Element::Encoding:
-      return L"encoding";
-    case XFA_Element::Event:
-      return L"event";
-    case XFA_Element::Whitespace:
-      return L"whitespace";
-    case XFA_Element::DefaultUi:
-      return L"defaultUi";
-    case XFA_Element::DataModel:
-      return L"dataModel";
-    case XFA_Element::Barcode:
-      return L"barcode";
-    case XFA_Element::TimePattern:
-      return L"timePattern";
-    case XFA_Element::BatchOutput:
-      return L"batchOutput";
-    case XFA_Element::Enforce:
-      return L"enforce";
-    case XFA_Element::CurrencySymbols:
-      return L"currencySymbols";
-    case XFA_Element::AddSilentPrint:
-      return L"addSilentPrint";
-    case XFA_Element::Rename:
-      return L"rename";
-    case XFA_Element::Operation:
-      return L"operation";
-    case XFA_Element::Typefaces:
-      return L"typefaces";
-    case XFA_Element::SubjectDNs:
-      return L"subjectDNs";
-    case XFA_Element::Issuers:
-      return L"issuers";
-    case XFA_Element::WsdlConnection:
-      return L"wsdlConnection";
-    case XFA_Element::Debug:
-      return L"debug";
-    case XFA_Element::Delta:
-      return L"delta";
-    case XFA_Element::EraNames:
-      return L"eraNames";
-    case XFA_Element::ModifyAnnots:
-      return L"modifyAnnots";
-    case XFA_Element::StartNode:
-      return L"startNode";
-    case XFA_Element::Button:
-      return L"button";
-    case XFA_Element::Format:
-      return L"format";
-    case XFA_Element::Border:
-      return L"border";
-    case XFA_Element::Area:
-      return L"area";
-    case XFA_Element::Hyphenation:
-      return L"hyphenation";
-    case XFA_Element::Text:
-      return L"text";
-    case XFA_Element::Time:
-      return L"time";
-    case XFA_Element::Type:
-      return L"type";
-    case XFA_Element::Overprint:
-      return L"overprint";
-    case XFA_Element::Certificates:
-      return L"certificates";
-    case XFA_Element::EncryptionMethods:
-      return L"encryptionMethods";
-    case XFA_Element::SetProperty:
-      return L"setProperty";
-    case XFA_Element::PrinterName:
-      return L"printerName";
-    case XFA_Element::StartPage:
-      return L"startPage";
-    case XFA_Element::PageOffset:
-      return L"pageOffset";
-    case XFA_Element::DateTime:
-      return L"dateTime";
-    case XFA_Element::Comb:
-      return L"comb";
-    case XFA_Element::Pattern:
-      return L"pattern";
-    case XFA_Element::IfEmpty:
-      return L"ifEmpty";
-    case XFA_Element::SuppressBanner:
-      return L"suppressBanner";
-    case XFA_Element::OutputBin:
-      return L"outputBin";
-    case XFA_Element::Field:
-      return L"field";
-    case XFA_Element::Agent:
-      return L"agent";
-    case XFA_Element::OutputXSL:
-      return L"outputXSL";
-    case XFA_Element::AdjustData:
-      return L"adjustData";
-    case XFA_Element::AutoSave:
-      return L"autoSave";
-    case XFA_Element::ContentArea:
-      return L"contentArea";
-    case XFA_Element::WsdlAddress:
-      return L"wsdlAddress";
-    case XFA_Element::Solid:
-      return L"solid";
-    case XFA_Element::DateTimeSymbols:
-      return L"dateTimeSymbols";
-    case XFA_Element::EncryptionLevel:
-      return L"encryptionLevel";
-    case XFA_Element::Edge:
-      return L"edge";
-    case XFA_Element::Stipple:
-      return L"stipple";
-    case XFA_Element::Attributes:
-      return L"attributes";
-    case XFA_Element::VersionControl:
-      return L"versionControl";
-    case XFA_Element::Meridiem:
-      return L"meridiem";
-    case XFA_Element::ExclGroup:
-      return L"exclGroup";
-    case XFA_Element::ToolTip:
-      return L"toolTip";
-    case XFA_Element::Compress:
-      return L"compress";
-    case XFA_Element::Reason:
-      return L"reason";
-    case XFA_Element::Execute:
-      return L"execute";
-    case XFA_Element::ContentCopy:
-      return L"contentCopy";
-    case XFA_Element::DateTimeEdit:
-      return L"dateTimeEdit";
-    case XFA_Element::Config:
-      return L"config";
-    case XFA_Element::Image:
-      return L"image";
-    case XFA_Element::SharpxHTML:
-      return L"#xHTML";
-    case XFA_Element::NumberOfCopies:
-      return L"numberOfCopies";
-    case XFA_Element::BehaviorOverride:
-      return L"behaviorOverride";
-    case XFA_Element::TimeStamp:
-      return L"timeStamp";
-    case XFA_Element::Month:
-      return L"month";
-    case XFA_Element::ViewerPreferences:
-      return L"viewerPreferences";
-    case XFA_Element::ScriptModel:
-      return L"scriptModel";
-    case XFA_Element::Decimal:
-      return L"decimal";
-    case XFA_Element::Subform:
-      return L"subform";
-    case XFA_Element::Select:
-      return L"select";
-    case XFA_Element::Window:
-      return L"window";
-    case XFA_Element::LocaleSet:
-      return L"localeSet";
-    case XFA_Element::Handler:
-      return L"handler";
-    case XFA_Element::Presence:
-      return L"presence";
-    case XFA_Element::Record:
-      return L"record";
-    case XFA_Element::Embed:
-      return L"embed";
-    case XFA_Element::Version:
-      return L"version";
-    case XFA_Element::Command:
-      return L"command";
-    case XFA_Element::Copies:
-      return L"copies";
-    case XFA_Element::Staple:
-      return L"staple";
-    case XFA_Element::SubmitFormat:
-      return L"submitFormat";
-    case XFA_Element::Boolean:
-      return L"boolean";
-    case XFA_Element::Message:
-      return L"message";
-    case XFA_Element::Output:
-      return L"output";
-    case XFA_Element::PsMap:
-      return L"psMap";
-    case XFA_Element::ExcludeNS:
-      return L"excludeNS";
-    case XFA_Element::Assist:
-      return L"assist";
-    case XFA_Element::Picture:
-      return L"picture";
-    case XFA_Element::Traversal:
-      return L"traversal";
-    case XFA_Element::SilentPrint:
-      return L"silentPrint";
-    case XFA_Element::WebClient:
-      return L"webClient";
-    case XFA_Element::Producer:
-      return L"producer";
-    case XFA_Element::Corner:
-      return L"corner";
-    case XFA_Element::MsgId:
-      return L"msgId";
-    case XFA_Element::Color:
-      return L"color";
-    case XFA_Element::Keep:
-      return L"keep";
-    case XFA_Element::Query:
-      return L"query";
-    case XFA_Element::Insert:
-      return L"insert";
-    case XFA_Element::ImageEdit:
-      return L"imageEdit";
-    case XFA_Element::Validate:
-      return L"validate";
-    case XFA_Element::DigestMethods:
-      return L"digestMethods";
-    case XFA_Element::NumberPatterns:
-      return L"numberPatterns";
-    case XFA_Element::PageSet:
-      return L"pageSet";
-    case XFA_Element::Integer:
-      return L"integer";
-    case XFA_Element::SoapAddress:
-      return L"soapAddress";
-    case XFA_Element::Equate:
-      return L"equate";
-    case XFA_Element::FormFieldFilling:
-      return L"formFieldFilling";
-    case XFA_Element::PageRange:
-      return L"pageRange";
-    case XFA_Element::Update:
-      return L"update";
-    case XFA_Element::ConnectString:
-      return L"connectString";
-    case XFA_Element::Mode:
-      return L"mode";
-    case XFA_Element::Layout:
-      return L"layout";
-    case XFA_Element::Sharpxml:
-      return L"#xml";
-    case XFA_Element::XsdConnection:
-      return L"xsdConnection";
-    case XFA_Element::Traverse:
-      return L"traverse";
-    case XFA_Element::Encodings:
-      return L"encodings";
-    case XFA_Element::Template:
-      return L"template";
-    case XFA_Element::Acrobat:
-      return L"acrobat";
-    case XFA_Element::ValidationMessaging:
-      return L"validationMessaging";
-    case XFA_Element::Signing:
-      return L"signing";
-    case XFA_Element::Script:
-      return L"script";
-    case XFA_Element::AddViewerPreferences:
-      return L"addViewerPreferences";
-    case XFA_Element::AlwaysEmbed:
-      return L"alwaysEmbed";
-    case XFA_Element::PasswordEdit:
-      return L"passwordEdit";
-    case XFA_Element::NumericEdit:
-      return L"numericEdit";
-    case XFA_Element::EncryptionMethod:
-      return L"encryptionMethod";
-    case XFA_Element::Change:
-      return L"change";
-    case XFA_Element::PageArea:
-      return L"pageArea";
-    case XFA_Element::SubmitUrl:
-      return L"submitUrl";
-    case XFA_Element::Oids:
-      return L"oids";
-    case XFA_Element::Signature:
-      return L"signature";
-    case XFA_Element::ADBE_JSConsole:
-      return L"ADBE_JSConsole";
-    case XFA_Element::Caption:
-      return L"caption";
-    case XFA_Element::Relevant:
-      return L"relevant";
-    case XFA_Element::FlipLabel:
-      return L"flipLabel";
-    case XFA_Element::ExData:
-      return L"exData";
-    case XFA_Element::DayNames:
-      return L"dayNames";
-    case XFA_Element::SoapAction:
-      return L"soapAction";
-    case XFA_Element::DefaultTypeface:
-      return L"defaultTypeface";
-    case XFA_Element::Manifest:
-      return L"manifest";
-    case XFA_Element::Overflow:
-      return L"overflow";
-    case XFA_Element::Linear:
-      return L"linear";
-    case XFA_Element::CurrencySymbol:
-      return L"currencySymbol";
-    case XFA_Element::Delete:
-      return L"delete";
-    case XFA_Element::Deltas:
-      return L"deltas";
-    case XFA_Element::DigestMethod:
-      return L"digestMethod";
-    case XFA_Element::InstanceManager:
-      return L"instanceManager";
-    case XFA_Element::EquateRange:
-      return L"equateRange";
-    case XFA_Element::Medium:
-      return L"medium";
-    case XFA_Element::TextEdit:
-      return L"textEdit";
-    case XFA_Element::TemplateCache:
-      return L"templateCache";
-    case XFA_Element::CompressObjectStream:
-      return L"compressObjectStream";
-    case XFA_Element::DataValue:
-      return L"dataValue";
-    case XFA_Element::AccessibleContent:
-      return L"accessibleContent";
-    case XFA_Element::IncludeXDPContent:
-      return L"includeXDPContent";
-    case XFA_Element::XmlConnection:
-      return L"xmlConnection";
-    case XFA_Element::ValidateApprovalSignatures:
-      return L"validateApprovalSignatures";
-    case XFA_Element::SignData:
-      return L"signData";
-    case XFA_Element::Packets:
-      return L"packets";
-    case XFA_Element::DatePattern:
-      return L"datePattern";
-    case XFA_Element::DuplexOption:
-      return L"duplexOption";
-    case XFA_Element::Base:
-      return L"base";
-    case XFA_Element::Bind:
-      return L"bind";
-    case XFA_Element::Compression:
-      return L"compression";
-    case XFA_Element::User:
-      return L"user";
-    case XFA_Element::Rectangle:
-      return L"rectangle";
-    case XFA_Element::EffectiveOutputPolicy:
-      return L"effectiveOutputPolicy";
-    case XFA_Element::ADBE_JSDebugger:
-      return L"ADBE_JSDebugger";
-    case XFA_Element::Acrobat7:
-      return L"acrobat7";
-    case XFA_Element::Interactive:
-      return L"interactive";
-    case XFA_Element::Locale:
-      return L"locale";
-    case XFA_Element::CurrentPage:
-      return L"currentPage";
-    case XFA_Element::Data:
-      return L"data";
-    case XFA_Element::Date:
-      return L"date";
-    case XFA_Element::Desc:
-      return L"desc";
-    case XFA_Element::Encrypt:
-      return L"encrypt";
-    case XFA_Element::Draw:
-      return L"draw";
-    case XFA_Element::Encryption:
-      return L"encryption";
-    case XFA_Element::MeridiemNames:
-      return L"meridiemNames";
-    case XFA_Element::Messaging:
-      return L"messaging";
-    case XFA_Element::Speak:
-      return L"speak";
-    case XFA_Element::DataGroup:
-      return L"dataGroup";
-    case XFA_Element::Common:
-      return L"common";
-    case XFA_Element::Sharptext:
-      return L"#text";
-    case XFA_Element::PaginationOverride:
-      return L"paginationOverride";
-    case XFA_Element::Reasons:
-      return L"reasons";
-    case XFA_Element::SignatureProperties:
-      return L"signatureProperties";
-    case XFA_Element::Threshold:
-      return L"threshold";
-    case XFA_Element::AppearanceFilter:
-      return L"appearanceFilter";
-    case XFA_Element::Fill:
-      return L"fill";
-    case XFA_Element::Font:
-      return L"font";
-    case XFA_Element::Form:
-      return L"form";
-    case XFA_Element::MediumInfo:
-      return L"mediumInfo";
-    case XFA_Element::Certificate:
-      return L"certificate";
-    case XFA_Element::Password:
-      return L"password";
-    case XFA_Element::RunScripts:
-      return L"runScripts";
-    case XFA_Element::Trace:
-      return L"trace";
-    case XFA_Element::Float:
-      return L"float";
-    case XFA_Element::RenderPolicy:
-      return L"renderPolicy";
-    case XFA_Element::Destination:
-      return L"destination";
-    case XFA_Element::Value:
-      return L"value";
-    case XFA_Element::Bookend:
-      return L"bookend";
-    case XFA_Element::ExObject:
-      return L"exObject";
-    case XFA_Element::OpenAction:
-      return L"openAction";
-    case XFA_Element::NeverEmbed:
-      return L"neverEmbed";
-    case XFA_Element::BindItems:
-      return L"bindItems";
-    case XFA_Element::Calculate:
-      return L"calculate";
-    case XFA_Element::Print:
-      return L"print";
-    case XFA_Element::Extras:
-      return L"extras";
-    case XFA_Element::Proto:
-      return L"proto";
-    case XFA_Element::DSigData:
-      return L"dSigData";
-    case XFA_Element::Creator:
-      return L"creator";
-    case XFA_Element::Connect:
-      return L"connect";
-    case XFA_Element::Permissions:
-      return L"permissions";
-    case XFA_Element::ConnectionSet:
-      return L"connectionSet";
-    case XFA_Element::Submit:
-      return L"submit";
-    case XFA_Element::Range:
-      return L"range";
-    case XFA_Element::Linearized:
-      return L"linearized";
-    case XFA_Element::Packet:
-      return L"packet";
-    case XFA_Element::RootElement:
-      return L"rootElement";
-    case XFA_Element::PlaintextMetadata:
-      return L"plaintextMetadata";
-    case XFA_Element::NumberSymbols:
-      return L"numberSymbols";
-    case XFA_Element::PrintHighQuality:
-      return L"printHighQuality";
-    case XFA_Element::Driver:
-      return L"driver";
-    case XFA_Element::IncrementalLoad:
-      return L"incrementalLoad";
-    case XFA_Element::SubjectDN:
-      return L"subjectDN";
-    case XFA_Element::CompressLogicalStructure:
-      return L"compressLogicalStructure";
-    case XFA_Element::IncrementalMerge:
-      return L"incrementalMerge";
-    case XFA_Element::Radial:
-      return L"radial";
-    case XFA_Element::Variables:
-      return L"variables";
-    case XFA_Element::TimePatterns:
-      return L"timePatterns";
-    case XFA_Element::EffectiveInputPolicy:
-      return L"effectiveInputPolicy";
-    case XFA_Element::NameAttr:
-      return L"nameAttr";
-    case XFA_Element::Conformance:
-      return L"conformance";
-    case XFA_Element::Transform:
-      return L"transform";
-    case XFA_Element::LockDocument:
-      return L"lockDocument";
-    case XFA_Element::BreakAfter:
-      return L"breakAfter";
-    case XFA_Element::Line:
-      return L"line";
-    case XFA_Element::Source:
-      return L"source";
-    case XFA_Element::Occur:
-      return L"occur";
-    case XFA_Element::PickTrayByPDFSize:
-      return L"pickTrayByPDFSize";
-    case XFA_Element::MonthNames:
-      return L"monthNames";
-    case XFA_Element::Severity:
-      return L"severity";
-    case XFA_Element::GroupParent:
-      return L"groupParent";
-    case XFA_Element::DocumentAssembly:
-      return L"documentAssembly";
-    case XFA_Element::NumberSymbol:
-      return L"numberSymbol";
-    case XFA_Element::Tagged:
-      return L"tagged";
-    case XFA_Element::Items:
-      return L"items";
-
-    default:
-      NOTREACHED();
-      break;
-  }
-  return L"";
-}
-#endif  // NDEBUG
diff --git a/xfa/fxfa/parser/cxfa_node_unittest.cpp b/xfa/fxfa/parser/cxfa_node_unittest.cpp
index dedef5d..620704f 100644
--- a/xfa/fxfa/parser/cxfa_node_unittest.cpp
+++ b/xfa/fxfa/parser/cxfa_node_unittest.cpp
@@ -4,24 +4,378 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
+#include "fxjs/xfa/cjx_node.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "testing/test_support.h"
+#include "third_party/base/ptr_util.h"
+#include "xfa/fxfa/parser/cxfa_document.h"
 
-TEST(CXFA_NodeTest, NameToAttribute) {
-  EXPECT_EQ(XFA_Attribute::Unknown, CXFA_Node::NameToAttribute(L""));
-  EXPECT_EQ(XFA_Attribute::Unknown, CXFA_Node::NameToAttribute(L"nonesuch"));
-  EXPECT_EQ(XFA_Attribute::H, CXFA_Node::NameToAttribute(L"h"));
-  EXPECT_EQ(XFA_Attribute::Short, CXFA_Node::NameToAttribute(L"short"));
-  EXPECT_EQ(XFA_Attribute::DecipherOnly,
-            CXFA_Node::NameToAttribute(L"decipherOnly"));
+namespace {
+
+class TestNode final : public CXFA_Node {
+ public:
+  explicit TestNode(CXFA_Document* doc)
+      : CXFA_Node(doc,
+                  XFA_PacketType::Form,
+                  (XFA_XDPPACKET_Template | XFA_XDPPACKET_Form),
+                  XFA_ObjectType::Node,
+                  XFA_Element::Node,
+                  {},
+                  {},
+                  pdfium::MakeUnique<CJX_Node>(this)) {}
+
+  ~TestNode() override = default;
+};
+
+}  // namespace
+
+class CXFANodeTest : public testing::Test {
+ public:
+  void SetUp() override {
+    doc_ = pdfium::MakeUnique<CXFA_Document>(nullptr, nullptr);
+    node_ = pdfium::MakeUnique<TestNode>(doc_.get());
+  }
+
+  void TearDown() override {
+    node_ = nullptr;
+    doc_ = nullptr;
+  }
+
+  CXFA_Document* GetDoc() const { return doc_.get(); }
+  CXFA_Node* GetNode() const { return node_.get(); }
+
+ private:
+  std::unique_ptr<CXFA_Document> doc_;
+  std::unique_ptr<TestNode> node_;
+};
+
+TEST_F(CXFANodeTest, InsertFirstChild) {
+  EXPECT_EQ(nullptr, GetNode()->GetFirstChild());
+  EXPECT_EQ(nullptr, GetNode()->GetLastChild());
+
+  CXFA_Node* child =
+      GetDoc()->CreateNode(XFA_PacketType::Form, XFA_Element::Ui);
+  GetNode()->InsertChildAndNotify(-1, child);
+
+  EXPECT_EQ(GetNode(), child->GetParent());
+  EXPECT_EQ(child, GetNode()->GetFirstChild());
+  EXPECT_EQ(child, GetNode()->GetLastChild());
+  EXPECT_EQ(nullptr, child->GetPrevSibling());
+  EXPECT_EQ(nullptr, child->GetNextSibling());
 }
 
-TEST(CXFA_NodeTest, GetAttributeEnumByName) {
-  EXPECT_FALSE(!!CXFA_Node::NameToAttributeEnum(L""));
-  EXPECT_FALSE(!!CXFA_Node::NameToAttributeEnum(L"nonesuch"));
-  EXPECT_EQ(XFA_AttributeEnum::Asterisk, *CXFA_Node::NameToAttributeEnum(L"*"));
-  EXPECT_EQ(XFA_AttributeEnum::Visible,
-            *CXFA_Node::NameToAttributeEnum(L"visible"));
-  EXPECT_EQ(XFA_AttributeEnum::Lowered,
-            *CXFA_Node::NameToAttributeEnum(L"lowered"));
+TEST_F(CXFANodeTest, InsertChildByNegativeIndex) {
+  CXFA_Node* child0 =
+      GetDoc()->CreateNode(XFA_PacketType::Form, XFA_Element::Ui);
+  GetNode()->InsertChildAndNotify(-1, child0);
+
+  CXFA_Node* child =
+      GetDoc()->CreateNode(XFA_PacketType::Form, XFA_Element::Ui);
+  GetNode()->InsertChildAndNotify(-1, child);
+
+  EXPECT_EQ(GetNode(), child->GetParent());
+  EXPECT_EQ(nullptr, child->GetNextSibling());
+  EXPECT_EQ(child0, child->GetPrevSibling());
+  EXPECT_EQ(child, child0->GetNextSibling());
+  EXPECT_EQ(nullptr, child0->GetPrevSibling());
+
+  EXPECT_EQ(child0, GetNode()->GetFirstChild());
+  EXPECT_EQ(child, GetNode()->GetLastChild());
+}
+
+TEST_F(CXFANodeTest, InsertChildByIndex) {
+  CXFA_Node* child0 =
+      GetDoc()->CreateNode(XFA_PacketType::Form, XFA_Element::Ui);
+  GetNode()->InsertChildAndNotify(-1, child0);
+
+  CXFA_Node* child1 =
+      GetDoc()->CreateNode(XFA_PacketType::Form, XFA_Element::Ui);
+  GetNode()->InsertChildAndNotify(-1, child1);
+
+  CXFA_Node* child2 =
+      GetDoc()->CreateNode(XFA_PacketType::Form, XFA_Element::Ui);
+  GetNode()->InsertChildAndNotify(-1, child2);
+
+  CXFA_Node* child3 =
+      GetDoc()->CreateNode(XFA_PacketType::Form, XFA_Element::Ui);
+  GetNode()->InsertChildAndNotify(-1, child3);
+
+  CXFA_Node* child =
+      GetDoc()->CreateNode(XFA_PacketType::Form, XFA_Element::Ui);
+  GetNode()->InsertChildAndNotify(2, child);
+
+  EXPECT_EQ(GetNode(), child->GetParent());
+
+  EXPECT_EQ(child0, GetNode()->GetFirstChild());
+  EXPECT_EQ(child1, child0->GetNextSibling());
+  EXPECT_EQ(child, child1->GetNextSibling());
+  EXPECT_EQ(child2, child->GetNextSibling());
+  EXPECT_EQ(child3, child2->GetNextSibling());
+  EXPECT_EQ(nullptr, child3->GetNextSibling());
+
+  EXPECT_EQ(child3, GetNode()->GetLastChild());
+  EXPECT_EQ(child2, child3->GetPrevSibling());
+  EXPECT_EQ(child, child2->GetPrevSibling());
+  EXPECT_EQ(child1, child->GetPrevSibling());
+  EXPECT_EQ(child0, child1->GetPrevSibling());
+  EXPECT_EQ(nullptr, child0->GetPrevSibling());
+}
+
+TEST_F(CXFANodeTest, InsertChildIndexPastEnd) {
+  CXFA_Node* child0 =
+      GetDoc()->CreateNode(XFA_PacketType::Form, XFA_Element::Ui);
+  GetNode()->InsertChildAndNotify(-1, child0);
+
+  CXFA_Node* child1 =
+      GetDoc()->CreateNode(XFA_PacketType::Form, XFA_Element::Ui);
+  GetNode()->InsertChildAndNotify(-1, child1);
+
+  CXFA_Node* child =
+      GetDoc()->CreateNode(XFA_PacketType::Form, XFA_Element::Ui);
+  GetNode()->InsertChildAndNotify(20, child);
+
+  EXPECT_EQ(GetNode(), child->GetParent());
+  EXPECT_EQ(nullptr, child->GetNextSibling());
+  EXPECT_EQ(child1, child->GetPrevSibling());
+  EXPECT_EQ(child, child1->GetNextSibling());
+
+  EXPECT_EQ(child0, GetNode()->GetFirstChild());
+  EXPECT_EQ(child, GetNode()->GetLastChild());
+}
+
+TEST_F(CXFANodeTest, InsertFirstChildBeforeNullptr) {
+  EXPECT_EQ(nullptr, GetNode()->GetFirstChild());
+  EXPECT_EQ(nullptr, GetNode()->GetLastChild());
+
+  CXFA_Node* child =
+      GetDoc()->CreateNode(XFA_PacketType::Form, XFA_Element::Ui);
+  GetNode()->InsertChildAndNotify(child, nullptr);
+  EXPECT_EQ(child, GetNode()->GetFirstChild());
+  EXPECT_EQ(child, GetNode()->GetLastChild());
+}
+
+TEST_F(CXFANodeTest, InsertBeforeWithNullBefore) {
+  CXFA_Node* child0 =
+      GetDoc()->CreateNode(XFA_PacketType::Form, XFA_Element::Ui);
+  GetNode()->InsertChildAndNotify(-1, child0);
+
+  CXFA_Node* child1 =
+      GetDoc()->CreateNode(XFA_PacketType::Form, XFA_Element::Ui);
+  GetNode()->InsertChildAndNotify(-1, child1);
+
+  CXFA_Node* child =
+      GetDoc()->CreateNode(XFA_PacketType::Form, XFA_Element::Ui);
+  GetNode()->InsertChildAndNotify(child, nullptr);
+
+  EXPECT_EQ(GetNode(), child->GetParent());
+  EXPECT_EQ(nullptr, child->GetNextSibling());
+  EXPECT_EQ(child1, child->GetPrevSibling());
+  EXPECT_EQ(child, child1->GetNextSibling());
+
+  EXPECT_EQ(child0, GetNode()->GetFirstChild());
+  EXPECT_EQ(child, GetNode()->GetLastChild());
+}
+
+TEST_F(CXFANodeTest, InsertBeforeFirstChild) {
+  CXFA_Node* child0 =
+      GetDoc()->CreateNode(XFA_PacketType::Form, XFA_Element::Ui);
+  GetNode()->InsertChildAndNotify(-1, child0);
+
+  CXFA_Node* child1 =
+      GetDoc()->CreateNode(XFA_PacketType::Form, XFA_Element::Ui);
+  GetNode()->InsertChildAndNotify(-1, child1);
+
+  CXFA_Node* child =
+      GetDoc()->CreateNode(XFA_PacketType::Form, XFA_Element::Ui);
+  GetNode()->InsertChildAndNotify(child, child0);
+
+  EXPECT_EQ(GetNode(), child->GetParent());
+  EXPECT_EQ(child0, child->GetNextSibling());
+  EXPECT_EQ(nullptr, child->GetPrevSibling());
+  EXPECT_EQ(child, child0->GetPrevSibling());
+
+  EXPECT_EQ(child, GetNode()->GetFirstChild());
+  EXPECT_EQ(child1, GetNode()->GetLastChild());
+}
+
+TEST_F(CXFANodeTest, InsertBefore) {
+  CXFA_Node* child0 =
+      GetDoc()->CreateNode(XFA_PacketType::Form, XFA_Element::Ui);
+  GetNode()->InsertChildAndNotify(-1, child0);
+
+  CXFA_Node* child1 =
+      GetDoc()->CreateNode(XFA_PacketType::Form, XFA_Element::Ui);
+  GetNode()->InsertChildAndNotify(-1, child1);
+
+  CXFA_Node* child2 =
+      GetDoc()->CreateNode(XFA_PacketType::Form, XFA_Element::Ui);
+  GetNode()->InsertChildAndNotify(-1, child2);
+
+  CXFA_Node* child3 =
+      GetDoc()->CreateNode(XFA_PacketType::Form, XFA_Element::Ui);
+  GetNode()->InsertChildAndNotify(-1, child3);
+
+  CXFA_Node* child =
+      GetDoc()->CreateNode(XFA_PacketType::Form, XFA_Element::Ui);
+  GetNode()->InsertChildAndNotify(child, child2);
+
+  EXPECT_EQ(GetNode(), child->GetParent());
+  EXPECT_EQ(child2, child->GetNextSibling());
+  EXPECT_EQ(child1, child->GetPrevSibling());
+  EXPECT_EQ(child, child1->GetNextSibling());
+  EXPECT_EQ(child, child2->GetPrevSibling());
+
+  EXPECT_EQ(child0, GetNode()->GetFirstChild());
+  EXPECT_EQ(child3, GetNode()->GetLastChild());
+}
+
+TEST_F(CXFANodeTest, RemoveOnlyChild) {
+  CXFA_Node* child0 =
+      GetDoc()->CreateNode(XFA_PacketType::Form, XFA_Element::Ui);
+  GetNode()->InsertChildAndNotify(-1, child0);
+  EXPECT_EQ(child0, GetNode()->GetFirstChild());
+  EXPECT_EQ(child0, GetNode()->GetLastChild());
+
+  GetNode()->RemoveChildAndNotify(child0, false);
+  EXPECT_EQ(nullptr, GetNode()->GetFirstChild());
+  EXPECT_EQ(nullptr, GetNode()->GetLastChild());
+  EXPECT_EQ(nullptr, child0->GetParent());
+  EXPECT_EQ(nullptr, child0->GetNextSibling());
+  EXPECT_EQ(nullptr, child0->GetPrevSibling());
+}
+
+TEST_F(CXFANodeTest, RemoveFirstChild) {
+  CXFA_Node* child0 =
+      GetDoc()->CreateNode(XFA_PacketType::Form, XFA_Element::Ui);
+  GetNode()->InsertChildAndNotify(-1, child0);
+
+  CXFA_Node* child1 =
+      GetDoc()->CreateNode(XFA_PacketType::Form, XFA_Element::Ui);
+  GetNode()->InsertChildAndNotify(-1, child1);
+
+  CXFA_Node* child2 =
+      GetDoc()->CreateNode(XFA_PacketType::Form, XFA_Element::Ui);
+  GetNode()->InsertChildAndNotify(-1, child2);
+  EXPECT_EQ(child0, GetNode()->GetFirstChild());
+  EXPECT_EQ(child2, GetNode()->GetLastChild());
+
+  GetNode()->RemoveChildAndNotify(child0, false);
+  EXPECT_EQ(child1, GetNode()->GetFirstChild());
+  EXPECT_EQ(child2, GetNode()->GetLastChild());
+  EXPECT_EQ(nullptr, child1->GetPrevSibling());
+  EXPECT_EQ(nullptr, child0->GetParent());
+  EXPECT_EQ(nullptr, child0->GetNextSibling());
+  EXPECT_EQ(nullptr, child0->GetPrevSibling());
+}
+
+TEST_F(CXFANodeTest, RemoveLastChild) {
+  CXFA_Node* child0 =
+      GetDoc()->CreateNode(XFA_PacketType::Form, XFA_Element::Ui);
+  GetNode()->InsertChildAndNotify(-1, child0);
+
+  CXFA_Node* child1 =
+      GetDoc()->CreateNode(XFA_PacketType::Form, XFA_Element::Ui);
+  GetNode()->InsertChildAndNotify(-1, child1);
+
+  CXFA_Node* child2 =
+      GetDoc()->CreateNode(XFA_PacketType::Form, XFA_Element::Ui);
+  GetNode()->InsertChildAndNotify(-1, child2);
+  EXPECT_EQ(child0, GetNode()->GetFirstChild());
+  EXPECT_EQ(child2, GetNode()->GetLastChild());
+
+  GetNode()->RemoveChildAndNotify(child2, false);
+  EXPECT_EQ(child0, GetNode()->GetFirstChild());
+  EXPECT_EQ(child1, GetNode()->GetLastChild());
+  EXPECT_EQ(nullptr, child1->GetNextSibling());
+  EXPECT_EQ(nullptr, child2->GetParent());
+  EXPECT_EQ(nullptr, child2->GetNextSibling());
+  EXPECT_EQ(nullptr, child2->GetPrevSibling());
+}
+
+TEST_F(CXFANodeTest, RemoveChild) {
+  CXFA_Node* child0 =
+      GetDoc()->CreateNode(XFA_PacketType::Form, XFA_Element::Ui);
+  GetNode()->InsertChildAndNotify(-1, child0);
+
+  CXFA_Node* child1 =
+      GetDoc()->CreateNode(XFA_PacketType::Form, XFA_Element::Ui);
+  GetNode()->InsertChildAndNotify(-1, child1);
+
+  CXFA_Node* child2 =
+      GetDoc()->CreateNode(XFA_PacketType::Form, XFA_Element::Ui);
+  GetNode()->InsertChildAndNotify(-1, child2);
+  EXPECT_EQ(child0, GetNode()->GetFirstChild());
+  EXPECT_EQ(child2, GetNode()->GetLastChild());
+
+  GetNode()->RemoveChildAndNotify(child1, false);
+  EXPECT_EQ(child0, GetNode()->GetFirstChild());
+  EXPECT_EQ(child2, GetNode()->GetLastChild());
+  EXPECT_EQ(child2, child0->GetNextSibling());
+  EXPECT_EQ(child0, child2->GetPrevSibling());
+  EXPECT_EQ(nullptr, child1->GetParent());
+  EXPECT_EQ(nullptr, child1->GetNextSibling());
+  EXPECT_EQ(nullptr, child1->GetPrevSibling());
+}
+
+TEST_F(CXFANodeTest, InsertChildWithParent) {
+  CXFA_Node* child0 =
+      GetDoc()->CreateNode(XFA_PacketType::Form, XFA_Element::Ui);
+  CXFA_Node* child1 =
+      GetDoc()->CreateNode(XFA_PacketType::Form, XFA_Element::Ui);
+  child0->InsertChildAndNotify(-1, child1);
+
+  EXPECT_DEATH_IF_SUPPORTED(GetNode()->InsertChildAndNotify(0, child1), "");
+}
+
+TEST_F(CXFANodeTest, InsertNullChild) {
+  EXPECT_DEATH_IF_SUPPORTED(GetNode()->InsertChildAndNotify(0, nullptr), "");
+}
+
+TEST_F(CXFANodeTest, InsertBeforeWithNullChild) {
+  EXPECT_DEATH_IF_SUPPORTED(GetNode()->InsertChildAndNotify(nullptr, nullptr),
+                            "");
+}
+
+TEST_F(CXFANodeTest, InsertBeforeWithBeforeInAnotherParent) {
+  CXFA_Node* child0 =
+      GetDoc()->CreateNode(XFA_PacketType::Form, XFA_Element::Ui);
+  GetNode()->InsertChildAndNotify(-1, child0);
+
+  CXFA_Node* child1 =
+      GetDoc()->CreateNode(XFA_PacketType::Form, XFA_Element::Ui);
+  child0->InsertChildAndNotify(-1, child1);
+
+  CXFA_Node* child =
+      GetDoc()->CreateNode(XFA_PacketType::Form, XFA_Element::Ui);
+  EXPECT_DEATH_IF_SUPPORTED(GetNode()->InsertChildAndNotify(child, child1), "");
+}
+
+TEST_F(CXFANodeTest, InsertBeforeWithNodeInAnotherParent) {
+  CXFA_Node* child0 =
+      GetDoc()->CreateNode(XFA_PacketType::Form, XFA_Element::Ui);
+  GetNode()->InsertChildAndNotify(-1, child0);
+
+  CXFA_Node* child1 =
+      GetDoc()->CreateNode(XFA_PacketType::Form, XFA_Element::Ui);
+  child0->InsertChildAndNotify(-1, child1);
+
+  EXPECT_DEATH_IF_SUPPORTED(GetNode()->InsertChildAndNotify(child1, nullptr),
+                            "");
+}
+
+TEST_F(CXFANodeTest, RemoveChildNullptr) {
+  EXPECT_DEATH_IF_SUPPORTED(GetNode()->RemoveChildAndNotify(nullptr, false),
+                            "");
+}
+
+TEST_F(CXFANodeTest, RemoveChildAnotherParent) {
+  CXFA_Node* child0 =
+      GetDoc()->CreateNode(XFA_PacketType::Form, XFA_Element::Ui);
+  GetNode()->InsertChildAndNotify(-1, child0);
+
+  CXFA_Node* child1 =
+      GetDoc()->CreateNode(XFA_PacketType::Form, XFA_Element::Ui);
+  child0->InsertChildAndNotify(-1, child1);
+
+  GetNode()->RemoveChildAndNotify(child1, false);
+  EXPECT_EQ(child0, child1->GetParent());
 }
diff --git a/xfa/fxfa/parser/cxfa_nodehelper.cpp b/xfa/fxfa/parser/cxfa_nodehelper.cpp
index eea054a..dde90bc 100644
--- a/xfa/fxfa/parser/cxfa_nodehelper.cpp
+++ b/xfa/fxfa/parser/cxfa_nodehelper.cpp
@@ -6,287 +6,35 @@
 
 #include "xfa/fxfa/parser/cxfa_nodehelper.h"
 
+#include <utility>
+
 #include "core/fxcrt/fx_extension.h"
-#include "fxjs/cfxjse_engine.h"
+#include "fxjs/xfa/cfxjse_engine.h"
 #include "fxjs/xfa/cjx_object.h"
 #include "xfa/fxfa/parser/cxfa_document.h"
 #include "xfa/fxfa/parser/cxfa_localemgr.h"
 #include "xfa/fxfa/parser/cxfa_node.h"
+#include "xfa/fxfa/parser/xfa_basic_data.h"
 #include "xfa/fxfa/parser/xfa_resolvenode_rs.h"
 #include "xfa/fxfa/parser/xfa_utils.h"
 
-CXFA_NodeHelper::CXFA_NodeHelper()
-    : m_eLastCreateType(XFA_Element::DataValue),
-      m_pCreateParent(nullptr),
-      m_iCreateCount(0),
-      m_iCreateFlag(XFA_ResolveNode_RSType_CreateNodeOne),
-      m_iCurAllStart(-1),
-      m_pAllStartParent(nullptr) {}
+CXFA_NodeHelper::CXFA_NodeHelper() = default;
 
-CXFA_NodeHelper::~CXFA_NodeHelper() {}
+CXFA_NodeHelper::~CXFA_NodeHelper() = default;
 
-CXFA_Node* CXFA_NodeHelper::ResolveNodes_GetOneChild(CXFA_Node* parent,
-                                                     const wchar_t* pwsName,
-                                                     bool bIsClassName) {
-  if (!parent)
-    return nullptr;
-
-  std::vector<CXFA_Node*> siblings;
-  uint32_t uNameHash = FX_HashCode_GetW(WideStringView(pwsName), false);
-  NodeAcc_TraverseAnySiblings(parent, uNameHash, &siblings, bIsClassName);
-  return !siblings.empty() ? siblings[0] : nullptr;
-}
-
-int32_t CXFA_NodeHelper::CountSiblings(CXFA_Node* pNode,
-                                       XFA_LOGIC_TYPE eLogicType,
-                                       std::vector<CXFA_Node*>* pSiblings,
-                                       bool bIsClassName) {
-  if (!pNode)
-    return 0;
-  CXFA_Node* parent = ResolveNodes_GetParent(pNode, XFA_LOGIC_NoTransparent);
-  if (!parent)
-    return 0;
-  if (!parent->HasProperty(pNode->GetElementType()) &&
-      eLogicType == XFA_LOGIC_Transparent) {
-    parent = ResolveNodes_GetParent(pNode, XFA_LOGIC_Transparent);
-    if (!parent)
-      return 0;
-  }
-  if (bIsClassName) {
-    return NodeAcc_TraverseSiblings(parent, pNode->GetClassHashCode(),
-                                    pSiblings, eLogicType, bIsClassName);
-  }
-  return NodeAcc_TraverseSiblings(parent, pNode->GetNameHash(), pSiblings,
-                                  eLogicType, bIsClassName);
-}
-
-int32_t CXFA_NodeHelper::NodeAcc_TraverseAnySiblings(
-    CXFA_Node* parent,
-    uint32_t dNameHash,
-    std::vector<CXFA_Node*>* pSiblings,
-    bool bIsClassName) {
-  if (!parent || !pSiblings)
-    return 0;
-
-  int32_t nCount = 0;
-  for (CXFA_Node* child :
-       parent->GetNodeList(XFA_NODEFILTER_Properties, XFA_Element::Unknown)) {
-    if (bIsClassName) {
-      if (child->GetClassHashCode() == dNameHash) {
-        pSiblings->push_back(child);
-        nCount++;
-      }
-    } else {
-      if (child->GetNameHash() == dNameHash) {
-        pSiblings->push_back(child);
-        nCount++;
-      }
-    }
-    if (nCount > 0)
-      return nCount;
-
-    nCount +=
-        NodeAcc_TraverseAnySiblings(child, dNameHash, pSiblings, bIsClassName);
-  }
-  for (CXFA_Node* child :
-       parent->GetNodeList(XFA_NODEFILTER_Children, XFA_Element::Unknown)) {
-    if (bIsClassName) {
-      if (child->GetClassHashCode() == dNameHash) {
-        pSiblings->push_back(child);
-        nCount++;
-      }
-    } else {
-      if (child->GetNameHash() == dNameHash) {
-        pSiblings->push_back(child);
-        nCount++;
-      }
-    }
-    if (nCount > 0)
-      return nCount;
-
-    nCount +=
-        NodeAcc_TraverseAnySiblings(child, dNameHash, pSiblings, bIsClassName);
-  }
-  return nCount;
-}
-
-int32_t CXFA_NodeHelper::NodeAcc_TraverseSiblings(
-    CXFA_Node* parent,
-    uint32_t dNameHash,
-    std::vector<CXFA_Node*>* pSiblings,
-    XFA_LOGIC_TYPE eLogicType,
-    bool bIsClassName,
-    bool bIsFindProperty) {
-  if (!parent || !pSiblings)
-    return 0;
-
-  int32_t nCount = 0;
-  if (bIsFindProperty) {
-    for (CXFA_Node* child :
-         parent->GetNodeList(XFA_NODEFILTER_Properties, XFA_Element::Unknown)) {
-      if (bIsClassName) {
-        if (child->GetClassHashCode() == dNameHash) {
-          pSiblings->push_back(child);
-          nCount++;
-        }
-      } else {
-        if (child->GetNameHash() == dNameHash) {
-          if (child->GetElementType() != XFA_Element::PageSet &&
-              child->GetElementType() != XFA_Element::Extras &&
-              child->GetElementType() != XFA_Element::Items) {
-            pSiblings->push_back(child);
-            nCount++;
-          }
-        }
-      }
-      if (child->IsUnnamed() &&
-          child->GetElementType() == XFA_Element::PageSet) {
-        nCount += NodeAcc_TraverseSiblings(child, dNameHash, pSiblings,
-                                           eLogicType, bIsClassName, false);
-      }
-    }
-    if (nCount > 0)
-      return nCount;
-  }
-  for (CXFA_Node* child :
-       parent->GetNodeList(XFA_NODEFILTER_Children, XFA_Element::Unknown)) {
-    if (child->GetElementType() == XFA_Element::Variables)
-      continue;
-
-    if (bIsClassName) {
-      if (child->GetClassHashCode() == dNameHash) {
-        pSiblings->push_back(child);
-        nCount++;
-      }
-    } else {
-      if (child->GetNameHash() == dNameHash) {
-        pSiblings->push_back(child);
-        nCount++;
-      }
-    }
-    if (eLogicType == XFA_LOGIC_NoTransparent)
-      continue;
-
-    if (NodeIsTransparent(child) &&
-        child->GetElementType() != XFA_Element::PageSet) {
-      nCount += NodeAcc_TraverseSiblings(child, dNameHash, pSiblings,
-                                         eLogicType, bIsClassName, false);
-    }
-  }
-  return nCount;
-}
-
-CXFA_Node* CXFA_NodeHelper::ResolveNodes_GetParent(CXFA_Node* pNode,
-                                                   XFA_LOGIC_TYPE eLogicType) {
-  if (!pNode) {
-    return nullptr;
-  }
-  if (eLogicType == XFA_LOGIC_NoTransparent) {
-    return pNode->GetParent();
-  }
-  CXFA_Node* parent;
-  CXFA_Node* node = pNode;
-  while (true) {
-    parent = ResolveNodes_GetParent(node);
-    if (!parent) {
-      break;
-    }
-    XFA_Element parentType = parent->GetElementType();
-    if ((!parent->IsUnnamed() && parentType != XFA_Element::SubformSet) ||
-        parentType == XFA_Element::Variables) {
-      break;
-    }
-    node = parent;
-  }
-  return parent;
-}
-
-int32_t CXFA_NodeHelper::GetIndex(CXFA_Node* pNode,
-                                  XFA_LOGIC_TYPE eLogicType,
-                                  bool bIsProperty,
-                                  bool bIsClassIndex) {
-  CXFA_Node* parent = ResolveNodes_GetParent(pNode, XFA_LOGIC_NoTransparent);
-  if (!parent) {
-    return 0;
-  }
-  if (!bIsProperty && eLogicType == XFA_LOGIC_Transparent) {
-    parent = ResolveNodes_GetParent(pNode, XFA_LOGIC_Transparent);
-    if (!parent) {
-      return 0;
-    }
-  }
-  uint32_t dwHashName = pNode->GetNameHash();
-  if (bIsClassIndex) {
-    dwHashName = pNode->GetClassHashCode();
-  }
-  std::vector<CXFA_Node*> siblings;
-  int32_t iSize = NodeAcc_TraverseSiblings(parent, dwHashName, &siblings,
-                                           eLogicType, bIsClassIndex);
-  for (int32_t i = 0; i < iSize; ++i) {
-    CXFA_Node* child = siblings[i];
-    if (child == pNode) {
-      return i;
-    }
-  }
-  return 0;
-}
-
-WideString CXFA_NodeHelper::GetNameExpression(CXFA_Node* refNode,
-                                              bool bIsAllPath,
-                                              XFA_LOGIC_TYPE eLogicType) {
-  WideString wsName;
-  if (bIsAllPath) {
-    wsName = GetNameExpression(refNode, false, eLogicType);
-    WideString wsParent;
-    CXFA_Node* parent =
-        ResolveNodes_GetParent(refNode, XFA_LOGIC_NoTransparent);
-    while (parent) {
-      wsParent = GetNameExpression(parent, false, eLogicType);
-      wsParent += L".";
-      wsParent += wsName;
-      wsName = wsParent;
-      parent = ResolveNodes_GetParent(parent, XFA_LOGIC_NoTransparent);
-    }
-    return wsName;
-  }
-
-  WideString ws;
-  bool bIsProperty = NodeIsProperty(refNode);
-  if (refNode->IsUnnamed() ||
-      (bIsProperty && refNode->GetElementType() != XFA_Element::PageSet)) {
-    ws = refNode->GetClassName();
-    return WideString::Format(L"#%ls[%d]", ws.c_str(),
-                              GetIndex(refNode, eLogicType, bIsProperty, true));
-  }
-  ws = refNode->JSObject()->GetCData(XFA_Attribute::Name);
-  ws.Replace(L".", L"\\.");
-  return WideString::Format(L"%ls[%d]", ws.c_str(),
-                            GetIndex(refNode, eLogicType, bIsProperty, false));
-}
-
-bool CXFA_NodeHelper::NodeIsTransparent(CXFA_Node* refNode) {
-  if (!refNode)
-    return false;
-
-  XFA_Element refNodeType = refNode->GetElementType();
-  return (refNode->IsUnnamed() && refNode->IsContainerNode()) ||
-         refNodeType == XFA_Element::SubformSet ||
-         refNodeType == XFA_Element::Area || refNodeType == XFA_Element::Proto;
-}
-
-bool CXFA_NodeHelper::CreateNode_ForCondition(WideString& wsCondition) {
-  int32_t iLen = wsCondition.GetLength();
+bool CXFA_NodeHelper::CreateNodeForCondition(const WideString& wsCondition) {
+  size_t szLen = wsCondition.GetLength();
   WideString wsIndex(L"0");
   bool bAll = false;
-  if (iLen == 0) {
+  if (szLen == 0) {
     m_iCreateFlag = XFA_ResolveNode_RSType_CreateNodeOne;
     return false;
   }
   if (wsCondition[0] != '[')
     return false;
 
-  int32_t i = 1;
-  for (; i < iLen; ++i) {
+  size_t i = 1;
+  for (; i < szLen; ++i) {
     wchar_t ch = wsCondition[i];
     if (ch == ' ')
       continue;
@@ -300,44 +48,51 @@
     m_iCreateFlag = XFA_ResolveNode_RSType_CreateNodeAll;
   } else {
     m_iCreateFlag = XFA_ResolveNode_RSType_CreateNodeOne;
-    wsIndex = wsCondition.Mid(i, iLen - 1 - i);
+    wsIndex = wsCondition.Substr(i, szLen - 1 - i);
   }
-  int32_t iIndex = wsIndex.GetInteger();
-  m_iCreateCount = iIndex;
+  int32_t iCount = wsIndex.GetInteger();
+  if (iCount < 0)
+    return false;
+
+  m_iCreateCount = iCount;
   return true;
 }
 
-bool CXFA_NodeHelper::ResolveNodes_CreateNode(WideString wsName,
-                                              WideString wsCondition,
-                                              bool bLastNode,
-                                              CFXJSE_Engine* pScriptContext) {
-  if (!m_pCreateParent) {
+bool CXFA_NodeHelper::CreateNode(const WideString& wsName,
+                                 const WideString& wsCondition,
+                                 bool bLastNode,
+                                 CFXJSE_Engine* pScriptContext) {
+  if (!m_pCreateParent)
     return false;
-  }
+
+  WideStringView wsNameView = wsName.AsStringView();
   bool bIsClassName = false;
   bool bResult = false;
-  if (wsName[0] == '!') {
-    wsName = wsName.Right(wsName.GetLength() - 1);
+  if (!wsNameView.IsEmpty() && wsNameView[0] == '!') {
+    wsNameView = wsNameView.Last(wsNameView.GetLength() - 1);
     m_pCreateParent = ToNode(
         pScriptContext->GetDocument()->GetXFAObject(XFA_HASHCODE_Datasets));
   }
-  if (wsName[0] == '#') {
+  if (!wsNameView.IsEmpty() && wsNameView[0] == '#') {
     bIsClassName = true;
-    wsName = wsName.Right(wsName.GetLength() - 1);
+    wsNameView = wsNameView.Last(wsNameView.GetLength() - 1);
   }
-  if (m_iCreateCount == 0) {
-    CreateNode_ForCondition(wsCondition);
-  }
+  if (wsNameView.IsEmpty())
+    return false;
+
+  if (m_iCreateCount == 0)
+    CreateNodeForCondition(wsCondition);
+
   if (bIsClassName) {
-    XFA_Element eType = CXFA_Node::NameToElement(wsName);
+    XFA_Element eType = XFA_GetElementByName(wsNameView);
     if (eType == XFA_Element::Unknown)
       return false;
 
-    for (int32_t iIndex = 0; iIndex < m_iCreateCount; iIndex++) {
+    for (size_t i = 0; i < m_iCreateCount; ++i) {
       CXFA_Node* pNewNode = m_pCreateParent->CreateSamePacketNode(eType);
       if (pNewNode) {
-        m_pCreateParent->InsertChild(pNewNode, nullptr);
-        if (iIndex == m_iCreateCount - 1) {
+        m_pCreateParent->InsertChildAndNotify(pNewNode, nullptr);
+        if (i == m_iCreateCount - 1) {
           m_pCreateParent = pNewNode;
         }
         bResult = true;
@@ -348,23 +103,23 @@
     if (bLastNode) {
       eClassType = m_eLastCreateType;
     }
-    for (int32_t iIndex = 0; iIndex < m_iCreateCount; iIndex++) {
+    for (size_t i = 0; i < m_iCreateCount; ++i) {
       CXFA_Node* pNewNode = m_pCreateParent->CreateSamePacketNode(eClassType);
       if (pNewNode) {
-        pNewNode->JSObject()->SetAttribute(XFA_Attribute::Name,
-                                           wsName.AsStringView(), false);
+        pNewNode->JSObject()->SetAttribute(XFA_Attribute::Name, wsNameView,
+                                           false);
         pNewNode->CreateXMLMappingNode();
-        m_pCreateParent->InsertChild(pNewNode, nullptr);
-        if (iIndex == m_iCreateCount - 1) {
+        m_pCreateParent->InsertChildAndNotify(pNewNode, nullptr);
+        if (i == m_iCreateCount - 1) {
           m_pCreateParent = pNewNode;
         }
         bResult = true;
       }
     }
   }
-  if (!bResult) {
+  if (!bResult)
     m_pCreateParent = nullptr;
-  }
+
   return bResult;
 }
 
@@ -382,8 +137,3 @@
     m_eLastCreateType = XFA_Element::DataValue;
   }
 }
-
-bool CXFA_NodeHelper::NodeIsProperty(CXFA_Node* refNode) {
-  CXFA_Node* parent = ResolveNodes_GetParent(refNode, XFA_LOGIC_NoTransparent);
-  return parent && refNode && parent->HasProperty(refNode->GetElementType());
-}
diff --git a/xfa/fxfa/parser/cxfa_nodehelper.h b/xfa/fxfa/parser/cxfa_nodehelper.h
index e13387e..66e7e66 100644
--- a/xfa/fxfa/parser/cxfa_nodehelper.h
+++ b/xfa/fxfa/parser/cxfa_nodehelper.h
@@ -9,64 +9,31 @@
 
 #include <vector>
 
+#include "core/fxcrt/fx_string.h"
+#include "xfa/fxfa/fxfa_basic.h"
 #include "xfa/fxfa/parser/xfa_resolvenode_rs.h"
 
 class CFXJSE_Engine;
-
-enum XFA_LOGIC_TYPE {
-  XFA_LOGIC_NoTransparent,
-  XFA_LOGIC_Transparent,
-};
+class CXFA_Node;
 
 class CXFA_NodeHelper {
  public:
   CXFA_NodeHelper();
   ~CXFA_NodeHelper();
 
-  CXFA_Node* ResolveNodes_GetOneChild(CXFA_Node* parent,
-                                      const wchar_t* pwsName,
-                                      bool bIsClassName = false);
-  CXFA_Node* ResolveNodes_GetParent(
-      CXFA_Node* pNode,
-      XFA_LOGIC_TYPE eLogicType = XFA_LOGIC_NoTransparent);
-
-  int32_t NodeAcc_TraverseSiblings(CXFA_Node* parent,
-                                   uint32_t dNameHash,
-                                   std::vector<CXFA_Node*>* pSiblings,
-                                   XFA_LOGIC_TYPE eLogicType,
-                                   bool bIsClassName = false,
-                                   bool bIsFindProperty = true);
-  int32_t NodeAcc_TraverseAnySiblings(CXFA_Node* parent,
-                                      uint32_t dNameHash,
-                                      std::vector<CXFA_Node*>* pSiblings,
-                                      bool bIsClassName = false);
-  int32_t CountSiblings(CXFA_Node* pNode,
-                        XFA_LOGIC_TYPE eLogicType,
-                        std::vector<CXFA_Node*>* pSiblings,
-                        bool bIsClassName = false);
-  int32_t GetIndex(CXFA_Node* pNode,
-                   XFA_LOGIC_TYPE eLogicType = XFA_LOGIC_NoTransparent,
-                   bool bIsProperty = false,
-                   bool bIsClassIndex = false);
-  WideString GetNameExpression(
-      CXFA_Node* refNode,
-      bool bIsAllPath,
-      XFA_LOGIC_TYPE eLogicType = XFA_LOGIC_NoTransparent);
-  bool NodeIsTransparent(CXFA_Node* refNode);
-  bool ResolveNodes_CreateNode(WideString wsName,
-                               WideString wsCondition,
-                               bool bLastNode,
-                               CFXJSE_Engine* pScriptContext);
-  bool CreateNode_ForCondition(WideString& wsCondition);
+  bool CreateNode(const WideString& wsName,
+                  const WideString& wsCondition,
+                  bool bLastNode,
+                  CFXJSE_Engine* pScriptContext);
+  bool CreateNodeForCondition(const WideString& wsCondition);
   void SetCreateNodeType(CXFA_Node* refNode);
-  bool NodeIsProperty(CXFA_Node* refNode);
 
-  XFA_Element m_eLastCreateType;
-  CXFA_Node* m_pCreateParent;
-  int32_t m_iCreateCount;
-  XFA_ResolveNode_RSType m_iCreateFlag;
-  int32_t m_iCurAllStart;
-  CXFA_Node* m_pAllStartParent;
+  XFA_Element m_eLastCreateType = XFA_Element::DataValue;
+  XFA_ResolveNode_RSType m_iCreateFlag = XFA_ResolveNode_RSType_CreateNodeOne;
+  size_t m_iCreateCount = 0;
+  int32_t m_iCurAllStart = -1;
+  UnownedPtr<CXFA_Node> m_pCreateParent;
+  UnownedPtr<CXFA_Node> m_pAllStartParent;
 };
 
 #endif  // XFA_FXFA_PARSER_CXFA_NODEHELPER_H_
diff --git a/xfa/fxfa/parser/cxfa_nodeiteratortemplate.h b/xfa/fxfa/parser/cxfa_nodeiteratortemplate.h
index 214f38e..8803efa 100644
--- a/xfa/fxfa/parser/cxfa_nodeiteratortemplate.h
+++ b/xfa/fxfa/parser/cxfa_nodeiteratortemplate.h
@@ -7,14 +7,18 @@
 #ifndef XFA_FXFA_PARSER_CXFA_NODEITERATORTEMPLATE_H_
 #define XFA_FXFA_PARSER_CXFA_NODEITERATORTEMPLATE_H_
 
-template <class NodeType, class TraverseStrategy>
+#include "core/fxcrt/unowned_ptr.h"
+
+template <class NodeType,
+          class TraverseStrategy,
+          typename HolderType = UnownedPtr<NodeType>>
 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; }
+  NodeType* GetRoot() const { return m_pRoot.Get(); }
+  NodeType* GetCurrent() const { return m_pCurrent.Get(); }
 
   void Reset() { m_pCurrent = m_pRoot; }
   bool SetCurrent(NodeType* pNode) {
@@ -22,7 +26,7 @@
       m_pCurrent = nullptr;
       return false;
     }
-    m_pCurrent = pNode;
+    m_pCurrent.Reset(pNode);
     return true;
   }
 
@@ -30,29 +34,27 @@
     if (!m_pRoot)
       return nullptr;
     if (!m_pCurrent) {
-      m_pCurrent = LastDescendant(m_pRoot);
-      return m_pCurrent;
+      m_pCurrent.Reset(LastDescendant(m_pRoot.Get()));
+      return m_pCurrent.Get();
     }
-    NodeType* pSibling = PreviousSiblingWithinSubtree(m_pCurrent);
+    NodeType* pSibling = PreviousSiblingWithinSubtree(m_pCurrent.Get());
     if (pSibling) {
-      m_pCurrent = LastDescendant(pSibling);
-      return m_pCurrent;
+      m_pCurrent.Reset(LastDescendant(pSibling));
+      return m_pCurrent.Get();
     }
-    NodeType* pParent = ParentWithinSubtree(m_pCurrent);
-    if (pParent) {
-      m_pCurrent = pParent;
-      return m_pCurrent;
-    }
-    return nullptr;
+    NodeType* pParent = ParentWithinSubtree(m_pCurrent.Get());
+    if (pParent)
+      m_pCurrent.Reset(pParent);
+    return pParent;
   }
 
   NodeType* MoveToNext() {
     if (!m_pRoot || !m_pCurrent)
       return nullptr;
-    NodeType* pChild = TraverseStrategy::GetFirstChild(m_pCurrent);
+    NodeType* pChild = TraverseStrategy::GetFirstChild(m_pCurrent.Get());
     if (pChild) {
-      m_pCurrent = pChild;
-      return m_pCurrent;
+      m_pCurrent.Reset(pChild);
+      return pChild;
     }
     return SkipChildrenAndMoveToNext();
   }
@@ -60,38 +62,32 @@
   NodeType* SkipChildrenAndMoveToNext() {
     if (!m_pRoot)
       return nullptr;
-    NodeType* pNode = m_pCurrent;
+    NodeType* pNode = m_pCurrent.Get();
     while (pNode) {
       NodeType* pSibling = NextSiblingWithinSubtree(pNode);
       if (pSibling) {
-        m_pCurrent = pSibling;
-        return m_pCurrent;
+        m_pCurrent.Reset(pSibling);
+        return pSibling;
       }
       pNode = ParentWithinSubtree(pNode);
     }
     m_pCurrent = nullptr;
-    return m_pCurrent;
+    return nullptr;
   }
 
  private:
   bool RootReachableFromNode(NodeType* pNode) {
-    if (!pNode)
-      return false;
-    if (pNode == m_pRoot)
-      return true;
-    return RootReachableFromNode(TraverseStrategy::GetParent(pNode));
+    return pNode && (pNode == m_pRoot ||
+                     RootReachableFromNode(TraverseStrategy::GetParent(pNode)));
   }
 
   NodeType* ParentWithinSubtree(NodeType* pNode) {
-    if (!pNode || pNode == m_pRoot)
-      return nullptr;
-    return TraverseStrategy::GetParent(pNode);
+    return pNode && pNode != m_pRoot ? TraverseStrategy::GetParent(pNode)
+                                     : nullptr;
   }
 
   NodeType* NextSiblingWithinSubtree(NodeType* pNode) {
-    if (pNode == m_pRoot)
-      return nullptr;
-    return TraverseStrategy::GetNextSibling(pNode);
+    return pNode != m_pRoot ? TraverseStrategy::GetNextSibling(pNode) : nullptr;
   }
 
   NodeType* PreviousSiblingWithinSubtree(NodeType* pNode) {
@@ -122,8 +118,8 @@
     return pChild ? LastDescendant(pChild) : pNode;
   }
 
-  NodeType* m_pRoot;
-  NodeType* m_pCurrent;
+  HolderType m_pRoot;
+  HolderType 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
index 114bed0..aa4f72d 100644
--- a/xfa/fxfa/parser/cxfa_nodeiteratortemplate_unittest.cpp
+++ b/xfa/fxfa/parser/cxfa_nodeiteratortemplate_unittest.cpp
@@ -8,7 +8,6 @@
 #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 {
diff --git a/xfa/fxfa/parser/cxfa_nodelocale.cpp b/xfa/fxfa/parser/cxfa_nodelocale.cpp
index a93452c..01d2dc5 100644
--- a/xfa/fxfa/parser/cxfa_nodelocale.cpp
+++ b/xfa/fxfa/parser/cxfa_nodelocale.cpp
@@ -8,7 +8,6 @@
 
 #include <utility>
 
-#include "core/fxcrt/xml/cxml_element.h"
 #include "fxjs/xfa/cjx_object.h"
 #include "xfa/fxfa/parser/cxfa_calendarsymbols.h"
 #include "xfa/fxfa/parser/cxfa_datetimesymbols.h"
@@ -51,24 +50,24 @@
                         : nullptr);
 }
 
-WideString CXFA_NodeLocale::GetNumbericSymbol(FX_LOCALENUMSYMBOL eType) const {
-  switch (eType) {
-    case FX_LOCALENUMSYMBOL_Decimal:
-      return GetSymbol(XFA_Element::NumberSymbols, L"decimal");
-    case FX_LOCALENUMSYMBOL_Grouping:
-      return GetSymbol(XFA_Element::NumberSymbols, L"grouping");
-    case FX_LOCALENUMSYMBOL_Percent:
-      return GetSymbol(XFA_Element::NumberSymbols, L"percent");
-    case FX_LOCALENUMSYMBOL_Minus:
-      return GetSymbol(XFA_Element::NumberSymbols, L"minus");
-    case FX_LOCALENUMSYMBOL_Zero:
-      return GetSymbol(XFA_Element::NumberSymbols, L"zero");
-    case FX_LOCALENUMSYMBOL_CurrencySymbol:
-      return GetSymbol(XFA_Element::CurrencySymbols, L"symbol");
-    case FX_LOCALENUMSYMBOL_CurrencyName:
-      return GetSymbol(XFA_Element::CurrencySymbols, L"isoname");
-  }
-  return WideString();
+WideString CXFA_NodeLocale::GetDecimalSymbol() const {
+  return GetSymbol(XFA_Element::NumberSymbols, L"decimal");
+}
+
+WideString CXFA_NodeLocale::GetGroupingSymbol() const {
+  return GetSymbol(XFA_Element::NumberSymbols, L"grouping");
+}
+
+WideString CXFA_NodeLocale::GetPercentSymbol() const {
+  return GetSymbol(XFA_Element::NumberSymbols, L"percent");
+}
+
+WideString CXFA_NodeLocale::GetMinusSymbol() const {
+  return GetSymbol(XFA_Element::NumberSymbols, L"minus");
+}
+
+WideString CXFA_NodeLocale::GetCurrencySymbol() const {
+  return GetSymbol(XFA_Element::CurrencySymbols, L"symbol");
 }
 
 WideString CXFA_NodeLocale::GetDateTimeSymbols() const {
@@ -136,7 +135,7 @@
 }
 
 CXFA_Node* CXFA_NodeLocale::GetNodeByName(CXFA_Node* pParent,
-                                          const WideStringView& wsName) const {
+                                          WideStringView wsName) const {
   CXFA_Node* pChild = pParent ? pParent->GetFirstChild() : nullptr;
   while (pChild) {
     if (pChild->JSObject()->GetAttribute(XFA_Attribute::Name) == wsName)
@@ -148,7 +147,7 @@
 }
 
 WideString CXFA_NodeLocale::GetSymbol(XFA_Element eElement,
-                                      const WideStringView& symbol_type) const {
+                                      WideStringView symbol_type) const {
   CXFA_Node* pSymbols =
       m_pLocale ? m_pLocale->GetChild<CXFA_Node>(0, eElement, false) : nullptr;
   CXFA_Node* pSymbol = GetNodeByName(pSymbols, symbol_type);
@@ -165,8 +164,8 @@
   if (!pCalendar)
     return WideString();
 
-  CXFA_Node* pNode = pCalendar->GetFirstChildByClass<CXFA_Node>(eElement);
-  for (; pNode; pNode = pNode->GetNextSameClassSibling<CXFA_Node>(eElement)) {
+  for (CXFA_Node* pNode = pCalendar->GetFirstChildByClass<CXFA_Node>(eElement);
+       pNode; pNode = pNode->GetNextSameClassSibling<CXFA_Node>(eElement)) {
     if (pNode->JSObject()->GetBoolean(XFA_Attribute::Abbr) == bAbbr) {
       CXFA_Node* pSymbol =
           pNode->GetChild<CXFA_Node>(index, XFA_Element::Unknown, false);
diff --git a/xfa/fxfa/parser/cxfa_nodelocale.h b/xfa/fxfa/parser/cxfa_nodelocale.h
index 6f79e4a..0ada1a4 100644
--- a/xfa/fxfa/parser/cxfa_nodelocale.h
+++ b/xfa/fxfa/parser/cxfa_nodelocale.h
@@ -7,24 +7,25 @@
 #ifndef XFA_FXFA_PARSER_CXFA_NODELOCALE_H_
 #define XFA_FXFA_PARSER_CXFA_NODELOCALE_H_
 
-#include <memory>
-
-#include "core/fxcrt/ifx_locale.h"
+#include "xfa/fgas/crt/locale_iface.h"
 #include "xfa/fxfa/fxfa_basic.h"
 
 class CXFA_Node;
 
 WideString XFA_PatternToString(FX_LOCALENUMSUBCATEGORY category);
 
-class CXFA_NodeLocale : public IFX_Locale {
+class CXFA_NodeLocale final : public LocaleIface {
  public:
   explicit CXFA_NodeLocale(CXFA_Node* pLocale);
   ~CXFA_NodeLocale() override;
 
-  // IFX_Locale
+  // LocaleIface
   WideString GetName() const override;
-  WideString GetNumbericSymbol(FX_LOCALENUMSYMBOL eType) const override;
-
+  WideString GetDecimalSymbol() const override;
+  WideString GetGroupingSymbol() const override;
+  WideString GetPercentSymbol() const override;
+  WideString GetMinusSymbol() const override;
+  WideString GetCurrencySymbol() const override;
   WideString GetDateTimeSymbols() const override;
   WideString GetMonthName(int32_t nMonth, bool bAbbr) const override;
   WideString GetDayName(int32_t nWeek, bool bAbbr) const override;
@@ -37,10 +38,8 @@
   WideString GetNumPattern(FX_LOCALENUMSUBCATEGORY eType) const override;
 
  private:
-  CXFA_Node* GetNodeByName(CXFA_Node* pParent,
-                           const WideStringView& wsName) const;
-  WideString GetSymbol(XFA_Element eElement,
-                       const WideStringView& symbol_type) const;
+  CXFA_Node* GetNodeByName(CXFA_Node* pParent, WideStringView wsName) const;
+  WideString GetSymbol(XFA_Element eElement, WideStringView symbol_type) const;
   WideString GetCalendarSymbol(XFA_Element eElement,
                                int index,
                                bool bAbbr) const;
diff --git a/xfa/fxfa/parser/cxfa_nodeowner.cpp b/xfa/fxfa/parser/cxfa_nodeowner.cpp
new file mode 100644
index 0000000..9baf16c
--- /dev/null
+++ b/xfa/fxfa/parser/cxfa_nodeowner.cpp
@@ -0,0 +1,26 @@
+// Copyright 2018 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
+
+#include "xfa/fxfa/parser/cxfa_nodeowner.h"
+
+#include <utility>
+
+#include "xfa/fxfa/parser/cxfa_node.h"
+
+CXFA_NodeOwner::CXFA_NodeOwner() = default;
+
+CXFA_NodeOwner::~CXFA_NodeOwner() {
+  is_being_destroyed_ = true;
+}
+
+CXFA_Node* CXFA_NodeOwner::AddOwnedNode(std::unique_ptr<CXFA_Node> node) {
+  if (!node)
+    return nullptr;
+
+  CXFA_Node* ret = node.get();
+  nodes_.push_back(std::move(node));
+  return ret;
+}
diff --git a/xfa/fxfa/parser/cxfa_nodeowner.h b/xfa/fxfa/parser/cxfa_nodeowner.h
new file mode 100644
index 0000000..8f6abca
--- /dev/null
+++ b/xfa/fxfa/parser/cxfa_nodeowner.h
@@ -0,0 +1,29 @@
+// Copyright 2018 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_NODEOWNER_H_
+#define XFA_FXFA_PARSER_CXFA_NODEOWNER_H_
+
+#include <memory>
+#include <vector>
+
+class CXFA_Node;
+
+class CXFA_NodeOwner {
+ public:
+  virtual ~CXFA_NodeOwner();
+
+  CXFA_Node* AddOwnedNode(std::unique_ptr<CXFA_Node> node);
+  bool IsBeingDestroyed() const { return is_being_destroyed_; }
+
+ protected:
+  CXFA_NodeOwner();
+
+  bool is_being_destroyed_ = false;
+  std::vector<std::unique_ptr<CXFA_Node>> nodes_;
+};
+
+#endif  // XFA_FXFA_PARSER_CXFA_NODEOWNER_H_
diff --git a/xfa/fxfa/parser/cxfa_numberofcopies.cpp b/xfa/fxfa/parser/cxfa_numberofcopies.cpp
index 0978859..d66fd98 100644
--- a/xfa/fxfa/parser/cxfa_numberofcopies.cpp
+++ b/xfa/fxfa/parser/cxfa_numberofcopies.cpp
@@ -6,14 +6,15 @@
 
 #include "xfa/fxfa/parser/cxfa_numberofcopies.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kNumberOfCopiesAttributeData[] = {
     {XFA_Attribute::Desc, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Lock, XFA_AttributeType::Integer, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"numberOfCopies";
+};
 
 }  // namespace
 
@@ -24,8 +25,8 @@
                 XFA_XDPPACKET_Config,
                 XFA_ObjectType::ContentNode,
                 XFA_Element::NumberOfCopies,
-                nullptr,
-                kAttributeData,
-                kName) {}
+                {},
+                kNumberOfCopiesAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_NumberOfCopies::~CXFA_NumberOfCopies() {}
+CXFA_NumberOfCopies::~CXFA_NumberOfCopies() = default;
diff --git a/xfa/fxfa/parser/cxfa_numberofcopies.h b/xfa/fxfa/parser/cxfa_numberofcopies.h
index 04bb599..3215bb3 100644
--- a/xfa/fxfa/parser/cxfa_numberofcopies.h
+++ b/xfa/fxfa/parser/cxfa_numberofcopies.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_NumberOfCopies : public CXFA_Node {
+class CXFA_NumberOfCopies final : public CXFA_Node {
  public:
   CXFA_NumberOfCopies(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_NumberOfCopies() override;
diff --git a/xfa/fxfa/parser/cxfa_numberpattern.cpp b/xfa/fxfa/parser/cxfa_numberpattern.cpp
index 6ee2698..964855c 100644
--- a/xfa/fxfa/parser/cxfa_numberpattern.cpp
+++ b/xfa/fxfa/parser/cxfa_numberpattern.cpp
@@ -6,14 +6,15 @@
 
 #include "xfa/fxfa/parser/cxfa_numberpattern.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kNumberPatternAttributeData[] = {
     {XFA_Attribute::Name, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::Numeric},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"numberPattern";
+     (void*)XFA_AttributeValue::Numeric},
+};
 
 }  // namespace
 
@@ -24,8 +25,8 @@
                 XFA_XDPPACKET_LocaleSet,
                 XFA_ObjectType::ContentNode,
                 XFA_Element::NumberPattern,
-                nullptr,
-                kAttributeData,
-                kName) {}
+                {},
+                kNumberPatternAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_NumberPattern::~CXFA_NumberPattern() {}
+CXFA_NumberPattern::~CXFA_NumberPattern() = default;
diff --git a/xfa/fxfa/parser/cxfa_numberpattern.h b/xfa/fxfa/parser/cxfa_numberpattern.h
index 0a4fabd..5c42d46 100644
--- a/xfa/fxfa/parser/cxfa_numberpattern.h
+++ b/xfa/fxfa/parser/cxfa_numberpattern.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_NumberPattern : public CXFA_Node {
+class CXFA_NumberPattern final : public CXFA_Node {
  public:
   CXFA_NumberPattern(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_NumberPattern() override;
diff --git a/xfa/fxfa/parser/cxfa_numberpatterns.cpp b/xfa/fxfa/parser/cxfa_numberpatterns.cpp
index a2f8373..1597a29 100644
--- a/xfa/fxfa/parser/cxfa_numberpatterns.cpp
+++ b/xfa/fxfa/parser/cxfa_numberpatterns.cpp
@@ -6,13 +6,14 @@
 
 #include "xfa/fxfa/parser/cxfa_numberpatterns.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::PropertyData kPropertyData[] = {
+const CXFA_Node::PropertyData kNumberPatternsPropertyData[] = {
     {XFA_Element::NumberPattern, 4, 0},
-    {XFA_Element::Unknown, 0, 0}};
-
-constexpr wchar_t kName[] = L"numberPatterns";
+};
 
 }  // namespace
 
@@ -23,8 +24,8 @@
                 XFA_XDPPACKET_LocaleSet,
                 XFA_ObjectType::Node,
                 XFA_Element::NumberPatterns,
-                kPropertyData,
-                nullptr,
-                kName) {}
+                kNumberPatternsPropertyData,
+                {},
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_NumberPatterns::~CXFA_NumberPatterns() {}
+CXFA_NumberPatterns::~CXFA_NumberPatterns() = default;
diff --git a/xfa/fxfa/parser/cxfa_numberpatterns.h b/xfa/fxfa/parser/cxfa_numberpatterns.h
index ef4f889..58c8cb6 100644
--- a/xfa/fxfa/parser/cxfa_numberpatterns.h
+++ b/xfa/fxfa/parser/cxfa_numberpatterns.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_NumberPatterns : public CXFA_Node {
+class CXFA_NumberPatterns final : public CXFA_Node {
  public:
   CXFA_NumberPatterns(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_NumberPatterns() override;
diff --git a/xfa/fxfa/parser/cxfa_numbersymbol.cpp b/xfa/fxfa/parser/cxfa_numbersymbol.cpp
index 74fdc1b..398ab17 100644
--- a/xfa/fxfa/parser/cxfa_numbersymbol.cpp
+++ b/xfa/fxfa/parser/cxfa_numbersymbol.cpp
@@ -6,14 +6,15 @@
 
 #include "xfa/fxfa/parser/cxfa_numbersymbol.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kNumberSymbolAttributeData[] = {
     {XFA_Attribute::Name, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::Decimal},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"numberSymbol";
+     (void*)XFA_AttributeValue::Decimal},
+};
 
 }  // namespace
 
@@ -23,8 +24,8 @@
                 XFA_XDPPACKET_LocaleSet,
                 XFA_ObjectType::ContentNode,
                 XFA_Element::NumberSymbol,
-                nullptr,
-                kAttributeData,
-                kName) {}
+                {},
+                kNumberSymbolAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_NumberSymbol::~CXFA_NumberSymbol() {}
+CXFA_NumberSymbol::~CXFA_NumberSymbol() = default;
diff --git a/xfa/fxfa/parser/cxfa_numbersymbol.h b/xfa/fxfa/parser/cxfa_numbersymbol.h
index c164b03..404f366 100644
--- a/xfa/fxfa/parser/cxfa_numbersymbol.h
+++ b/xfa/fxfa/parser/cxfa_numbersymbol.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_NumberSymbol : public CXFA_Node {
+class CXFA_NumberSymbol final : public CXFA_Node {
  public:
   CXFA_NumberSymbol(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_NumberSymbol() override;
diff --git a/xfa/fxfa/parser/cxfa_numbersymbols.cpp b/xfa/fxfa/parser/cxfa_numbersymbols.cpp
index 0d27f69..adc7234 100644
--- a/xfa/fxfa/parser/cxfa_numbersymbols.cpp
+++ b/xfa/fxfa/parser/cxfa_numbersymbols.cpp
@@ -6,13 +6,14 @@
 
 #include "xfa/fxfa/parser/cxfa_numbersymbols.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::PropertyData kPropertyData[] = {
+const CXFA_Node::PropertyData kNumberSymbolsPropertyData[] = {
     {XFA_Element::NumberSymbol, 5, 0},
-    {XFA_Element::Unknown, 0, 0}};
-
-constexpr wchar_t kName[] = L"numberSymbols";
+};
 
 }  // namespace
 
@@ -23,8 +24,8 @@
                 XFA_XDPPACKET_LocaleSet,
                 XFA_ObjectType::Node,
                 XFA_Element::NumberSymbols,
-                kPropertyData,
-                nullptr,
-                kName) {}
+                kNumberSymbolsPropertyData,
+                {},
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_NumberSymbols::~CXFA_NumberSymbols() {}
+CXFA_NumberSymbols::~CXFA_NumberSymbols() = default;
diff --git a/xfa/fxfa/parser/cxfa_numbersymbols.h b/xfa/fxfa/parser/cxfa_numbersymbols.h
index 972df9f..37bb6fc 100644
--- a/xfa/fxfa/parser/cxfa_numbersymbols.h
+++ b/xfa/fxfa/parser/cxfa_numbersymbols.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_NumberSymbols : public CXFA_Node {
+class CXFA_NumberSymbols final : public CXFA_Node {
  public:
   CXFA_NumberSymbols(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_NumberSymbols() override;
diff --git a/xfa/fxfa/parser/cxfa_numericedit.cpp b/xfa/fxfa/parser/cxfa_numericedit.cpp
index 5a65c76..641fe2a 100644
--- a/xfa/fxfa/parser/cxfa_numericedit.cpp
+++ b/xfa/fxfa/parser/cxfa_numericedit.cpp
@@ -6,25 +6,25 @@
 
 #include "xfa/fxfa/parser/cxfa_numericedit.h"
 
-#include "fxjs/xfa/cjx_numericedit.h"
+#include "fxjs/xfa/cjx_node.h"
 #include "third_party/base/ptr_util.h"
 
 namespace {
 
-const CXFA_Node::PropertyData kPropertyData[] = {{XFA_Element::Margin, 1, 0},
-                                                 {XFA_Element::Border, 1, 0},
-                                                 {XFA_Element::Comb, 1, 0},
-                                                 {XFA_Element::Extras, 1, 0},
-                                                 {XFA_Element::Unknown, 0, 0}};
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::PropertyData kNumericEditPropertyData[] = {
+    {XFA_Element::Margin, 1, 0},
+    {XFA_Element::Border, 1, 0},
+    {XFA_Element::Comb, 1, 0},
+    {XFA_Element::Extras, 1, 0},
+};
+
+const CXFA_Node::AttributeData kNumericEditAttributeData[] = {
     {XFA_Attribute::Id, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Use, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Usehref, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::HScrollPolicy, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::Auto},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"numericEdit";
+     (void*)XFA_AttributeValue::Auto},
+};
 
 }  // namespace
 
@@ -34,9 +34,16 @@
                 (XFA_XDPPACKET_Template | XFA_XDPPACKET_Form),
                 XFA_ObjectType::Node,
                 XFA_Element::NumericEdit,
-                kPropertyData,
-                kAttributeData,
-                kName,
-                pdfium::MakeUnique<CJX_NumericEdit>(this)) {}
+                kNumericEditPropertyData,
+                kNumericEditAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_NumericEdit::~CXFA_NumericEdit() {}
+CXFA_NumericEdit::~CXFA_NumericEdit() = default;
+
+XFA_Element CXFA_NumericEdit::GetValueNodeType() const {
+  return XFA_Element::Float;
+}
+
+XFA_FFWidgetType CXFA_NumericEdit::GetDefaultFFWidgetType() const {
+  return XFA_FFWidgetType::kNumericEdit;
+}
diff --git a/xfa/fxfa/parser/cxfa_numericedit.h b/xfa/fxfa/parser/cxfa_numericedit.h
index d9cfd7e..145bf08 100644
--- a/xfa/fxfa/parser/cxfa_numericedit.h
+++ b/xfa/fxfa/parser/cxfa_numericedit.h
@@ -9,10 +9,13 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_NumericEdit : public CXFA_Node {
+class CXFA_NumericEdit final : public CXFA_Node {
  public:
   CXFA_NumericEdit(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_NumericEdit() override;
+
+  XFA_Element GetValueNodeType() const override;
+  XFA_FFWidgetType GetDefaultFFWidgetType() const override;
 };
 
 #endif  // XFA_FXFA_PARSER_CXFA_NUMERICEDIT_H_
diff --git a/xfa/fxfa/parser/cxfa_object.cpp b/xfa/fxfa/parser/cxfa_object.cpp
index 7c73db0..6d730bf 100644
--- a/xfa/fxfa/parser/cxfa_object.cpp
+++ b/xfa/fxfa/parser/cxfa_object.cpp
@@ -9,35 +9,43 @@
 #include <utility>
 
 #include "core/fxcrt/fx_extension.h"
-#include "fxjs/cfxjse_engine.h"
-#include "fxjs/cfxjse_value.h"
-#include "third_party/base/ptr_util.h"
+#include "fxjs/xfa/cfxjse_engine.h"
+#include "fxjs/xfa/cfxjse_value.h"
+#include "fxjs/xfa/cjx_object.h"
 #include "xfa/fxfa/cxfa_ffnotify.h"
 #include "xfa/fxfa/parser/cxfa_document.h"
 #include "xfa/fxfa/parser/cxfa_node.h"
+#include "xfa/fxfa/parser/cxfa_thisproxy.h"
 #include "xfa/fxfa/parser/cxfa_treelist.h"
+#include "xfa/fxfa/parser/xfa_basic_data.h"
 
 CXFA_Object::CXFA_Object(CXFA_Document* pDocument,
                          XFA_ObjectType objectType,
                          XFA_Element elementType,
-                         const WideStringView& elementName,
                          std::unique_ptr<CJX_Object> jsObject)
-    : CFXJSE_HostObject(kXFA),
-      m_pDocument(pDocument),
+    : m_pDocument(pDocument),
       m_objectType(objectType),
       m_elementType(elementType),
-      m_elementNameHash(FX_HashCode_GetW(elementName, false)),
-      m_elementName(elementName),
+      m_elementName(XFA_ElementToName(elementType)),
+      m_elementNameHash(FX_HashCode_GetAsIfW(m_elementName, false)),
       m_pJSObject(std::move(jsObject)) {}
 
-CXFA_Object::~CXFA_Object() {}
+CXFA_Object::~CXFA_Object() {
+  if (!GetDocument()->IsBeingDestroyed() && GetDocument()->HasScriptContext())
+    GetDocument()->GetScriptContext()->RemoveJSBindingFromMap(this);
+}
+
+CXFA_Object* CXFA_Object::AsCXFAObject() {
+  return this;
+}
 
 WideString CXFA_Object::GetSOMExpression() {
-  CFXJSE_Engine* pScriptContext = m_pDocument->GetScriptContext();
-  if (!pScriptContext)
-    return WideString();
+  CXFA_Node* pNode = AsNode();
+  return pNode ? pNode->GetNameExpression() : WideString();
+}
 
-  return pScriptContext->GetSomExpression(ToNode(this));
+CXFA_List* CXFA_Object::AsList() {
+  return IsList() ? static_cast<CXFA_List*>(this) : nullptr;
 }
 
 CXFA_Node* CXFA_Object::AsNode() {
@@ -48,22 +56,22 @@
   return IsTreeList() ? static_cast<CXFA_TreeList*>(this) : nullptr;
 }
 
-const CXFA_Node* CXFA_Object::AsNode() const {
-  return IsNode() ? static_cast<const CXFA_Node*>(this) : nullptr;
+CXFA_ThisProxy* CXFA_Object::AsThisProxy() {
+  return IsThisProxy() ? static_cast<CXFA_ThisProxy*>(this) : nullptr;
 }
 
-const CXFA_TreeList* CXFA_Object::AsTreeList() const {
-  return IsTreeList() ? static_cast<const CXFA_TreeList*>(this) : nullptr;
-}
-
-void CXFA_Object::CreateWidgetAcc() {
-  acc_ = pdfium::MakeUnique<CXFA_WidgetAcc>(AsNode());
+CXFA_List* ToList(CXFA_Object* pObj) {
+  return pObj ? pObj->AsList() : nullptr;
 }
 
 CXFA_Node* ToNode(CXFA_Object* pObj) {
   return pObj ? pObj->AsNode() : nullptr;
 }
 
-const CXFA_Node* ToNode(const CXFA_Object* pObj) {
-  return pObj ? pObj->AsNode() : nullptr;
+CXFA_TreeList* ToTreeList(CXFA_Object* pObj) {
+  return pObj ? pObj->AsTreeList() : nullptr;
+}
+
+CXFA_ThisProxy* ToThisProxy(CXFA_Object* pObj) {
+  return pObj ? pObj->AsThisProxy() : nullptr;
 }
diff --git a/xfa/fxfa/parser/cxfa_object.h b/xfa/fxfa/parser/cxfa_object.h
index 5d5f31c..cfbcb13 100644
--- a/xfa/fxfa/parser/cxfa_object.h
+++ b/xfa/fxfa/parser/cxfa_object.h
@@ -10,7 +10,7 @@
 #include <memory>
 
 #include "core/fxcrt/fx_string.h"
-#include "fxjs/fxjse.h"
+#include "fxjs/xfa/fxjse.h"
 #include "xfa/fxfa/fxfa_basic.h"
 
 enum class XFA_ObjectType {
@@ -24,22 +24,30 @@
   TreeList,
   ContainerNode,
   ContentNode,
-  VariablesThis
+  ThisProxy,
 };
 
 class CJX_Object;
 class CXFA_Document;
+class CXFA_List;
 class CXFA_Node;
+class CXFA_ThisProxy;
 class CXFA_TreeList;
-class CXFA_WidgetAcc;
 
 class CXFA_Object : public CFXJSE_HostObject {
  public:
   ~CXFA_Object() override;
 
+  // CFXJSE_HostObject:
+  CXFA_Object* AsCXFAObject() override;
+
   CXFA_Document* GetDocument() const { return m_pDocument.Get(); }
   XFA_ObjectType GetObjectType() const { return m_objectType; }
 
+  bool IsList() const {
+    return m_objectType == XFA_ObjectType::List ||
+           m_objectType == XFA_ObjectType::TreeList;
+  }
   bool IsNode() const {
     return m_objectType == XFA_ObjectType::Node ||
            m_objectType == XFA_ObjectType::NodeC ||
@@ -47,8 +55,7 @@
            m_objectType == XFA_ObjectType::ModelNode ||
            m_objectType == XFA_ObjectType::TextNode ||
            m_objectType == XFA_ObjectType::ContainerNode ||
-           m_objectType == XFA_ObjectType::ContentNode ||
-           m_objectType == XFA_ObjectType::VariablesThis;
+           m_objectType == XFA_ObjectType::ContentNode;
   }
   bool IsTreeList() const { return m_objectType == XFA_ObjectType::TreeList; }
   bool IsContentNode() const {
@@ -59,15 +66,12 @@
   }
   bool IsModelNode() const { return m_objectType == XFA_ObjectType::ModelNode; }
   bool IsNodeV() const { return m_objectType == XFA_ObjectType::NodeV; }
-  bool IsVariablesThis() const {
-    return m_objectType == XFA_ObjectType::VariablesThis;
-  }
+  bool IsThisProxy() const { return m_objectType == XFA_ObjectType::ThisProxy; }
 
+  CXFA_List* AsList();
   CXFA_Node* AsNode();
   CXFA_TreeList* AsTreeList();
-
-  const CXFA_Node* AsNode() const;
-  const CXFA_TreeList* AsTreeList() const;
+  CXFA_ThisProxy* AsThisProxy();
 
   CJX_Object* JSObject() { return m_pJSObject.get(); }
   const CJX_Object* JSObject() const { return m_pJSObject.get(); }
@@ -78,11 +82,9 @@
            m_elementType == XFA_Element::Subform ||
            m_elementType == XFA_Element::ExclGroup;
   }
-  void CreateWidgetAcc();
-  CXFA_WidgetAcc* GetWidgetAcc() { return acc_.get(); }
 
   XFA_Element GetElementType() const { return m_elementType; }
-  WideStringView GetClassName() const { return m_elementName; }
+  ByteStringView GetClassName() const { return m_elementName; }
   uint32_t GetClassHashCode() const { return m_elementNameHash; }
 
   WideString GetSOMExpression();
@@ -91,21 +93,20 @@
   CXFA_Object(CXFA_Document* pDocument,
               XFA_ObjectType objectType,
               XFA_Element eType,
-              const WideStringView& elementName,
               std::unique_ptr<CJX_Object> jsObject);
 
   UnownedPtr<CXFA_Document> const m_pDocument;
   const XFA_ObjectType m_objectType;
   const XFA_Element m_elementType;
-
+  const ByteStringView m_elementName;
   const uint32_t m_elementNameHash;
-  const WideStringView m_elementName;
-
   std::unique_ptr<CJX_Object> m_pJSObject;
-  std::unique_ptr<CXFA_WidgetAcc> acc_;
 };
 
+// Helper functions that permit nullptr arguments.
+CXFA_List* ToList(CXFA_Object* pObj);
 CXFA_Node* ToNode(CXFA_Object* pObj);
-const CXFA_Node* ToNode(const CXFA_Object* pObj);
+CXFA_TreeList* ToTreeList(CXFA_Object* pObj);
+CXFA_ThisProxy* ToThisProxy(CXFA_Object* pObj);
 
 #endif  // XFA_FXFA_PARSER_CXFA_OBJECT_H_
diff --git a/xfa/fxfa/parser/cxfa_occur.cpp b/xfa/fxfa/parser/cxfa_occur.cpp
index 7be3f70..ee68981 100644
--- a/xfa/fxfa/parser/cxfa_occur.cpp
+++ b/xfa/fxfa/parser/cxfa_occur.cpp
@@ -11,18 +11,18 @@
 
 namespace {
 
-const CXFA_Node::PropertyData kPropertyData[] = {{XFA_Element::Extras, 1, 0},
-                                                 {XFA_Element::Unknown, 0, 0}};
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::PropertyData kOccurPropertyData[] = {
+    {XFA_Element::Extras, 1, 0},
+};
+
+const CXFA_Node::AttributeData kOccurAttributeData[] = {
     {XFA_Attribute::Id, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Max, XFA_AttributeType::Integer, (void*)1},
     {XFA_Attribute::Min, XFA_AttributeType::Integer, (void*)1},
     {XFA_Attribute::Use, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Initial, XFA_AttributeType::Integer, (void*)1},
     {XFA_Attribute::Usehref, XFA_AttributeType::CData, nullptr},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"occur";
+};
 
 }  // namespace
 
@@ -32,12 +32,11 @@
                 (XFA_XDPPACKET_Template | XFA_XDPPACKET_Form),
                 XFA_ObjectType::Node,
                 XFA_Element::Occur,
-                kPropertyData,
-                kAttributeData,
-                kName,
+                kOccurPropertyData,
+                kOccurAttributeData,
                 pdfium::MakeUnique<CJX_Occur>(this)) {}
 
-CXFA_Occur::~CXFA_Occur() {}
+CXFA_Occur::~CXFA_Occur() = default;
 
 int32_t CXFA_Occur::GetMax() {
   Optional<int32_t> max = JSObject()->TryInteger(XFA_Attribute::Max, true);
diff --git a/xfa/fxfa/parser/cxfa_occur.h b/xfa/fxfa/parser/cxfa_occur.h
index 070c15c..58029a3 100644
--- a/xfa/fxfa/parser/cxfa_occur.h
+++ b/xfa/fxfa/parser/cxfa_occur.h
@@ -11,7 +11,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Occur : public CXFA_Node {
+class CXFA_Occur final : public CXFA_Node {
  public:
   static constexpr int32_t kDefaultMax = 1;
   static constexpr int32_t kDefaultMin = 1;
diff --git a/xfa/fxfa/parser/cxfa_oid.cpp b/xfa/fxfa/parser/cxfa_oid.cpp
index 7202e40..9032733 100644
--- a/xfa/fxfa/parser/cxfa_oid.cpp
+++ b/xfa/fxfa/parser/cxfa_oid.cpp
@@ -6,19 +6,17 @@
 
 #include "xfa/fxfa/parser/cxfa_oid.h"
 
-#include "fxjs/xfa/cjx_oid.h"
+#include "fxjs/xfa/cjx_textnode.h"
 #include "third_party/base/ptr_util.h"
 
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kOidAttributeData[] = {
     {XFA_Attribute::Id, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Name, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Use, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Usehref, XFA_AttributeType::CData, nullptr},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"oid";
+};
 
 }  // namespace
 
@@ -28,9 +26,8 @@
                 (XFA_XDPPACKET_Template | XFA_XDPPACKET_Form),
                 XFA_ObjectType::TextNode,
                 XFA_Element::Oid,
-                nullptr,
-                kAttributeData,
-                kName,
-                pdfium::MakeUnique<CJX_Oid>(this)) {}
+                {},
+                kOidAttributeData,
+                pdfium::MakeUnique<CJX_TextNode>(this)) {}
 
-CXFA_Oid::~CXFA_Oid() {}
+CXFA_Oid::~CXFA_Oid() = default;
diff --git a/xfa/fxfa/parser/cxfa_oid.h b/xfa/fxfa/parser/cxfa_oid.h
index 45abf8b..c9ccb71 100644
--- a/xfa/fxfa/parser/cxfa_oid.h
+++ b/xfa/fxfa/parser/cxfa_oid.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Oid : public CXFA_Node {
+class CXFA_Oid final : public CXFA_Node {
  public:
   CXFA_Oid(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Oid() override;
diff --git a/xfa/fxfa/parser/cxfa_oids.cpp b/xfa/fxfa/parser/cxfa_oids.cpp
index 31d2a6d..64408ca 100644
--- a/xfa/fxfa/parser/cxfa_oids.cpp
+++ b/xfa/fxfa/parser/cxfa_oids.cpp
@@ -6,20 +6,18 @@
 
 #include "xfa/fxfa/parser/cxfa_oids.h"
 
-#include "fxjs/xfa/cjx_oids.h"
+#include "fxjs/xfa/cjx_node.h"
 #include "third_party/base/ptr_util.h"
 
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kOidsAttributeData[] = {
     {XFA_Attribute::Id, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Use, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Type, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::Optional},
+     (void*)XFA_AttributeValue::Optional},
     {XFA_Attribute::Usehref, XFA_AttributeType::CData, nullptr},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"oids";
+};
 
 }  // namespace
 
@@ -29,9 +27,8 @@
                 (XFA_XDPPACKET_Template | XFA_XDPPACKET_Form),
                 XFA_ObjectType::Node,
                 XFA_Element::Oids,
-                nullptr,
-                kAttributeData,
-                kName,
-                pdfium::MakeUnique<CJX_Oids>(this)) {}
+                {},
+                kOidsAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_Oids::~CXFA_Oids() {}
+CXFA_Oids::~CXFA_Oids() = default;
diff --git a/xfa/fxfa/parser/cxfa_oids.h b/xfa/fxfa/parser/cxfa_oids.h
index cc8cd9c..f537601 100644
--- a/xfa/fxfa/parser/cxfa_oids.h
+++ b/xfa/fxfa/parser/cxfa_oids.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Oids : public CXFA_Node {
+class CXFA_Oids final : public CXFA_Node {
  public:
   CXFA_Oids(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Oids() override;
diff --git a/xfa/fxfa/parser/cxfa_openaction.cpp b/xfa/fxfa/parser/cxfa_openaction.cpp
index c50f433..b6264c2 100644
--- a/xfa/fxfa/parser/cxfa_openaction.cpp
+++ b/xfa/fxfa/parser/cxfa_openaction.cpp
@@ -6,17 +6,19 @@
 
 #include "xfa/fxfa/parser/cxfa_openaction.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::PropertyData kPropertyData[] = {
+const CXFA_Node::PropertyData kOpenActionPropertyData[] = {
     {XFA_Element::Destination, 1, 0},
-    {XFA_Element::Unknown, 0, 0}};
-const CXFA_Node::AttributeData kAttributeData[] = {
+};
+
+const CXFA_Node::AttributeData kOpenActionAttributeData[] = {
     {XFA_Attribute::Desc, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Lock, XFA_AttributeType::Integer, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"openAction";
+};
 
 }  // namespace
 
@@ -26,8 +28,8 @@
                 XFA_XDPPACKET_Config,
                 XFA_ObjectType::Node,
                 XFA_Element::OpenAction,
-                kPropertyData,
-                kAttributeData,
-                kName) {}
+                kOpenActionPropertyData,
+                kOpenActionAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_OpenAction::~CXFA_OpenAction() {}
+CXFA_OpenAction::~CXFA_OpenAction() = default;
diff --git a/xfa/fxfa/parser/cxfa_openaction.h b/xfa/fxfa/parser/cxfa_openaction.h
index d84eb29..2eff67c 100644
--- a/xfa/fxfa/parser/cxfa_openaction.h
+++ b/xfa/fxfa/parser/cxfa_openaction.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_OpenAction : public CXFA_Node {
+class CXFA_OpenAction final : public CXFA_Node {
  public:
   CXFA_OpenAction(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_OpenAction() override;
diff --git a/xfa/fxfa/parser/cxfa_operation.cpp b/xfa/fxfa/parser/cxfa_operation.cpp
index cc92d8c..dbd59ba 100644
--- a/xfa/fxfa/parser/cxfa_operation.cpp
+++ b/xfa/fxfa/parser/cxfa_operation.cpp
@@ -6,21 +6,19 @@
 
 #include "xfa/fxfa/parser/cxfa_operation.h"
 
-#include "fxjs/xfa/cjx_operation.h"
+#include "fxjs/xfa/cjx_textnode.h"
 #include "third_party/base/ptr_util.h"
 
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kOperationAttributeData[] = {
     {XFA_Attribute::Id, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Name, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Use, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Output, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Usehref, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Input, XFA_AttributeType::CData, nullptr},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"operation";
+};
 
 }  // namespace
 
@@ -30,9 +28,8 @@
                 XFA_XDPPACKET_ConnectionSet,
                 XFA_ObjectType::TextNode,
                 XFA_Element::Operation,
-                nullptr,
-                kAttributeData,
-                kName,
-                pdfium::MakeUnique<CJX_Operation>(this)) {}
+                {},
+                kOperationAttributeData,
+                pdfium::MakeUnique<CJX_TextNode>(this)) {}
 
-CXFA_Operation::~CXFA_Operation() {}
+CXFA_Operation::~CXFA_Operation() = default;
diff --git a/xfa/fxfa/parser/cxfa_operation.h b/xfa/fxfa/parser/cxfa_operation.h
index 454a354..4df63aa 100644
--- a/xfa/fxfa/parser/cxfa_operation.h
+++ b/xfa/fxfa/parser/cxfa_operation.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Operation : public CXFA_Node {
+class CXFA_Operation final : public CXFA_Node {
  public:
   CXFA_Operation(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Operation() override;
diff --git a/xfa/fxfa/parser/cxfa_output.cpp b/xfa/fxfa/parser/cxfa_output.cpp
index 124d7e5..c9e77de 100644
--- a/xfa/fxfa/parser/cxfa_output.cpp
+++ b/xfa/fxfa/parser/cxfa_output.cpp
@@ -6,18 +6,21 @@
 
 #include "xfa/fxfa/parser/cxfa_output.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::PropertyData kPropertyData[] = {{XFA_Element::To, 1, 0},
-                                                 {XFA_Element::Uri, 1, 0},
-                                                 {XFA_Element::Type, 1, 0},
-                                                 {XFA_Element::Unknown, 0, 0}};
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::PropertyData kOutputPropertyData[] = {
+    {XFA_Element::To, 1, 0},
+    {XFA_Element::Uri, 1, 0},
+    {XFA_Element::Type, 1, 0},
+};
+
+const CXFA_Node::AttributeData kOutputAttributeData[] = {
     {XFA_Attribute::Desc, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Lock, XFA_AttributeType::Integer, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"output";
+};
 
 }  // namespace
 
@@ -27,8 +30,8 @@
                 XFA_XDPPACKET_Config,
                 XFA_ObjectType::Node,
                 XFA_Element::Output,
-                kPropertyData,
-                kAttributeData,
-                kName) {}
+                kOutputPropertyData,
+                kOutputAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_Output::~CXFA_Output() {}
+CXFA_Output::~CXFA_Output() = default;
diff --git a/xfa/fxfa/parser/cxfa_output.h b/xfa/fxfa/parser/cxfa_output.h
index 2eb1391..45555be 100644
--- a/xfa/fxfa/parser/cxfa_output.h
+++ b/xfa/fxfa/parser/cxfa_output.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Output : public CXFA_Node {
+class CXFA_Output final : public CXFA_Node {
  public:
   CXFA_Output(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Output() override;
diff --git a/xfa/fxfa/parser/cxfa_outputbin.cpp b/xfa/fxfa/parser/cxfa_outputbin.cpp
index bb0ef2e..3b9174f 100644
--- a/xfa/fxfa/parser/cxfa_outputbin.cpp
+++ b/xfa/fxfa/parser/cxfa_outputbin.cpp
@@ -6,14 +6,15 @@
 
 #include "xfa/fxfa/parser/cxfa_outputbin.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kOutputBinAttributeData[] = {
     {XFA_Attribute::Desc, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Lock, XFA_AttributeType::Integer, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"outputBin";
+};
 
 }  // namespace
 
@@ -23,8 +24,8 @@
                 XFA_XDPPACKET_Config,
                 XFA_ObjectType::ContentNode,
                 XFA_Element::OutputBin,
-                nullptr,
-                kAttributeData,
-                kName) {}
+                {},
+                kOutputBinAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_OutputBin::~CXFA_OutputBin() {}
+CXFA_OutputBin::~CXFA_OutputBin() = default;
diff --git a/xfa/fxfa/parser/cxfa_outputbin.h b/xfa/fxfa/parser/cxfa_outputbin.h
index 25a1ae0..7ab4540 100644
--- a/xfa/fxfa/parser/cxfa_outputbin.h
+++ b/xfa/fxfa/parser/cxfa_outputbin.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_OutputBin : public CXFA_Node {
+class CXFA_OutputBin final : public CXFA_Node {
  public:
   CXFA_OutputBin(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_OutputBin() override;
diff --git a/xfa/fxfa/parser/cxfa_outputxsl.cpp b/xfa/fxfa/parser/cxfa_outputxsl.cpp
index d56cc15..ab733bc 100644
--- a/xfa/fxfa/parser/cxfa_outputxsl.cpp
+++ b/xfa/fxfa/parser/cxfa_outputxsl.cpp
@@ -6,16 +6,19 @@
 
 #include "xfa/fxfa/parser/cxfa_outputxsl.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::PropertyData kPropertyData[] = {{XFA_Element::Uri, 1, 0},
-                                                 {XFA_Element::Unknown, 0, 0}};
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::PropertyData kOutputXSLPropertyData[] = {
+    {XFA_Element::Uri, 1, 0},
+};
+
+const CXFA_Node::AttributeData kOutputXSLAttributeData[] = {
     {XFA_Attribute::Desc, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Lock, XFA_AttributeType::Integer, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"outputXSL";
+};
 
 }  // namespace
 
@@ -25,8 +28,8 @@
                 XFA_XDPPACKET_Config,
                 XFA_ObjectType::Node,
                 XFA_Element::OutputXSL,
-                kPropertyData,
-                kAttributeData,
-                kName) {}
+                kOutputXSLPropertyData,
+                kOutputXSLAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_OutputXSL::~CXFA_OutputXSL() {}
+CXFA_OutputXSL::~CXFA_OutputXSL() = default;
diff --git a/xfa/fxfa/parser/cxfa_outputxsl.h b/xfa/fxfa/parser/cxfa_outputxsl.h
index 4535523..361ea42 100644
--- a/xfa/fxfa/parser/cxfa_outputxsl.h
+++ b/xfa/fxfa/parser/cxfa_outputxsl.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_OutputXSL : public CXFA_Node {
+class CXFA_OutputXSL final : public CXFA_Node {
  public:
   CXFA_OutputXSL(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_OutputXSL() override;
diff --git a/xfa/fxfa/parser/cxfa_overflow.cpp b/xfa/fxfa/parser/cxfa_overflow.cpp
index 2589714..9ae517b 100644
--- a/xfa/fxfa/parser/cxfa_overflow.cpp
+++ b/xfa/fxfa/parser/cxfa_overflow.cpp
@@ -6,21 +6,19 @@
 
 #include "xfa/fxfa/parser/cxfa_overflow.h"
 
-#include "fxjs/xfa/cjx_overflow.h"
+#include "fxjs/xfa/cjx_node.h"
 #include "third_party/base/ptr_util.h"
 
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kOverflowAttributeData[] = {
     {XFA_Attribute::Id, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Use, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Trailer, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Usehref, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Target, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Leader, XFA_AttributeType::CData, nullptr},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"overflow";
+};
 
 }  // namespace
 
@@ -30,9 +28,8 @@
                 (XFA_XDPPACKET_Template | XFA_XDPPACKET_Form),
                 XFA_ObjectType::Node,
                 XFA_Element::Overflow,
-                nullptr,
-                kAttributeData,
-                kName,
-                pdfium::MakeUnique<CJX_Overflow>(this)) {}
+                {},
+                kOverflowAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_Overflow::~CXFA_Overflow() {}
+CXFA_Overflow::~CXFA_Overflow() = default;
diff --git a/xfa/fxfa/parser/cxfa_overflow.h b/xfa/fxfa/parser/cxfa_overflow.h
index e6627ba..da2717a 100644
--- a/xfa/fxfa/parser/cxfa_overflow.h
+++ b/xfa/fxfa/parser/cxfa_overflow.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Overflow : public CXFA_Node {
+class CXFA_Overflow final : public CXFA_Node {
  public:
   CXFA_Overflow(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Overflow() override;
diff --git a/xfa/fxfa/parser/cxfa_overprint.cpp b/xfa/fxfa/parser/cxfa_overprint.cpp
index cf5ee4b..ee70ce5 100644
--- a/xfa/fxfa/parser/cxfa_overprint.cpp
+++ b/xfa/fxfa/parser/cxfa_overprint.cpp
@@ -6,14 +6,15 @@
 
 #include "xfa/fxfa/parser/cxfa_overprint.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kOverprintAttributeData[] = {
     {XFA_Attribute::Desc, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Lock, XFA_AttributeType::Integer, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"overprint";
+};
 
 }  // namespace
 
@@ -23,8 +24,8 @@
                 XFA_XDPPACKET_Config,
                 XFA_ObjectType::ContentNode,
                 XFA_Element::Overprint,
-                nullptr,
-                kAttributeData,
-                kName) {}
+                {},
+                kOverprintAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_Overprint::~CXFA_Overprint() {}
+CXFA_Overprint::~CXFA_Overprint() = default;
diff --git a/xfa/fxfa/parser/cxfa_overprint.h b/xfa/fxfa/parser/cxfa_overprint.h
index a9ec241..e5e360d 100644
--- a/xfa/fxfa/parser/cxfa_overprint.h
+++ b/xfa/fxfa/parser/cxfa_overprint.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Overprint : public CXFA_Node {
+class CXFA_Overprint final : public CXFA_Node {
  public:
   CXFA_Overprint(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Overprint() override;
diff --git a/xfa/fxfa/parser/cxfa_packet.cpp b/xfa/fxfa/parser/cxfa_packet.cpp
index 6112271..96938ac 100644
--- a/xfa/fxfa/parser/cxfa_packet.cpp
+++ b/xfa/fxfa/parser/cxfa_packet.cpp
@@ -9,21 +9,14 @@
 #include "fxjs/xfa/cjx_packet.h"
 #include "third_party/base/ptr_util.h"
 
-namespace {
-
-constexpr wchar_t kName[] = L"packet";
-
-}  // namespace
-
 CXFA_Packet::CXFA_Packet(CXFA_Document* doc, XFA_PacketType packet)
     : CXFA_Node(doc,
                 packet,
                 XFA_XDPPACKET_XDP,
                 XFA_ObjectType::NodeC,
                 XFA_Element::Packet,
-                nullptr,
-                nullptr,
-                kName,
+                {},
+                {},
                 pdfium::MakeUnique<CJX_Packet>(this)) {}
 
-CXFA_Packet::~CXFA_Packet() {}
+CXFA_Packet::~CXFA_Packet() = default;
diff --git a/xfa/fxfa/parser/cxfa_packet.h b/xfa/fxfa/parser/cxfa_packet.h
index 6bda61d..c94c74c 100644
--- a/xfa/fxfa/parser/cxfa_packet.h
+++ b/xfa/fxfa/parser/cxfa_packet.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Packet : public CXFA_Node {
+class CXFA_Packet final : public CXFA_Node {
  public:
   CXFA_Packet(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Packet() override;
diff --git a/xfa/fxfa/parser/cxfa_packets.cpp b/xfa/fxfa/parser/cxfa_packets.cpp
index 21b8b19..7981063 100644
--- a/xfa/fxfa/parser/cxfa_packets.cpp
+++ b/xfa/fxfa/parser/cxfa_packets.cpp
@@ -6,14 +6,15 @@
 
 #include "xfa/fxfa/parser/cxfa_packets.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kPacketsAttributeData[] = {
     {XFA_Attribute::Desc, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Lock, XFA_AttributeType::Integer, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"packets";
+};
 
 }  // namespace
 
@@ -23,8 +24,8 @@
                 XFA_XDPPACKET_Config,
                 XFA_ObjectType::ContentNode,
                 XFA_Element::Packets,
-                nullptr,
-                kAttributeData,
-                kName) {}
+                {},
+                kPacketsAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_Packets::~CXFA_Packets() {}
+CXFA_Packets::~CXFA_Packets() = default;
diff --git a/xfa/fxfa/parser/cxfa_packets.h b/xfa/fxfa/parser/cxfa_packets.h
index ebf29b6..5e0f408 100644
--- a/xfa/fxfa/parser/cxfa_packets.h
+++ b/xfa/fxfa/parser/cxfa_packets.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Packets : public CXFA_Node {
+class CXFA_Packets final : public CXFA_Node {
  public:
   CXFA_Packets(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Packets() override;
diff --git a/xfa/fxfa/parser/cxfa_pagearea.cpp b/xfa/fxfa/parser/cxfa_pagearea.cpp
index f82b344..cc48e89 100644
--- a/xfa/fxfa/parser/cxfa_pagearea.cpp
+++ b/xfa/fxfa/parser/cxfa_pagearea.cpp
@@ -6,33 +6,33 @@
 
 #include "xfa/fxfa/parser/cxfa_pagearea.h"
 
-#include "fxjs/xfa/cjx_pagearea.h"
+#include "fxjs/xfa/cjx_container.h"
 #include "third_party/base/ptr_util.h"
 
 namespace {
 
-const CXFA_Node::PropertyData kPropertyData[] = {{XFA_Element::Medium, 1, 0},
-                                                 {XFA_Element::Desc, 1, 0},
-                                                 {XFA_Element::Extras, 1, 0},
-                                                 {XFA_Element::Occur, 1, 0},
-                                                 {XFA_Element::Unknown, 0, 0}};
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::PropertyData kPageAreaPropertyData[] = {
+    {XFA_Element::Medium, 1, 0},
+    {XFA_Element::Desc, 1, 0},
+    {XFA_Element::Extras, 1, 0},
+    {XFA_Element::Occur, 1, 0},
+};
+
+const CXFA_Node::AttributeData kPageAreaAttributeData[] = {
     {XFA_Attribute::Id, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Name, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Use, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::PagePosition, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::Any},
+     (void*)XFA_AttributeValue::Any},
     {XFA_Attribute::OddOrEven, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::Any},
+     (void*)XFA_AttributeValue::Any},
     {XFA_Attribute::Relevant, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::InitialNumber, XFA_AttributeType::Integer, (void*)1},
     {XFA_Attribute::Usehref, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Numbered, XFA_AttributeType::Integer, (void*)1},
     {XFA_Attribute::BlankOrNotBlank, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::Any},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"pageArea";
+     (void*)XFA_AttributeValue::Any},
+};
 
 }  // namespace
 
@@ -42,9 +42,8 @@
                 (XFA_XDPPACKET_Template | XFA_XDPPACKET_Form),
                 XFA_ObjectType::ContainerNode,
                 XFA_Element::PageArea,
-                kPropertyData,
-                kAttributeData,
-                kName,
-                pdfium::MakeUnique<CJX_PageArea>(this)) {}
+                kPageAreaPropertyData,
+                kPageAreaAttributeData,
+                pdfium::MakeUnique<CJX_Container>(this)) {}
 
-CXFA_PageArea::~CXFA_PageArea() {}
+CXFA_PageArea::~CXFA_PageArea() = default;
diff --git a/xfa/fxfa/parser/cxfa_pagearea.h b/xfa/fxfa/parser/cxfa_pagearea.h
index f3cab1e..8a8afaa 100644
--- a/xfa/fxfa/parser/cxfa_pagearea.h
+++ b/xfa/fxfa/parser/cxfa_pagearea.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_PageArea : public CXFA_Node {
+class CXFA_PageArea final : public CXFA_Node {
  public:
   CXFA_PageArea(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_PageArea() override;
diff --git a/xfa/fxfa/parser/cxfa_pageoffset.cpp b/xfa/fxfa/parser/cxfa_pageoffset.cpp
index 4671019..8054b4b 100644
--- a/xfa/fxfa/parser/cxfa_pageoffset.cpp
+++ b/xfa/fxfa/parser/cxfa_pageoffset.cpp
@@ -6,16 +6,17 @@
 
 #include "xfa/fxfa/parser/cxfa_pageoffset.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kPageOffsetAttributeData[] = {
     {XFA_Attribute::X, XFA_AttributeType::Measure, (void*)L"0in"},
     {XFA_Attribute::Y, XFA_AttributeType::Measure, (void*)L"0in"},
     {XFA_Attribute::Desc, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Lock, XFA_AttributeType::Integer, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"pageOffset";
+};
 
 }  // namespace
 
@@ -25,8 +26,8 @@
                 XFA_XDPPACKET_Config,
                 XFA_ObjectType::Node,
                 XFA_Element::PageOffset,
-                nullptr,
-                kAttributeData,
-                kName) {}
+                {},
+                kPageOffsetAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_PageOffset::~CXFA_PageOffset() {}
+CXFA_PageOffset::~CXFA_PageOffset() = default;
diff --git a/xfa/fxfa/parser/cxfa_pageoffset.h b/xfa/fxfa/parser/cxfa_pageoffset.h
index a396c57..d090b11 100644
--- a/xfa/fxfa/parser/cxfa_pageoffset.h
+++ b/xfa/fxfa/parser/cxfa_pageoffset.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_PageOffset : public CXFA_Node {
+class CXFA_PageOffset final : public CXFA_Node {
  public:
   CXFA_PageOffset(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_PageOffset() override;
diff --git a/xfa/fxfa/parser/cxfa_pagerange.cpp b/xfa/fxfa/parser/cxfa_pagerange.cpp
index 5de7f5f..307b8dd 100644
--- a/xfa/fxfa/parser/cxfa_pagerange.cpp
+++ b/xfa/fxfa/parser/cxfa_pagerange.cpp
@@ -6,14 +6,15 @@
 
 #include "xfa/fxfa/parser/cxfa_pagerange.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kPageRangeAttributeData[] = {
     {XFA_Attribute::Desc, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Lock, XFA_AttributeType::Integer, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"pageRange";
+};
 
 }  // namespace
 
@@ -23,8 +24,8 @@
                 XFA_XDPPACKET_Config,
                 XFA_ObjectType::ContentNode,
                 XFA_Element::PageRange,
-                nullptr,
-                kAttributeData,
-                kName) {}
+                {},
+                kPageRangeAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_PageRange::~CXFA_PageRange() {}
+CXFA_PageRange::~CXFA_PageRange() = default;
diff --git a/xfa/fxfa/parser/cxfa_pagerange.h b/xfa/fxfa/parser/cxfa_pagerange.h
index 949276a..a0317b5 100644
--- a/xfa/fxfa/parser/cxfa_pagerange.h
+++ b/xfa/fxfa/parser/cxfa_pagerange.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_PageRange : public CXFA_Node {
+class CXFA_PageRange final : public CXFA_Node {
  public:
   CXFA_PageRange(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_PageRange() override;
diff --git a/xfa/fxfa/parser/cxfa_pageset.cpp b/xfa/fxfa/parser/cxfa_pageset.cpp
index 2fea618..1f08645 100644
--- a/xfa/fxfa/parser/cxfa_pageset.cpp
+++ b/xfa/fxfa/parser/cxfa_pageset.cpp
@@ -6,27 +6,27 @@
 
 #include "xfa/fxfa/parser/cxfa_pageset.h"
 
-#include "fxjs/xfa/cjx_pageset.h"
+#include "fxjs/xfa/cjx_container.h"
 #include "third_party/base/ptr_util.h"
 
 namespace {
 
-const CXFA_Node::PropertyData kPropertyData[] = {{XFA_Element::Extras, 1, 0},
-                                                 {XFA_Element::Occur, 1, 0},
-                                                 {XFA_Element::Unknown, 0, 0}};
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::PropertyData kPageSetPropertyData[] = {
+    {XFA_Element::Extras, 1, 0},
+    {XFA_Element::Occur, 1, 0},
+};
+
+const CXFA_Node::AttributeData kPageSetAttributeData[] = {
     {XFA_Attribute::Id, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Name, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Use, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Relation, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::OrderedOccurrence},
+     (void*)XFA_AttributeValue::OrderedOccurrence},
     {XFA_Attribute::Relevant, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::DuplexImposition, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::LongEdge},
+     (void*)XFA_AttributeValue::LongEdge},
     {XFA_Attribute::Usehref, XFA_AttributeType::CData, nullptr},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"pageSet";
+};
 
 }  // namespace
 
@@ -36,9 +36,8 @@
                 (XFA_XDPPACKET_Template | XFA_XDPPACKET_Form),
                 XFA_ObjectType::ContainerNode,
                 XFA_Element::PageSet,
-                kPropertyData,
-                kAttributeData,
-                kName,
-                pdfium::MakeUnique<CJX_PageSet>(this)) {}
+                kPageSetPropertyData,
+                kPageSetAttributeData,
+                pdfium::MakeUnique<CJX_Container>(this)) {}
 
-CXFA_PageSet::~CXFA_PageSet() {}
+CXFA_PageSet::~CXFA_PageSet() = default;
diff --git a/xfa/fxfa/parser/cxfa_pageset.h b/xfa/fxfa/parser/cxfa_pageset.h
index 9cc3b17..da71581 100644
--- a/xfa/fxfa/parser/cxfa_pageset.h
+++ b/xfa/fxfa/parser/cxfa_pageset.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_PageSet : public CXFA_Node {
+class CXFA_PageSet final : public CXFA_Node {
  public:
   CXFA_PageSet(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_PageSet() override;
diff --git a/xfa/fxfa/parser/cxfa_pagination.cpp b/xfa/fxfa/parser/cxfa_pagination.cpp
index 99600ea..1c393a1 100644
--- a/xfa/fxfa/parser/cxfa_pagination.cpp
+++ b/xfa/fxfa/parser/cxfa_pagination.cpp
@@ -6,14 +6,15 @@
 
 #include "xfa/fxfa/parser/cxfa_pagination.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kPaginationAttributeData[] = {
     {XFA_Attribute::Desc, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Lock, XFA_AttributeType::Integer, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"pagination";
+};
 
 }  // namespace
 
@@ -23,8 +24,8 @@
                 XFA_XDPPACKET_Config,
                 XFA_ObjectType::ContentNode,
                 XFA_Element::Pagination,
-                nullptr,
-                kAttributeData,
-                kName) {}
+                {},
+                kPaginationAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_Pagination::~CXFA_Pagination() {}
+CXFA_Pagination::~CXFA_Pagination() = default;
diff --git a/xfa/fxfa/parser/cxfa_pagination.h b/xfa/fxfa/parser/cxfa_pagination.h
index a455ecb..9bbd820 100644
--- a/xfa/fxfa/parser/cxfa_pagination.h
+++ b/xfa/fxfa/parser/cxfa_pagination.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Pagination : public CXFA_Node {
+class CXFA_Pagination final : public CXFA_Node {
  public:
   CXFA_Pagination(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Pagination() override;
diff --git a/xfa/fxfa/parser/cxfa_paginationoverride.cpp b/xfa/fxfa/parser/cxfa_paginationoverride.cpp
index 8e8b6c6..0dfe7f2 100644
--- a/xfa/fxfa/parser/cxfa_paginationoverride.cpp
+++ b/xfa/fxfa/parser/cxfa_paginationoverride.cpp
@@ -6,14 +6,15 @@
 
 #include "xfa/fxfa/parser/cxfa_paginationoverride.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kPaginationOverrideAttributeData[] = {
     {XFA_Attribute::Desc, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Lock, XFA_AttributeType::Integer, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"paginationOverride";
+};
 
 }  // namespace
 
@@ -24,8 +25,8 @@
                 XFA_XDPPACKET_Config,
                 XFA_ObjectType::ContentNode,
                 XFA_Element::PaginationOverride,
-                nullptr,
-                kAttributeData,
-                kName) {}
+                {},
+                kPaginationOverrideAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_PaginationOverride::~CXFA_PaginationOverride() {}
+CXFA_PaginationOverride::~CXFA_PaginationOverride() = default;
diff --git a/xfa/fxfa/parser/cxfa_paginationoverride.h b/xfa/fxfa/parser/cxfa_paginationoverride.h
index 9cc9528..4f0efba 100644
--- a/xfa/fxfa/parser/cxfa_paginationoverride.h
+++ b/xfa/fxfa/parser/cxfa_paginationoverride.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_PaginationOverride : public CXFA_Node {
+class CXFA_PaginationOverride final : public CXFA_Node {
  public:
   CXFA_PaginationOverride(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_PaginationOverride() override;
diff --git a/xfa/fxfa/parser/cxfa_para.cpp b/xfa/fxfa/parser/cxfa_para.cpp
index ad7190d..6907baf 100644
--- a/xfa/fxfa/parser/cxfa_para.cpp
+++ b/xfa/fxfa/parser/cxfa_para.cpp
@@ -6,19 +6,20 @@
 
 #include "xfa/fxfa/parser/cxfa_para.h"
 
-#include "fxjs/xfa/cjx_para.h"
+#include "fxjs/xfa/cjx_node.h"
 #include "third_party/base/ptr_util.h"
 #include "xfa/fxfa/parser/cxfa_measurement.h"
 
 namespace {
 
-const CXFA_Node::PropertyData kPropertyData[] = {
+const CXFA_Node::PropertyData kParaPropertyData[] = {
     {XFA_Element::Hyphenation, 1, 0},
-    {XFA_Element::Unknown, 0, 0}};
-const CXFA_Node::AttributeData kAttributeData[] = {
+};
+
+const CXFA_Node::AttributeData kParaAttributeData[] = {
     {XFA_Attribute::Id, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::HAlign, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::Left},
+     (void*)XFA_AttributeValue::Left},
     {XFA_Attribute::TextIndent, XFA_AttributeType::Measure, (void*)L"0in"},
     {XFA_Attribute::Use, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Widows, XFA_AttributeType::Integer, (void*)0},
@@ -28,16 +29,14 @@
     {XFA_Attribute::Preserve, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::SpaceBelow, XFA_AttributeType::Measure, (void*)L"0in"},
     {XFA_Attribute::VAlign, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::Top},
+     (void*)XFA_AttributeValue::Top},
     {XFA_Attribute::TabDefault, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::TabStops, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Orphans, XFA_AttributeType::Integer, (void*)0},
     {XFA_Attribute::Usehref, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::LineHeight, XFA_AttributeType::Measure, (void*)L"0pt"},
     {XFA_Attribute::SpaceAbove, XFA_AttributeType::Measure, (void*)L"0in"},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"para";
+};
 
 }  // namespace
 
@@ -47,47 +46,44 @@
                 (XFA_XDPPACKET_Template | XFA_XDPPACKET_Form),
                 XFA_ObjectType::Node,
                 XFA_Element::Para,
-                kPropertyData,
-                kAttributeData,
-                kName,
-                pdfium::MakeUnique<CJX_Para>(this)) {}
+                kParaPropertyData,
+                kParaAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_Para::~CXFA_Para() {}
+CXFA_Para::~CXFA_Para() = default;
 
-XFA_AttributeEnum CXFA_Para::GetHorizontalAlign() {
+XFA_AttributeValue CXFA_Para::GetHorizontalAlign() {
   return JSObject()
       ->TryEnum(XFA_Attribute::HAlign, true)
-      .value_or(XFA_AttributeEnum::Left);
+      .value_or(XFA_AttributeValue::Left);
 }
 
-XFA_AttributeEnum CXFA_Para::GetVerticalAlign() {
+XFA_AttributeValue CXFA_Para::GetVerticalAlign() {
   return JSObject()
       ->TryEnum(XFA_Attribute::VAlign, true)
-      .value_or(XFA_AttributeEnum::Top);
+      .value_or(XFA_AttributeValue::Top);
 }
 
 float CXFA_Para::GetLineHeight() {
-  return JSObject()->GetMeasure(XFA_Attribute::LineHeight).ToUnit(XFA_Unit::Pt);
+  return JSObject()->GetMeasureInUnit(XFA_Attribute::LineHeight, XFA_Unit::Pt);
 }
 
 float CXFA_Para::GetMarginLeft() {
-  return JSObject()->GetMeasure(XFA_Attribute::MarginLeft).ToUnit(XFA_Unit::Pt);
+  return JSObject()->GetMeasureInUnit(XFA_Attribute::MarginLeft, XFA_Unit::Pt);
 }
 
 float CXFA_Para::GetMarginRight() {
-  return JSObject()
-      ->GetMeasure(XFA_Attribute::MarginRight)
-      .ToUnit(XFA_Unit::Pt);
+  return JSObject()->GetMeasureInUnit(XFA_Attribute::MarginRight, XFA_Unit::Pt);
 }
 
 float CXFA_Para::GetSpaceAbove() {
-  return JSObject()->GetMeasure(XFA_Attribute::SpaceAbove).ToUnit(XFA_Unit::Pt);
+  return JSObject()->GetMeasureInUnit(XFA_Attribute::SpaceAbove, XFA_Unit::Pt);
 }
 
 float CXFA_Para::GetSpaceBelow() {
-  return JSObject()->GetMeasure(XFA_Attribute::SpaceBelow).ToUnit(XFA_Unit::Pt);
+  return JSObject()->GetMeasureInUnit(XFA_Attribute::SpaceBelow, XFA_Unit::Pt);
 }
 
 float CXFA_Para::GetTextIndent() {
-  return JSObject()->GetMeasure(XFA_Attribute::TextIndent).ToUnit(XFA_Unit::Pt);
+  return JSObject()->GetMeasureInUnit(XFA_Attribute::TextIndent, XFA_Unit::Pt);
 }
diff --git a/xfa/fxfa/parser/cxfa_para.h b/xfa/fxfa/parser/cxfa_para.h
index afb48ce..735a199 100644
--- a/xfa/fxfa/parser/cxfa_para.h
+++ b/xfa/fxfa/parser/cxfa_para.h
@@ -9,13 +9,13 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Para : public CXFA_Node {
+class CXFA_Para final : public CXFA_Node {
  public:
   CXFA_Para(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Para() override;
 
-  XFA_AttributeEnum GetHorizontalAlign();
-  XFA_AttributeEnum GetVerticalAlign();
+  XFA_AttributeValue GetHorizontalAlign();
+  XFA_AttributeValue GetVerticalAlign();
   float GetLineHeight();
   float GetMarginLeft();
   float GetMarginRight();
diff --git a/xfa/fxfa/parser/cxfa_part.cpp b/xfa/fxfa/parser/cxfa_part.cpp
index d645571..d2acf53 100644
--- a/xfa/fxfa/parser/cxfa_part.cpp
+++ b/xfa/fxfa/parser/cxfa_part.cpp
@@ -6,14 +6,15 @@
 
 #include "xfa/fxfa/parser/cxfa_part.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kPartAttributeData[] = {
     {XFA_Attribute::Desc, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Lock, XFA_AttributeType::Integer, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"part";
+};
 
 }  // namespace
 
@@ -23,8 +24,8 @@
                 XFA_XDPPACKET_Config,
                 XFA_ObjectType::ContentNode,
                 XFA_Element::Part,
-                nullptr,
-                kAttributeData,
-                kName) {}
+                {},
+                kPartAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_Part::~CXFA_Part() {}
+CXFA_Part::~CXFA_Part() = default;
diff --git a/xfa/fxfa/parser/cxfa_part.h b/xfa/fxfa/parser/cxfa_part.h
index 3db7639..99c2c59 100644
--- a/xfa/fxfa/parser/cxfa_part.h
+++ b/xfa/fxfa/parser/cxfa_part.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Part : public CXFA_Node {
+class CXFA_Part final : public CXFA_Node {
  public:
   CXFA_Part(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Part() override;
diff --git a/xfa/fxfa/parser/cxfa_password.cpp b/xfa/fxfa/parser/cxfa_password.cpp
index 3b3f719..057b818 100644
--- a/xfa/fxfa/parser/cxfa_password.cpp
+++ b/xfa/fxfa/parser/cxfa_password.cpp
@@ -6,19 +6,17 @@
 
 #include "xfa/fxfa/parser/cxfa_password.h"
 
-#include "fxjs/xfa/cjx_password.h"
+#include "fxjs/xfa/cjx_textnode.h"
 #include "third_party/base/ptr_util.h"
 
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kPasswordAttributeData[] = {
     {XFA_Attribute::Id, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Name, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Use, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Usehref, XFA_AttributeType::CData, nullptr},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"password";
+};
 
 }  // namespace
 
@@ -28,9 +26,8 @@
                 XFA_XDPPACKET_SourceSet,
                 XFA_ObjectType::TextNode,
                 XFA_Element::Password,
-                nullptr,
-                kAttributeData,
-                kName,
-                pdfium::MakeUnique<CJX_Password>(this)) {}
+                {},
+                kPasswordAttributeData,
+                pdfium::MakeUnique<CJX_TextNode>(this)) {}
 
-CXFA_Password::~CXFA_Password() {}
+CXFA_Password::~CXFA_Password() = default;
diff --git a/xfa/fxfa/parser/cxfa_password.h b/xfa/fxfa/parser/cxfa_password.h
index 904f91f..a2cbca7 100644
--- a/xfa/fxfa/parser/cxfa_password.h
+++ b/xfa/fxfa/parser/cxfa_password.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Password : public CXFA_Node {
+class CXFA_Password final : public CXFA_Node {
  public:
   CXFA_Password(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Password() override;
diff --git a/xfa/fxfa/parser/cxfa_passwordedit.cpp b/xfa/fxfa/parser/cxfa_passwordedit.cpp
index e86cd13..f8f3c5e 100644
--- a/xfa/fxfa/parser/cxfa_passwordedit.cpp
+++ b/xfa/fxfa/parser/cxfa_passwordedit.cpp
@@ -6,25 +6,25 @@
 
 #include "xfa/fxfa/parser/cxfa_passwordedit.h"
 
-#include "fxjs/xfa/cjx_passwordedit.h"
+#include "fxjs/xfa/cjx_node.h"
 #include "third_party/base/ptr_util.h"
 
 namespace {
 
-const CXFA_Node::PropertyData kPropertyData[] = {{XFA_Element::Margin, 1, 0},
-                                                 {XFA_Element::Border, 1, 0},
-                                                 {XFA_Element::Extras, 1, 0},
-                                                 {XFA_Element::Unknown, 0, 0}};
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::PropertyData kPasswordEditPropertyData[] = {
+    {XFA_Element::Margin, 1, 0},
+    {XFA_Element::Border, 1, 0},
+    {XFA_Element::Extras, 1, 0},
+};
+
+const CXFA_Node::AttributeData kPasswordEditAttributeData[] = {
     {XFA_Attribute::Id, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Use, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::PasswordChar, XFA_AttributeType::CData, (void*)L"*"},
     {XFA_Attribute::Usehref, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::HScrollPolicy, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::Auto},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"passwordEdit";
+     (void*)XFA_AttributeValue::Auto},
+};
 
 }  // namespace
 
@@ -34,8 +34,16 @@
                 (XFA_XDPPACKET_Template | XFA_XDPPACKET_Form),
                 XFA_ObjectType::Node,
                 XFA_Element::PasswordEdit,
-                kPropertyData,
-                kAttributeData,
-                kName) {}
+                kPasswordEditPropertyData,
+                kPasswordEditAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_PasswordEdit::~CXFA_PasswordEdit() {}
+CXFA_PasswordEdit::~CXFA_PasswordEdit() = default;
+
+XFA_FFWidgetType CXFA_PasswordEdit::GetDefaultFFWidgetType() const {
+  return XFA_FFWidgetType::kPasswordEdit;
+}
+
+WideString CXFA_PasswordEdit::GetPasswordChar() {
+  return JSObject()->GetCData(XFA_Attribute::PasswordChar);
+}
diff --git a/xfa/fxfa/parser/cxfa_passwordedit.h b/xfa/fxfa/parser/cxfa_passwordedit.h
index 2db05ba..fae812f 100644
--- a/xfa/fxfa/parser/cxfa_passwordedit.h
+++ b/xfa/fxfa/parser/cxfa_passwordedit.h
@@ -9,10 +9,13 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_PasswordEdit : public CXFA_Node {
+class CXFA_PasswordEdit final : public CXFA_Node {
  public:
   CXFA_PasswordEdit(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_PasswordEdit() override;
+
+  XFA_FFWidgetType GetDefaultFFWidgetType() const override;
+  WideString GetPasswordChar();
 };
 
 #endif  // XFA_FXFA_PARSER_CXFA_PASSWORDEDIT_H_
diff --git a/xfa/fxfa/parser/cxfa_pattern.cpp b/xfa/fxfa/parser/cxfa_pattern.cpp
index 4cd32cc..e6f38aa 100644
--- a/xfa/fxfa/parser/cxfa_pattern.cpp
+++ b/xfa/fxfa/parser/cxfa_pattern.cpp
@@ -6,25 +6,26 @@
 
 #include "xfa/fxfa/parser/cxfa_pattern.h"
 
-#include "fxjs/xfa/cjx_pattern.h"
+#include "core/fxge/render_defines.h"
+#include "fxjs/xfa/cjx_node.h"
 #include "third_party/base/ptr_util.h"
 #include "xfa/fxfa/parser/cxfa_color.h"
 #include "xfa/fxgraphics/cxfa_gepattern.h"
 
 namespace {
 
-const CXFA_Node::PropertyData kPropertyData[] = {{XFA_Element::Color, 1, 0},
-                                                 {XFA_Element::Extras, 1, 0},
-                                                 {XFA_Element::Unknown, 0, 0}};
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::PropertyData kPatternPropertyData[] = {
+    {XFA_Element::Color, 1, 0},
+    {XFA_Element::Extras, 1, 0},
+};
+
+const CXFA_Node::AttributeData kPatternAttributeData[] = {
     {XFA_Attribute::Id, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Use, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Type, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::CrossHatch},
+     (void*)XFA_AttributeValue::CrossHatch},
     {XFA_Attribute::Usehref, XFA_AttributeType::CData, nullptr},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"pattern";
+};
 
 }  // namespace
 
@@ -34,18 +35,17 @@
                 (XFA_XDPPACKET_Template | XFA_XDPPACKET_Form),
                 XFA_ObjectType::Node,
                 XFA_Element::Pattern,
-                kPropertyData,
-                kAttributeData,
-                kName,
-                pdfium::MakeUnique<CJX_Pattern>(this)) {}
+                kPatternPropertyData,
+                kPatternAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_Pattern::~CXFA_Pattern() {}
+CXFA_Pattern::~CXFA_Pattern() = default;
 
 CXFA_Color* CXFA_Pattern::GetColorIfExists() {
   return GetChild<CXFA_Color>(0, XFA_Element::Color, false);
 }
 
-XFA_AttributeEnum CXFA_Pattern::GetType() {
+XFA_AttributeValue CXFA_Pattern::GetType() {
   return JSObject()->GetEnum(XFA_Attribute::Type);
 }
 
@@ -59,19 +59,19 @@
 
   FX_HatchStyle iHatch = FX_HatchStyle::Cross;
   switch (GetType()) {
-    case XFA_AttributeEnum::CrossDiagonal:
+    case XFA_AttributeValue::CrossDiagonal:
       iHatch = FX_HatchStyle::DiagonalCross;
       break;
-    case XFA_AttributeEnum::DiagonalLeft:
+    case XFA_AttributeValue::DiagonalLeft:
       iHatch = FX_HatchStyle::ForwardDiagonal;
       break;
-    case XFA_AttributeEnum::DiagonalRight:
+    case XFA_AttributeValue::DiagonalRight:
       iHatch = FX_HatchStyle::BackwardDiagonal;
       break;
-    case XFA_AttributeEnum::Horizontal:
+    case XFA_AttributeValue::Horizontal:
       iHatch = FX_HatchStyle::Horizontal;
       break;
-    case XFA_AttributeEnum::Vertical:
+    case XFA_AttributeValue::Vertical:
       iHatch = FX_HatchStyle::Vertical;
       break;
     default:
diff --git a/xfa/fxfa/parser/cxfa_pattern.h b/xfa/fxfa/parser/cxfa_pattern.h
index 7533ac9..bf5c526 100644
--- a/xfa/fxfa/parser/cxfa_pattern.h
+++ b/xfa/fxfa/parser/cxfa_pattern.h
@@ -14,9 +14,10 @@
 class CXFA_Color;
 class CXFA_Graphics;
 
-class CXFA_Pattern : public CXFA_Node {
+class CXFA_Pattern final : public CXFA_Node {
  public:
-  static constexpr XFA_AttributeEnum kDefaultType = XFA_AttributeEnum::Unknown;
+  static constexpr XFA_AttributeValue kDefaultType =
+      XFA_AttributeValue::Unknown;
 
   CXFA_Pattern(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Pattern() override;
@@ -28,7 +29,7 @@
             const CFX_Matrix& matrix);
 
  private:
-  XFA_AttributeEnum GetType();
+  XFA_AttributeValue GetType();
   CXFA_Color* GetColorIfExists();
 };
 
diff --git a/xfa/fxfa/parser/cxfa_pcl.cpp b/xfa/fxfa/parser/cxfa_pcl.cpp
index 1f5e348..e55c80d 100644
--- a/xfa/fxfa/parser/cxfa_pcl.cpp
+++ b/xfa/fxfa/parser/cxfa_pcl.cpp
@@ -6,21 +6,23 @@
 
 #include "xfa/fxfa/parser/cxfa_pcl.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::PropertyData kPropertyData[] = {
+const CXFA_Node::PropertyData kPclPropertyData[] = {
     {XFA_Element::FontInfo, 1, 0},   {XFA_Element::Jog, 1, 0},
     {XFA_Element::Xdc, 1, 0},        {XFA_Element::BatchOutput, 1, 0},
     {XFA_Element::PageOffset, 1, 0}, {XFA_Element::OutputBin, 1, 0},
     {XFA_Element::Staple, 1, 0},     {XFA_Element::MediumInfo, 1, 0},
-    {XFA_Element::Unknown, 0, 0}};
-const CXFA_Node::AttributeData kAttributeData[] = {
+};
+
+const CXFA_Node::AttributeData kPclAttributeData[] = {
     {XFA_Attribute::Name, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Desc, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Lock, XFA_AttributeType::Integer, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"pcl";
+};
 
 }  // namespace
 
@@ -30,8 +32,8 @@
                 XFA_XDPPACKET_Config,
                 XFA_ObjectType::Node,
                 XFA_Element::Pcl,
-                kPropertyData,
-                kAttributeData,
-                kName) {}
+                kPclPropertyData,
+                kPclAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_Pcl::~CXFA_Pcl() {}
+CXFA_Pcl::~CXFA_Pcl() = default;
diff --git a/xfa/fxfa/parser/cxfa_pcl.h b/xfa/fxfa/parser/cxfa_pcl.h
index 9b78265..c9d94d6 100644
--- a/xfa/fxfa/parser/cxfa_pcl.h
+++ b/xfa/fxfa/parser/cxfa_pcl.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Pcl : public CXFA_Node {
+class CXFA_Pcl final : public CXFA_Node {
  public:
   CXFA_Pcl(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Pcl() override;
diff --git a/xfa/fxfa/parser/cxfa_pdf.cpp b/xfa/fxfa/parser/cxfa_pdf.cpp
index 800d393..499893c 100644
--- a/xfa/fxfa/parser/cxfa_pdf.cpp
+++ b/xfa/fxfa/parser/cxfa_pdf.cpp
@@ -6,9 +6,12 @@
 
 #include "xfa/fxfa/parser/cxfa_pdf.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::PropertyData kPropertyData[] = {
+const CXFA_Node::PropertyData kPdfPropertyData[] = {
     {XFA_Element::AdobeExtensionLevel, 1, 0},
     {XFA_Element::FontInfo, 1, 0},
     {XFA_Element::Xdc, 1, 0},
@@ -28,14 +31,13 @@
     {XFA_Element::Creator, 1, 0},
     {XFA_Element::Linearized, 1, 0},
     {XFA_Element::Tagged, 1, 0},
-    {XFA_Element::Unknown, 0, 0}};
-const CXFA_Node::AttributeData kAttributeData[] = {
+};
+
+const CXFA_Node::AttributeData kPdfAttributeData[] = {
     {XFA_Attribute::Name, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Desc, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Lock, XFA_AttributeType::Integer, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"pdf";
+};
 
 }  // namespace
 
@@ -45,8 +47,8 @@
                 XFA_XDPPACKET_Config,
                 XFA_ObjectType::Node,
                 XFA_Element::Pdf,
-                kPropertyData,
-                kAttributeData,
-                kName) {}
+                kPdfPropertyData,
+                kPdfAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_Pdf::~CXFA_Pdf() {}
+CXFA_Pdf::~CXFA_Pdf() = default;
diff --git a/xfa/fxfa/parser/cxfa_pdf.h b/xfa/fxfa/parser/cxfa_pdf.h
index d0925c8..00e4d38 100644
--- a/xfa/fxfa/parser/cxfa_pdf.h
+++ b/xfa/fxfa/parser/cxfa_pdf.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Pdf : public CXFA_Node {
+class CXFA_Pdf final : public CXFA_Node {
  public:
   CXFA_Pdf(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Pdf() override;
diff --git a/xfa/fxfa/parser/cxfa_pdfa.cpp b/xfa/fxfa/parser/cxfa_pdfa.cpp
index f41eb93..77d723f 100644
--- a/xfa/fxfa/parser/cxfa_pdfa.cpp
+++ b/xfa/fxfa/parser/cxfa_pdfa.cpp
@@ -6,20 +6,22 @@
 
 #include "xfa/fxfa/parser/cxfa_pdfa.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::PropertyData kPropertyData[] = {
+const CXFA_Node::PropertyData kPdfaPropertyData[] = {
     {XFA_Element::Amd, 1, 0},
     {XFA_Element::Part, 1, 0},
     {XFA_Element::IncludeXDPContent, 1, 0},
     {XFA_Element::Conformance, 1, 0},
-    {XFA_Element::Unknown, 0, 0}};
-const CXFA_Node::AttributeData kAttributeData[] = {
+};
+
+const CXFA_Node::AttributeData kPdfaAttributeData[] = {
     {XFA_Attribute::Desc, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Lock, XFA_AttributeType::Integer, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"pdfa";
+};
 
 }  // namespace
 
@@ -29,8 +31,8 @@
                 XFA_XDPPACKET_Config,
                 XFA_ObjectType::Node,
                 XFA_Element::Pdfa,
-                kPropertyData,
-                kAttributeData,
-                kName) {}
+                kPdfaPropertyData,
+                kPdfaAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_Pdfa::~CXFA_Pdfa() {}
+CXFA_Pdfa::~CXFA_Pdfa() = default;
diff --git a/xfa/fxfa/parser/cxfa_pdfa.h b/xfa/fxfa/parser/cxfa_pdfa.h
index d0816a2..e43f025 100644
--- a/xfa/fxfa/parser/cxfa_pdfa.h
+++ b/xfa/fxfa/parser/cxfa_pdfa.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Pdfa : public CXFA_Node {
+class CXFA_Pdfa final : public CXFA_Node {
  public:
   CXFA_Pdfa(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Pdfa() override;
diff --git a/xfa/fxfa/parser/cxfa_permissions.cpp b/xfa/fxfa/parser/cxfa_permissions.cpp
index a56ac32..06e3a08 100644
--- a/xfa/fxfa/parser/cxfa_permissions.cpp
+++ b/xfa/fxfa/parser/cxfa_permissions.cpp
@@ -6,9 +6,12 @@
 
 #include "xfa/fxfa/parser/cxfa_permissions.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::PropertyData kPropertyData[] = {
+const CXFA_Node::PropertyData kPermissionsPropertyData[] = {
     {XFA_Element::ModifyAnnots, 1, 0},
     {XFA_Element::ContentCopy, 1, 0},
     {XFA_Element::FormFieldFilling, 1, 0},
@@ -18,13 +21,12 @@
     {XFA_Element::PlaintextMetadata, 1, 0},
     {XFA_Element::PrintHighQuality, 1, 0},
     {XFA_Element::DocumentAssembly, 1, 0},
-    {XFA_Element::Unknown, 0, 0}};
-const CXFA_Node::AttributeData kAttributeData[] = {
+};
+
+const CXFA_Node::AttributeData kPermissionsAttributeData[] = {
     {XFA_Attribute::Desc, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Lock, XFA_AttributeType::Integer, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"permissions";
+};
 
 }  // namespace
 
@@ -34,8 +36,8 @@
                 XFA_XDPPACKET_Config,
                 XFA_ObjectType::Node,
                 XFA_Element::Permissions,
-                kPropertyData,
-                kAttributeData,
-                kName) {}
+                kPermissionsPropertyData,
+                kPermissionsAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_Permissions::~CXFA_Permissions() {}
+CXFA_Permissions::~CXFA_Permissions() = default;
diff --git a/xfa/fxfa/parser/cxfa_permissions.h b/xfa/fxfa/parser/cxfa_permissions.h
index dca9018..79b3bf1 100644
--- a/xfa/fxfa/parser/cxfa_permissions.h
+++ b/xfa/fxfa/parser/cxfa_permissions.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Permissions : public CXFA_Node {
+class CXFA_Permissions final : public CXFA_Node {
  public:
   CXFA_Permissions(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Permissions() override;
diff --git a/xfa/fxfa/parser/cxfa_picktraybypdfsize.cpp b/xfa/fxfa/parser/cxfa_picktraybypdfsize.cpp
index b4e5ec2..3b2b7a3 100644
--- a/xfa/fxfa/parser/cxfa_picktraybypdfsize.cpp
+++ b/xfa/fxfa/parser/cxfa_picktraybypdfsize.cpp
@@ -6,14 +6,15 @@
 
 #include "xfa/fxfa/parser/cxfa_picktraybypdfsize.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kPickTrayByPDFSizeAttributeData[] = {
     {XFA_Attribute::Desc, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Lock, XFA_AttributeType::Integer, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"pickTrayByPDFSize";
+};
 
 }  // namespace
 
@@ -24,8 +25,8 @@
                 XFA_XDPPACKET_Config,
                 XFA_ObjectType::ContentNode,
                 XFA_Element::PickTrayByPDFSize,
-                nullptr,
-                kAttributeData,
-                kName) {}
+                {},
+                kPickTrayByPDFSizeAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_PickTrayByPDFSize::~CXFA_PickTrayByPDFSize() {}
+CXFA_PickTrayByPDFSize::~CXFA_PickTrayByPDFSize() = default;
diff --git a/xfa/fxfa/parser/cxfa_picktraybypdfsize.h b/xfa/fxfa/parser/cxfa_picktraybypdfsize.h
index ef75e5c..3871552 100644
--- a/xfa/fxfa/parser/cxfa_picktraybypdfsize.h
+++ b/xfa/fxfa/parser/cxfa_picktraybypdfsize.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_PickTrayByPDFSize : public CXFA_Node {
+class CXFA_PickTrayByPDFSize final : public CXFA_Node {
  public:
   CXFA_PickTrayByPDFSize(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_PickTrayByPDFSize() override;
diff --git a/xfa/fxfa/parser/cxfa_picture.cpp b/xfa/fxfa/parser/cxfa_picture.cpp
index 4863a77..a1005ec 100644
--- a/xfa/fxfa/parser/cxfa_picture.cpp
+++ b/xfa/fxfa/parser/cxfa_picture.cpp
@@ -6,20 +6,18 @@
 
 #include "xfa/fxfa/parser/cxfa_picture.h"
 
-#include "fxjs/xfa/cjx_picture.h"
+#include "fxjs/xfa/cjx_node.h"
 #include "third_party/base/ptr_util.h"
 
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kPictureAttributeData[] = {
     {XFA_Attribute::Id, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Use, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Usehref, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Desc, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Lock, XFA_AttributeType::Integer, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"picture";
+};
 
 }  // namespace
 
@@ -30,9 +28,8 @@
           (XFA_XDPPACKET_Config | XFA_XDPPACKET_Template | XFA_XDPPACKET_Form),
           XFA_ObjectType::ContentNode,
           XFA_Element::Picture,
-          nullptr,
-          kAttributeData,
-          kName,
-          pdfium::MakeUnique<CJX_Picture>(this)) {}
+          {},
+          kPictureAttributeData,
+          pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_Picture::~CXFA_Picture() {}
+CXFA_Picture::~CXFA_Picture() = default;
diff --git a/xfa/fxfa/parser/cxfa_picture.h b/xfa/fxfa/parser/cxfa_picture.h
index 9fd2c55..304c7b9 100644
--- a/xfa/fxfa/parser/cxfa_picture.h
+++ b/xfa/fxfa/parser/cxfa_picture.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Picture : public CXFA_Node {
+class CXFA_Picture final : public CXFA_Node {
  public:
   CXFA_Picture(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Picture() override;
diff --git a/xfa/fxfa/parser/cxfa_plaintextmetadata.cpp b/xfa/fxfa/parser/cxfa_plaintextmetadata.cpp
index a5c51dd..75abb78 100644
--- a/xfa/fxfa/parser/cxfa_plaintextmetadata.cpp
+++ b/xfa/fxfa/parser/cxfa_plaintextmetadata.cpp
@@ -6,14 +6,15 @@
 
 #include "xfa/fxfa/parser/cxfa_plaintextmetadata.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kPlaintextMetadataAttributeData[] = {
     {XFA_Attribute::Desc, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Lock, XFA_AttributeType::Integer, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"plaintextMetadata";
+};
 
 }  // namespace
 
@@ -24,8 +25,8 @@
                 XFA_XDPPACKET_Config,
                 XFA_ObjectType::ContentNode,
                 XFA_Element::PlaintextMetadata,
-                nullptr,
-                kAttributeData,
-                kName) {}
+                {},
+                kPlaintextMetadataAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_PlaintextMetadata::~CXFA_PlaintextMetadata() {}
+CXFA_PlaintextMetadata::~CXFA_PlaintextMetadata() = default;
diff --git a/xfa/fxfa/parser/cxfa_plaintextmetadata.h b/xfa/fxfa/parser/cxfa_plaintextmetadata.h
index 03dce65..65e0ded 100644
--- a/xfa/fxfa/parser/cxfa_plaintextmetadata.h
+++ b/xfa/fxfa/parser/cxfa_plaintextmetadata.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_PlaintextMetadata : public CXFA_Node {
+class CXFA_PlaintextMetadata final : public CXFA_Node {
  public:
   CXFA_PlaintextMetadata(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_PlaintextMetadata() override;
diff --git a/xfa/fxfa/parser/cxfa_presence.cpp b/xfa/fxfa/parser/cxfa_presence.cpp
index f2389d9..99353a6 100644
--- a/xfa/fxfa/parser/cxfa_presence.cpp
+++ b/xfa/fxfa/parser/cxfa_presence.cpp
@@ -6,14 +6,15 @@
 
 #include "xfa/fxfa/parser/cxfa_presence.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kPresenceAttributeData[] = {
     {XFA_Attribute::Desc, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Lock, XFA_AttributeType::Integer, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"presence";
+};
 
 }  // namespace
 
@@ -23,8 +24,8 @@
                 XFA_XDPPACKET_Config,
                 XFA_ObjectType::NodeV,
                 XFA_Element::Presence,
-                nullptr,
-                kAttributeData,
-                kName) {}
+                {},
+                kPresenceAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_Presence::~CXFA_Presence() {}
+CXFA_Presence::~CXFA_Presence() = default;
diff --git a/xfa/fxfa/parser/cxfa_presence.h b/xfa/fxfa/parser/cxfa_presence.h
index a9b7766..1bd6e45 100644
--- a/xfa/fxfa/parser/cxfa_presence.h
+++ b/xfa/fxfa/parser/cxfa_presence.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Presence : public CXFA_Node {
+class CXFA_Presence final : public CXFA_Node {
  public:
   CXFA_Presence(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Presence() override;
diff --git a/xfa/fxfa/parser/cxfa_present.cpp b/xfa/fxfa/parser/cxfa_present.cpp
index 7552a79..e645f55 100644
--- a/xfa/fxfa/parser/cxfa_present.cpp
+++ b/xfa/fxfa/parser/cxfa_present.cpp
@@ -6,9 +6,12 @@
 
 #include "xfa/fxfa/parser/cxfa_present.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::PropertyData kPropertyData[] = {
+const CXFA_Node::PropertyData kPresentPropertyData[] = {
     {XFA_Element::Xdp, 1, 0},
     {XFA_Element::Cache, 1, 0},
     {XFA_Element::Pagination, 1, 0},
@@ -23,13 +26,12 @@
     {XFA_Element::PaginationOverride, 1, 0},
     {XFA_Element::Destination, 1, 0},
     {XFA_Element::IncrementalMerge, 1, 0},
-    {XFA_Element::Unknown, 0, 0}};
-const CXFA_Node::AttributeData kAttributeData[] = {
+};
+
+const CXFA_Node::AttributeData kPresentAttributeData[] = {
     {XFA_Attribute::Desc, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Lock, XFA_AttributeType::Integer, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"present";
+};
 
 }  // namespace
 
@@ -39,8 +41,8 @@
                 XFA_XDPPACKET_Config,
                 XFA_ObjectType::Node,
                 XFA_Element::Present,
-                kPropertyData,
-                kAttributeData,
-                kName) {}
+                kPresentPropertyData,
+                kPresentAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_Present::~CXFA_Present() {}
+CXFA_Present::~CXFA_Present() = default;
diff --git a/xfa/fxfa/parser/cxfa_present.h b/xfa/fxfa/parser/cxfa_present.h
index 13b3c61..36db503 100644
--- a/xfa/fxfa/parser/cxfa_present.h
+++ b/xfa/fxfa/parser/cxfa_present.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Present : public CXFA_Node {
+class CXFA_Present final : public CXFA_Node {
  public:
   CXFA_Present(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Present() override;
diff --git a/xfa/fxfa/parser/cxfa_print.cpp b/xfa/fxfa/parser/cxfa_print.cpp
index f90186d..227af1e 100644
--- a/xfa/fxfa/parser/cxfa_print.cpp
+++ b/xfa/fxfa/parser/cxfa_print.cpp
@@ -6,14 +6,15 @@
 
 #include "xfa/fxfa/parser/cxfa_print.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kPrintAttributeData[] = {
     {XFA_Attribute::Desc, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Lock, XFA_AttributeType::Integer, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"print";
+};
 
 }  // namespace
 
@@ -23,8 +24,8 @@
                 XFA_XDPPACKET_Config,
                 XFA_ObjectType::ContentNode,
                 XFA_Element::Print,
-                nullptr,
-                kAttributeData,
-                kName) {}
+                {},
+                kPrintAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_Print::~CXFA_Print() {}
+CXFA_Print::~CXFA_Print() = default;
diff --git a/xfa/fxfa/parser/cxfa_print.h b/xfa/fxfa/parser/cxfa_print.h
index 5f2513e..7f6fff9 100644
--- a/xfa/fxfa/parser/cxfa_print.h
+++ b/xfa/fxfa/parser/cxfa_print.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Print : public CXFA_Node {
+class CXFA_Print final : public CXFA_Node {
  public:
   CXFA_Print(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Print() override;
diff --git a/xfa/fxfa/parser/cxfa_printername.cpp b/xfa/fxfa/parser/cxfa_printername.cpp
index a5e6197..b434d26 100644
--- a/xfa/fxfa/parser/cxfa_printername.cpp
+++ b/xfa/fxfa/parser/cxfa_printername.cpp
@@ -6,14 +6,15 @@
 
 #include "xfa/fxfa/parser/cxfa_printername.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kPrinterNameAttributeData[] = {
     {XFA_Attribute::Desc, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Lock, XFA_AttributeType::Integer, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"printerName";
+};
 
 }  // namespace
 
@@ -23,8 +24,8 @@
                 XFA_XDPPACKET_Config,
                 XFA_ObjectType::ContentNode,
                 XFA_Element::PrinterName,
-                nullptr,
-                kAttributeData,
-                kName) {}
+                {},
+                kPrinterNameAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_PrinterName::~CXFA_PrinterName() {}
+CXFA_PrinterName::~CXFA_PrinterName() = default;
diff --git a/xfa/fxfa/parser/cxfa_printername.h b/xfa/fxfa/parser/cxfa_printername.h
index 4f07885..a85d61e 100644
--- a/xfa/fxfa/parser/cxfa_printername.h
+++ b/xfa/fxfa/parser/cxfa_printername.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_PrinterName : public CXFA_Node {
+class CXFA_PrinterName final : public CXFA_Node {
  public:
   CXFA_PrinterName(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_PrinterName() override;
diff --git a/xfa/fxfa/parser/cxfa_printhighquality.cpp b/xfa/fxfa/parser/cxfa_printhighquality.cpp
index 8b1184f..38d16f5 100644
--- a/xfa/fxfa/parser/cxfa_printhighquality.cpp
+++ b/xfa/fxfa/parser/cxfa_printhighquality.cpp
@@ -6,14 +6,15 @@
 
 #include "xfa/fxfa/parser/cxfa_printhighquality.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kPrintHighQualityAttributeData[] = {
     {XFA_Attribute::Desc, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Lock, XFA_AttributeType::Integer, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"printHighQuality";
+};
 
 }  // namespace
 
@@ -24,8 +25,8 @@
                 XFA_XDPPACKET_Config,
                 XFA_ObjectType::ContentNode,
                 XFA_Element::PrintHighQuality,
-                nullptr,
-                kAttributeData,
-                kName) {}
+                {},
+                kPrintHighQualityAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_PrintHighQuality::~CXFA_PrintHighQuality() {}
+CXFA_PrintHighQuality::~CXFA_PrintHighQuality() = default;
diff --git a/xfa/fxfa/parser/cxfa_printhighquality.h b/xfa/fxfa/parser/cxfa_printhighquality.h
index 6cd61125..6268489 100644
--- a/xfa/fxfa/parser/cxfa_printhighquality.h
+++ b/xfa/fxfa/parser/cxfa_printhighquality.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_PrintHighQuality : public CXFA_Node {
+class CXFA_PrintHighQuality final : public CXFA_Node {
  public:
   CXFA_PrintHighQuality(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_PrintHighQuality() override;
diff --git a/xfa/fxfa/parser/cxfa_printscaling.cpp b/xfa/fxfa/parser/cxfa_printscaling.cpp
index 8d68f68..a6641a3 100644
--- a/xfa/fxfa/parser/cxfa_printscaling.cpp
+++ b/xfa/fxfa/parser/cxfa_printscaling.cpp
@@ -6,14 +6,15 @@
 
 #include "xfa/fxfa/parser/cxfa_printscaling.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kPrintScalingAttributeData[] = {
     {XFA_Attribute::Desc, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Lock, XFA_AttributeType::Integer, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"printScaling";
+};
 
 }  // namespace
 
@@ -23,8 +24,8 @@
                 XFA_XDPPACKET_Config,
                 XFA_ObjectType::ContentNode,
                 XFA_Element::PrintScaling,
-                nullptr,
-                kAttributeData,
-                kName) {}
+                {},
+                kPrintScalingAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_PrintScaling::~CXFA_PrintScaling() {}
+CXFA_PrintScaling::~CXFA_PrintScaling() = default;
diff --git a/xfa/fxfa/parser/cxfa_printscaling.h b/xfa/fxfa/parser/cxfa_printscaling.h
index e21d427..76bf112 100644
--- a/xfa/fxfa/parser/cxfa_printscaling.h
+++ b/xfa/fxfa/parser/cxfa_printscaling.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_PrintScaling : public CXFA_Node {
+class CXFA_PrintScaling final : public CXFA_Node {
  public:
   CXFA_PrintScaling(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_PrintScaling() override;
diff --git a/xfa/fxfa/parser/cxfa_producer.cpp b/xfa/fxfa/parser/cxfa_producer.cpp
index 45253c7..07ed6e5 100644
--- a/xfa/fxfa/parser/cxfa_producer.cpp
+++ b/xfa/fxfa/parser/cxfa_producer.cpp
@@ -6,14 +6,15 @@
 
 #include "xfa/fxfa/parser/cxfa_producer.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kProducerAttributeData[] = {
     {XFA_Attribute::Desc, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Lock, XFA_AttributeType::Integer, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"producer";
+};
 
 }  // namespace
 
@@ -23,8 +24,8 @@
                 XFA_XDPPACKET_Config,
                 XFA_ObjectType::ContentNode,
                 XFA_Element::Producer,
-                nullptr,
-                kAttributeData,
-                kName) {}
+                {},
+                kProducerAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_Producer::~CXFA_Producer() {}
+CXFA_Producer::~CXFA_Producer() = default;
diff --git a/xfa/fxfa/parser/cxfa_producer.h b/xfa/fxfa/parser/cxfa_producer.h
index 584826e..c40a334 100644
--- a/xfa/fxfa/parser/cxfa_producer.h
+++ b/xfa/fxfa/parser/cxfa_producer.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Producer : public CXFA_Node {
+class CXFA_Producer final : public CXFA_Node {
  public:
   CXFA_Producer(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Producer() override;
diff --git a/xfa/fxfa/parser/cxfa_proto.cpp b/xfa/fxfa/parser/cxfa_proto.cpp
index 6d103e7..c59ae13 100644
--- a/xfa/fxfa/parser/cxfa_proto.cpp
+++ b/xfa/fxfa/parser/cxfa_proto.cpp
@@ -6,11 +6,8 @@
 
 #include "xfa/fxfa/parser/cxfa_proto.h"
 
-namespace {
-
-constexpr wchar_t kName[] = L"proto";
-
-}  // namespace
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
 
 CXFA_Proto::CXFA_Proto(CXFA_Document* doc, XFA_PacketType packet)
     : CXFA_Node(doc,
@@ -18,8 +15,8 @@
                 (XFA_XDPPACKET_Template | XFA_XDPPACKET_Form),
                 XFA_ObjectType::Node,
                 XFA_Element::Proto,
-                nullptr,
-                nullptr,
-                kName) {}
+                {},
+                {},
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_Proto::~CXFA_Proto() {}
+CXFA_Proto::~CXFA_Proto() = default;
diff --git a/xfa/fxfa/parser/cxfa_proto.h b/xfa/fxfa/parser/cxfa_proto.h
index 8e1d84a..5af7ba2 100644
--- a/xfa/fxfa/parser/cxfa_proto.h
+++ b/xfa/fxfa/parser/cxfa_proto.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Proto : public CXFA_Node {
+class CXFA_Proto final : public CXFA_Node {
  public:
   CXFA_Proto(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Proto() override;
diff --git a/xfa/fxfa/parser/cxfa_ps.cpp b/xfa/fxfa/parser/cxfa_ps.cpp
index 1b2f532..35e5da3 100644
--- a/xfa/fxfa/parser/cxfa_ps.cpp
+++ b/xfa/fxfa/parser/cxfa_ps.cpp
@@ -6,21 +6,23 @@
 
 #include "xfa/fxfa/parser/cxfa_ps.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::PropertyData kPropertyData[] = {
+const CXFA_Node::PropertyData kPsPropertyData[] = {
     {XFA_Element::FontInfo, 1, 0},  {XFA_Element::Jog, 1, 0},
     {XFA_Element::Xdc, 1, 0},       {XFA_Element::BatchOutput, 1, 0},
     {XFA_Element::OutputBin, 1, 0}, {XFA_Element::Compress, 1, 0},
     {XFA_Element::Staple, 1, 0},    {XFA_Element::MediumInfo, 1, 0},
-    {XFA_Element::Unknown, 0, 0}};
-const CXFA_Node::AttributeData kAttributeData[] = {
+};
+
+const CXFA_Node::AttributeData kPsAttributeData[] = {
     {XFA_Attribute::Name, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Desc, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Lock, XFA_AttributeType::Integer, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"ps";
+};
 
 }  // namespace
 
@@ -30,8 +32,8 @@
                 XFA_XDPPACKET_Config,
                 XFA_ObjectType::Node,
                 XFA_Element::Ps,
-                kPropertyData,
-                kAttributeData,
-                kName) {}
+                kPsPropertyData,
+                kPsAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_Ps::~CXFA_Ps() {}
+CXFA_Ps::~CXFA_Ps() = default;
diff --git a/xfa/fxfa/parser/cxfa_ps.h b/xfa/fxfa/parser/cxfa_ps.h
index 5ef7e82..f51c510 100644
--- a/xfa/fxfa/parser/cxfa_ps.h
+++ b/xfa/fxfa/parser/cxfa_ps.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Ps : public CXFA_Node {
+class CXFA_Ps final : public CXFA_Node {
  public:
   CXFA_Ps(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Ps() override;
diff --git a/xfa/fxfa/parser/cxfa_psmap.cpp b/xfa/fxfa/parser/cxfa_psmap.cpp
index 0c0b122..12ca00b 100644
--- a/xfa/fxfa/parser/cxfa_psmap.cpp
+++ b/xfa/fxfa/parser/cxfa_psmap.cpp
@@ -6,11 +6,8 @@
 
 #include "xfa/fxfa/parser/cxfa_psmap.h"
 
-namespace {
-
-constexpr wchar_t kName[] = L"psMap";
-
-}  // namespace
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
 
 CXFA_PsMap::CXFA_PsMap(CXFA_Document* doc, XFA_PacketType packet)
     : CXFA_Node(doc,
@@ -18,8 +15,8 @@
                 XFA_XDPPACKET_Config,
                 XFA_ObjectType::Node,
                 XFA_Element::PsMap,
-                nullptr,
-                nullptr,
-                kName) {}
+                {},
+                {},
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_PsMap::~CXFA_PsMap() {}
+CXFA_PsMap::~CXFA_PsMap() = default;
diff --git a/xfa/fxfa/parser/cxfa_psmap.h b/xfa/fxfa/parser/cxfa_psmap.h
index 8297aaa..802e123 100644
--- a/xfa/fxfa/parser/cxfa_psmap.h
+++ b/xfa/fxfa/parser/cxfa_psmap.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_PsMap : public CXFA_Node {
+class CXFA_PsMap final : public CXFA_Node {
  public:
   CXFA_PsMap(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_PsMap() override;
diff --git a/xfa/fxfa/parser/cxfa_query.cpp b/xfa/fxfa/parser/cxfa_query.cpp
index 5e18565..7f2db0b 100644
--- a/xfa/fxfa/parser/cxfa_query.cpp
+++ b/xfa/fxfa/parser/cxfa_query.cpp
@@ -6,24 +6,24 @@
 
 #include "xfa/fxfa/parser/cxfa_query.h"
 
-#include "fxjs/xfa/cjx_query.h"
+#include "fxjs/xfa/cjx_node.h"
 #include "third_party/base/ptr_util.h"
 
 namespace {
 
-const CXFA_Node::PropertyData kPropertyData[] = {{XFA_Element::RecordSet, 1, 0},
-                                                 {XFA_Element::Select, 1, 0},
-                                                 {XFA_Element::Unknown, 0, 0}};
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::PropertyData kQueryPropertyData[] = {
+    {XFA_Element::RecordSet, 1, 0},
+    {XFA_Element::Select, 1, 0},
+};
+
+const CXFA_Node::AttributeData kQueryAttributeData[] = {
     {XFA_Attribute::Id, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Name, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Use, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::CommandType, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::Unknown},
+     (void*)XFA_AttributeValue::Unknown},
     {XFA_Attribute::Usehref, XFA_AttributeType::CData, nullptr},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"query";
+};
 
 }  // namespace
 
@@ -33,9 +33,8 @@
                 XFA_XDPPACKET_SourceSet,
                 XFA_ObjectType::Node,
                 XFA_Element::Query,
-                kPropertyData,
-                kAttributeData,
-                kName,
-                pdfium::MakeUnique<CJX_Query>(this)) {}
+                kQueryPropertyData,
+                kQueryAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_Query::~CXFA_Query() {}
+CXFA_Query::~CXFA_Query() = default;
diff --git a/xfa/fxfa/parser/cxfa_query.h b/xfa/fxfa/parser/cxfa_query.h
index 548e7fc..7d62c68 100644
--- a/xfa/fxfa/parser/cxfa_query.h
+++ b/xfa/fxfa/parser/cxfa_query.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Query : public CXFA_Node {
+class CXFA_Query final : public CXFA_Node {
  public:
   CXFA_Query(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Query() override;
diff --git a/xfa/fxfa/parser/cxfa_radial.cpp b/xfa/fxfa/parser/cxfa_radial.cpp
index 3d024e7..4eb944f 100644
--- a/xfa/fxfa/parser/cxfa_radial.cpp
+++ b/xfa/fxfa/parser/cxfa_radial.cpp
@@ -8,25 +8,26 @@
 
 #include <utility>
 
-#include "fxjs/xfa/cjx_radial.h"
+#include "core/fxge/render_defines.h"
+#include "fxjs/xfa/cjx_node.h"
 #include "third_party/base/ptr_util.h"
 #include "xfa/fxfa/parser/cxfa_color.h"
 #include "xfa/fxgraphics/cxfa_geshading.h"
 
 namespace {
 
-const CXFA_Node::PropertyData kPropertyData[] = {{XFA_Element::Color, 1, 0},
-                                                 {XFA_Element::Extras, 1, 0},
-                                                 {XFA_Element::Unknown, 0, 0}};
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::PropertyData kRadialPropertyData[] = {
+    {XFA_Element::Color, 1, 0},
+    {XFA_Element::Extras, 1, 0},
+};
+
+const CXFA_Node::AttributeData kRadialAttributeData[] = {
     {XFA_Attribute::Id, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Use, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Type, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::ToEdge},
+     (void*)XFA_AttributeValue::ToEdge},
     {XFA_Attribute::Usehref, XFA_AttributeType::CData, nullptr},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"radial";
+};
 
 }  // namespace
 
@@ -36,17 +37,15 @@
                 (XFA_XDPPACKET_Template | XFA_XDPPACKET_Form),
                 XFA_ObjectType::Node,
                 XFA_Element::Radial,
-                kPropertyData,
-                kAttributeData,
-                kName,
-                pdfium::MakeUnique<CJX_Radial>(this)) {}
+                kRadialPropertyData,
+                kRadialAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_Radial::~CXFA_Radial() {}
+CXFA_Radial::~CXFA_Radial() = default;
 
 bool CXFA_Radial::IsToEdge() {
-  return JSObject()
-             ->TryEnum(XFA_Attribute::Type, true)
-             .value_or(XFA_AttributeEnum::ToEdge) == XFA_AttributeEnum::ToEdge;
+  auto value = JSObject()->TryEnum(XFA_Attribute::Type, true);
+  return !value.has_value() || value.value() == XFA_AttributeValue::ToEdge;
 }
 
 CXFA_Color* CXFA_Radial::GetColorIfExists() {
diff --git a/xfa/fxfa/parser/cxfa_radial.h b/xfa/fxfa/parser/cxfa_radial.h
index b7ce95c..8fb30b5 100644
--- a/xfa/fxfa/parser/cxfa_radial.h
+++ b/xfa/fxfa/parser/cxfa_radial.h
@@ -14,7 +14,7 @@
 class CXFA_Color;
 class CXFA_Graphics;
 
-class CXFA_Radial : public CXFA_Node {
+class CXFA_Radial final : public CXFA_Node {
  public:
   CXFA_Radial(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Radial() override;
diff --git a/xfa/fxfa/parser/cxfa_range.cpp b/xfa/fxfa/parser/cxfa_range.cpp
index bd5f870..9f62b1d 100644
--- a/xfa/fxfa/parser/cxfa_range.cpp
+++ b/xfa/fxfa/parser/cxfa_range.cpp
@@ -6,14 +6,15 @@
 
 #include "xfa/fxfa/parser/cxfa_range.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kRangeAttributeData[] = {
     {XFA_Attribute::Desc, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Lock, XFA_AttributeType::Integer, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"range";
+};
 
 }  // namespace
 
@@ -23,8 +24,8 @@
                 XFA_XDPPACKET_Config,
                 XFA_ObjectType::NodeV,
                 XFA_Element::Range,
-                nullptr,
-                kAttributeData,
-                kName) {}
+                {},
+                kRangeAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_Range::~CXFA_Range() {}
+CXFA_Range::~CXFA_Range() = default;
diff --git a/xfa/fxfa/parser/cxfa_range.h b/xfa/fxfa/parser/cxfa_range.h
index 23c8d1f..5d8920d 100644
--- a/xfa/fxfa/parser/cxfa_range.h
+++ b/xfa/fxfa/parser/cxfa_range.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Range : public CXFA_Node {
+class CXFA_Range final : public CXFA_Node {
  public:
   CXFA_Range(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Range() override;
diff --git a/xfa/fxfa/parser/cxfa_reason.cpp b/xfa/fxfa/parser/cxfa_reason.cpp
index 625ede9..8af61ba 100644
--- a/xfa/fxfa/parser/cxfa_reason.cpp
+++ b/xfa/fxfa/parser/cxfa_reason.cpp
@@ -6,19 +6,17 @@
 
 #include "xfa/fxfa/parser/cxfa_reason.h"
 
-#include "fxjs/xfa/cjx_reason.h"
+#include "fxjs/xfa/cjx_textnode.h"
 #include "third_party/base/ptr_util.h"
 
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kReasonAttributeData[] = {
     {XFA_Attribute::Id, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Name, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Use, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Usehref, XFA_AttributeType::CData, nullptr},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"reason";
+};
 
 }  // namespace
 
@@ -28,9 +26,8 @@
                 (XFA_XDPPACKET_Template | XFA_XDPPACKET_Form),
                 XFA_ObjectType::TextNode,
                 XFA_Element::Reason,
-                nullptr,
-                kAttributeData,
-                kName,
-                pdfium::MakeUnique<CJX_Reason>(this)) {}
+                {},
+                kReasonAttributeData,
+                pdfium::MakeUnique<CJX_TextNode>(this)) {}
 
-CXFA_Reason::~CXFA_Reason() {}
+CXFA_Reason::~CXFA_Reason() = default;
diff --git a/xfa/fxfa/parser/cxfa_reason.h b/xfa/fxfa/parser/cxfa_reason.h
index 451fd82..1475637 100644
--- a/xfa/fxfa/parser/cxfa_reason.h
+++ b/xfa/fxfa/parser/cxfa_reason.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Reason : public CXFA_Node {
+class CXFA_Reason final : public CXFA_Node {
  public:
   CXFA_Reason(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Reason() override;
diff --git a/xfa/fxfa/parser/cxfa_reasons.cpp b/xfa/fxfa/parser/cxfa_reasons.cpp
index bd3d761..704f411 100644
--- a/xfa/fxfa/parser/cxfa_reasons.cpp
+++ b/xfa/fxfa/parser/cxfa_reasons.cpp
@@ -6,20 +6,18 @@
 
 #include "xfa/fxfa/parser/cxfa_reasons.h"
 
-#include "fxjs/xfa/cjx_reasons.h"
+#include "fxjs/xfa/cjx_node.h"
 #include "third_party/base/ptr_util.h"
 
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kReasonsAttributeData[] = {
     {XFA_Attribute::Id, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Use, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Type, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::Optional},
+     (void*)XFA_AttributeValue::Optional},
     {XFA_Attribute::Usehref, XFA_AttributeType::CData, nullptr},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"reasons";
+};
 
 }  // namespace
 
@@ -29,9 +27,8 @@
                 (XFA_XDPPACKET_Template | XFA_XDPPACKET_Form),
                 XFA_ObjectType::Node,
                 XFA_Element::Reasons,
-                nullptr,
-                kAttributeData,
-                kName,
-                pdfium::MakeUnique<CJX_Reasons>(this)) {}
+                {},
+                kReasonsAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_Reasons::~CXFA_Reasons() {}
+CXFA_Reasons::~CXFA_Reasons() = default;
diff --git a/xfa/fxfa/parser/cxfa_reasons.h b/xfa/fxfa/parser/cxfa_reasons.h
index 57e9e09..673a9b2 100644
--- a/xfa/fxfa/parser/cxfa_reasons.h
+++ b/xfa/fxfa/parser/cxfa_reasons.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Reasons : public CXFA_Node {
+class CXFA_Reasons final : public CXFA_Node {
  public:
   CXFA_Reasons(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Reasons() override;
diff --git a/xfa/fxfa/parser/cxfa_record.cpp b/xfa/fxfa/parser/cxfa_record.cpp
index 5c5ded1..5c10f05 100644
--- a/xfa/fxfa/parser/cxfa_record.cpp
+++ b/xfa/fxfa/parser/cxfa_record.cpp
@@ -6,14 +6,15 @@
 
 #include "xfa/fxfa/parser/cxfa_record.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kRecordAttributeData[] = {
     {XFA_Attribute::Desc, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Lock, XFA_AttributeType::Integer, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"record";
+};
 
 }  // namespace
 
@@ -23,8 +24,8 @@
                 XFA_XDPPACKET_Config,
                 XFA_ObjectType::NodeV,
                 XFA_Element::Record,
-                nullptr,
-                kAttributeData,
-                kName) {}
+                {},
+                kRecordAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_Record::~CXFA_Record() {}
+CXFA_Record::~CXFA_Record() = default;
diff --git a/xfa/fxfa/parser/cxfa_record.h b/xfa/fxfa/parser/cxfa_record.h
index bd2622d..de0d0c4 100644
--- a/xfa/fxfa/parser/cxfa_record.h
+++ b/xfa/fxfa/parser/cxfa_record.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Record : public CXFA_Node {
+class CXFA_Record final : public CXFA_Node {
  public:
   CXFA_Record(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Record() override;
diff --git a/xfa/fxfa/parser/cxfa_recordset.cpp b/xfa/fxfa/parser/cxfa_recordset.cpp
index a90c589..ad77695 100644
--- a/xfa/fxfa/parser/cxfa_recordset.cpp
+++ b/xfa/fxfa/parser/cxfa_recordset.cpp
@@ -6,30 +6,28 @@
 
 #include "xfa/fxfa/parser/cxfa_recordset.h"
 
-#include "fxjs/xfa/cjx_recordset.h"
+#include "fxjs/xfa/cjx_node.h"
 #include "third_party/base/ptr_util.h"
 
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kRecordSetAttributeData[] = {
     {XFA_Attribute::Id, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Name, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Max, XFA_AttributeType::Integer, (void*)0},
     {XFA_Attribute::Use, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::EofAction, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::MoveLast},
+     (void*)XFA_AttributeValue::MoveLast},
     {XFA_Attribute::CursorType, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::ForwardOnly},
+     (void*)XFA_AttributeValue::ForwardOnly},
     {XFA_Attribute::LockType, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::ReadOnly},
+     (void*)XFA_AttributeValue::ReadOnly},
     {XFA_Attribute::BofAction, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::MoveFirst},
+     (void*)XFA_AttributeValue::MoveFirst},
     {XFA_Attribute::Usehref, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::CursorLocation, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::Client},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"recordSet";
+     (void*)XFA_AttributeValue::Client},
+};
 
 }  // namespace
 
@@ -39,9 +37,8 @@
                 XFA_XDPPACKET_SourceSet,
                 XFA_ObjectType::Node,
                 XFA_Element::RecordSet,
-                nullptr,
-                kAttributeData,
-                kName,
-                pdfium::MakeUnique<CJX_RecordSet>(this)) {}
+                {},
+                kRecordSetAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_RecordSet::~CXFA_RecordSet() {}
+CXFA_RecordSet::~CXFA_RecordSet() = default;
diff --git a/xfa/fxfa/parser/cxfa_recordset.h b/xfa/fxfa/parser/cxfa_recordset.h
index c623516..a9895bd 100644
--- a/xfa/fxfa/parser/cxfa_recordset.h
+++ b/xfa/fxfa/parser/cxfa_recordset.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_RecordSet : public CXFA_Node {
+class CXFA_RecordSet final : public CXFA_Node {
  public:
   CXFA_RecordSet(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_RecordSet() override;
diff --git a/xfa/fxfa/parser/cxfa_rectangle.cpp b/xfa/fxfa/parser/cxfa_rectangle.cpp
index ac98df0..632141d 100644
--- a/xfa/fxfa/parser/cxfa_rectangle.cpp
+++ b/xfa/fxfa/parser/cxfa_rectangle.cpp
@@ -8,26 +8,27 @@
 
 #include <utility>
 
-#include "fxjs/xfa/cjx_rectangle.h"
+#include "core/fxge/render_defines.h"
+#include "fxjs/xfa/cjx_node.h"
 #include "third_party/base/ptr_util.h"
 #include "xfa/fxfa/parser/cxfa_corner.h"
 #include "xfa/fxfa/parser/cxfa_stroke.h"
 
 namespace {
 
-const CXFA_Node::PropertyData kPropertyData[] = {{XFA_Element::Edge, 4, 0},
-                                                 {XFA_Element::Corner, 4, 0},
-                                                 {XFA_Element::Fill, 1, 0},
-                                                 {XFA_Element::Unknown, 0, 0}};
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::PropertyData kRectanglePropertyData[] = {
+    {XFA_Element::Edge, 4, 0},
+    {XFA_Element::Corner, 4, 0},
+    {XFA_Element::Fill, 1, 0},
+};
+
+const CXFA_Node::AttributeData kRectangleAttributeData[] = {
     {XFA_Attribute::Id, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Use, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Usehref, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Hand, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::Even},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"rectangle";
+     (void*)XFA_AttributeValue::Even},
+};
 
 }  // namespace
 
@@ -37,19 +38,17 @@
                (XFA_XDPPACKET_Template | XFA_XDPPACKET_Form),
                XFA_ObjectType::Node,
                XFA_Element::Rectangle,
-               kPropertyData,
-               kAttributeData,
-               kName,
-               pdfium::MakeUnique<CJX_Rectangle>(this)) {}
+               kRectanglePropertyData,
+               kRectangleAttributeData,
+               pdfium::MakeUnique<CJX_Node>(this)) {}
 
 CXFA_Rectangle::CXFA_Rectangle(CXFA_Document* pDoc,
                                XFA_PacketType ePacket,
                                uint32_t validPackets,
                                XFA_ObjectType oType,
                                XFA_Element eType,
-                               const PropertyData* properties,
-                               const AttributeData* attributes,
-                               const WideStringView& elementName,
+                               pdfium::span<const PropertyData> properties,
+                               pdfium::span<const AttributeData> attributes,
                                std::unique_ptr<CJX_Object> js_node)
     : CXFA_Box(pDoc,
                ePacket,
@@ -58,7 +57,6 @@
                eType,
                properties,
                attributes,
-               elementName,
                std::move(js_node)) {}
 
 CXFA_Rectangle::~CXFA_Rectangle() {}
@@ -92,7 +90,7 @@
       stroke1 = strokes[0];
       if (stroke1->IsInverted())
         bSameStyles = false;
-      if (stroke1->GetJoinType() != XFA_AttributeEnum::Square)
+      if (stroke1->GetJoinType() != XFA_AttributeValue::Square)
         bSameStyles = false;
     }
   }
@@ -110,12 +108,12 @@
     float nx = 1.0f;
     float ny = 1.0f;
     CFX_PointF cp1, cp2;
-    auto* corner1 = static_cast<CXFA_Corner*>(strokes[i]);
-    auto* corner2 = static_cast<CXFA_Corner*>(strokes[(i + 2) % 8]);
+    CXFA_Stroke* corner1 = strokes[i];
+    CXFA_Stroke* corner2 = strokes[(i + 2) % 8];
     float fRadius1 = corner1->GetRadius();
     float fRadius2 = corner2->GetRadius();
     bool bInverted = corner1->IsInverted();
-    bool bRound = corner1->GetJoinType() == XFA_AttributeEnum::Round;
+    bool bRound = corner1->GetJoinType() == XFA_AttributeValue::Round;
     if (bRound) {
       sy = FX_PI / 2;
     }
@@ -214,36 +212,36 @@
   for (int32_t i = 1; i < 8; i += 2) {
     float fThickness = std::fmax(0.0, strokes[i]->GetThickness());
     float fHalf = fThickness / 2;
-    XFA_AttributeEnum iHand = GetHand();
+    XFA_AttributeValue iHand = GetHand();
     switch (i) {
       case 1:
-        if (iHand == XFA_AttributeEnum::Left) {
+        if (iHand == XFA_AttributeValue::Left) {
           rtWidget.top -= fHalf;
           rtWidget.height += fHalf;
-        } else if (iHand == XFA_AttributeEnum::Right) {
+        } else if (iHand == XFA_AttributeValue::Right) {
           rtWidget.top += fHalf;
           rtWidget.height -= fHalf;
         }
         break;
       case 3:
-        if (iHand == XFA_AttributeEnum::Left) {
+        if (iHand == XFA_AttributeValue::Left) {
           rtWidget.width += fHalf;
-        } else if (iHand == XFA_AttributeEnum::Right) {
+        } else if (iHand == XFA_AttributeValue::Right) {
           rtWidget.width -= fHalf;
         }
         break;
       case 5:
-        if (iHand == XFA_AttributeEnum::Left) {
+        if (iHand == XFA_AttributeValue::Left) {
           rtWidget.height += fHalf;
-        } else if (iHand == XFA_AttributeEnum::Right) {
+        } else if (iHand == XFA_AttributeValue::Right) {
           rtWidget.height -= fHalf;
         }
         break;
       case 7:
-        if (iHand == XFA_AttributeEnum::Left) {
+        if (iHand == XFA_AttributeValue::Left) {
           rtWidget.left -= fHalf;
           rtWidget.width += fHalf;
-        } else if (iHand == XFA_AttributeEnum::Right) {
+        } else if (iHand == XFA_AttributeValue::Right) {
           rtWidget.left += fHalf;
           rtWidget.width -= fHalf;
         }
@@ -259,23 +257,23 @@
                             const CFX_Matrix& matrix) {
   bool bVisible;
   float fThickness;
-  XFA_AttributeEnum i3DType;
+  XFA_AttributeValue i3DType;
   std::tie(i3DType, bVisible, fThickness) = Get3DStyle();
-  if (i3DType != XFA_AttributeEnum::Unknown) {
+  if (i3DType != XFA_AttributeValue::Unknown) {
     if (!bVisible || fThickness < 0.001f)
       return;
 
     switch (i3DType) {
-      case XFA_AttributeEnum::Lowered:
+      case XFA_AttributeValue::Lowered:
         StrokeLowered(pGS, rtWidget, fThickness, matrix);
         break;
-      case XFA_AttributeEnum::Raised:
+      case XFA_AttributeValue::Raised:
         StrokeRaised(pGS, rtWidget, fThickness, matrix);
         break;
-      case XFA_AttributeEnum::Etched:
+      case XFA_AttributeValue::Etched:
         StrokeEtched(pGS, rtWidget, fThickness, matrix);
         break;
-      case XFA_AttributeEnum::Embossed:
+      case XFA_AttributeValue::Embossed:
         StrokeEmbossed(pGS, rtWidget, fThickness, matrix);
         break;
       default:
@@ -312,7 +310,7 @@
       stroke1 = strokes[0];
       if (stroke1->IsInverted())
         bSameStyles = false;
-      if (stroke1->GetJoinType() != XFA_AttributeEnum::Square)
+      if (stroke1->GetJoinType() != XFA_AttributeValue::Square)
         bSameStyles = false;
     }
   }
@@ -445,17 +443,18 @@
                              int32_t nIndex,
                              bool bStart,
                              bool bCorner) {
-  ASSERT(nIndex >= 0 && nIndex < 8);
+  ASSERT(nIndex >= 0);
+  ASSERT(nIndex < 8);
 
   int32_t n = (nIndex & 1) ? nIndex - 1 : nIndex;
-  auto* corner1 = static_cast<CXFA_Corner*>(strokes[n]);
-  auto* corner2 = static_cast<CXFA_Corner*>(strokes[(n + 2) % 8]);
+  CXFA_Stroke* corner1 = strokes[n];
+  CXFA_Stroke* corner2 = strokes[(n + 2) % 8];
   float fRadius1 = bCorner ? corner1->GetRadius() : 0.0f;
   float fRadius2 = bCorner ? corner2->GetRadius() : 0.0f;
   bool bInverted = corner1->IsInverted();
   float offsetY = 0.0f;
   float offsetX = 0.0f;
-  bool bRound = corner1->GetJoinType() == XFA_AttributeEnum::Round;
+  bool bRound = corner1->GetJoinType() == XFA_AttributeValue::Round;
   float halfAfter = 0.0f;
   float halfBefore = 0.0f;
 
diff --git a/xfa/fxfa/parser/cxfa_rectangle.h b/xfa/fxfa/parser/cxfa_rectangle.h
index b117e66..6d17471 100644
--- a/xfa/fxfa/parser/cxfa_rectangle.h
+++ b/xfa/fxfa/parser/cxfa_rectangle.h
@@ -32,9 +32,8 @@
                  uint32_t validPackets,
                  XFA_ObjectType oType,
                  XFA_Element eType,
-                 const PropertyData* properties,
-                 const AttributeData* attributes,
-                 const WideStringView& elementName,
+                 pdfium::span<const PropertyData> properties,
+                 pdfium::span<const AttributeData> attributes,
                  std::unique_ptr<CJX_Object> js_node);
 
  private:
diff --git a/xfa/fxfa/parser/cxfa_ref.cpp b/xfa/fxfa/parser/cxfa_ref.cpp
index 0d7df44..fc4f59a 100644
--- a/xfa/fxfa/parser/cxfa_ref.cpp
+++ b/xfa/fxfa/parser/cxfa_ref.cpp
@@ -6,18 +6,16 @@
 
 #include "xfa/fxfa/parser/cxfa_ref.h"
 
-#include "fxjs/xfa/cjx_ref.h"
+#include "fxjs/xfa/cjx_textnode.h"
 #include "third_party/base/ptr_util.h"
 
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kRefAttributeData[] = {
     {XFA_Attribute::Id, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Use, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Usehref, XFA_AttributeType::CData, nullptr},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"ref";
+};
 
 }  // namespace
 
@@ -27,9 +25,8 @@
                 (XFA_XDPPACKET_Template | XFA_XDPPACKET_Form),
                 XFA_ObjectType::TextNode,
                 XFA_Element::Ref,
-                nullptr,
-                kAttributeData,
-                kName,
-                pdfium::MakeUnique<CJX_Ref>(this)) {}
+                {},
+                kRefAttributeData,
+                pdfium::MakeUnique<CJX_TextNode>(this)) {}
 
-CXFA_Ref::~CXFA_Ref() {}
+CXFA_Ref::~CXFA_Ref() = default;
diff --git a/xfa/fxfa/parser/cxfa_ref.h b/xfa/fxfa/parser/cxfa_ref.h
index 630510f..5ab8e00 100644
--- a/xfa/fxfa/parser/cxfa_ref.h
+++ b/xfa/fxfa/parser/cxfa_ref.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Ref : public CXFA_Node {
+class CXFA_Ref final : public CXFA_Node {
  public:
   CXFA_Ref(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Ref() override;
diff --git a/xfa/fxfa/parser/cxfa_relevant.cpp b/xfa/fxfa/parser/cxfa_relevant.cpp
index c67ff1e..f6b8a52 100644
--- a/xfa/fxfa/parser/cxfa_relevant.cpp
+++ b/xfa/fxfa/parser/cxfa_relevant.cpp
@@ -6,14 +6,15 @@
 
 #include "xfa/fxfa/parser/cxfa_relevant.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kRelevantAttributeData[] = {
     {XFA_Attribute::Desc, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Lock, XFA_AttributeType::Integer, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"relevant";
+};
 
 }  // namespace
 
@@ -23,8 +24,8 @@
                 XFA_XDPPACKET_Config,
                 XFA_ObjectType::NodeV,
                 XFA_Element::Relevant,
-                nullptr,
-                kAttributeData,
-                kName) {}
+                {},
+                kRelevantAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_Relevant::~CXFA_Relevant() {}
+CXFA_Relevant::~CXFA_Relevant() = default;
diff --git a/xfa/fxfa/parser/cxfa_relevant.h b/xfa/fxfa/parser/cxfa_relevant.h
index 2018c95..03283c3 100644
--- a/xfa/fxfa/parser/cxfa_relevant.h
+++ b/xfa/fxfa/parser/cxfa_relevant.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Relevant : public CXFA_Node {
+class CXFA_Relevant final : public CXFA_Node {
  public:
   CXFA_Relevant(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Relevant() override;
diff --git a/xfa/fxfa/parser/cxfa_rename.cpp b/xfa/fxfa/parser/cxfa_rename.cpp
index b0adbd7..f444554 100644
--- a/xfa/fxfa/parser/cxfa_rename.cpp
+++ b/xfa/fxfa/parser/cxfa_rename.cpp
@@ -6,14 +6,15 @@
 
 #include "xfa/fxfa/parser/cxfa_rename.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kRenameAttributeData[] = {
     {XFA_Attribute::Desc, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Lock, XFA_AttributeType::Integer, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"rename";
+};
 
 }  // namespace
 
@@ -23,8 +24,8 @@
                 XFA_XDPPACKET_Config,
                 XFA_ObjectType::NodeV,
                 XFA_Element::Rename,
-                nullptr,
-                kAttributeData,
-                kName) {}
+                {},
+                kRenameAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_Rename::~CXFA_Rename() {}
+CXFA_Rename::~CXFA_Rename() = default;
diff --git a/xfa/fxfa/parser/cxfa_rename.h b/xfa/fxfa/parser/cxfa_rename.h
index 665c852..f50d852 100644
--- a/xfa/fxfa/parser/cxfa_rename.h
+++ b/xfa/fxfa/parser/cxfa_rename.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Rename : public CXFA_Node {
+class CXFA_Rename final : public CXFA_Node {
  public:
   CXFA_Rename(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Rename() override;
diff --git a/xfa/fxfa/parser/cxfa_renderpolicy.cpp b/xfa/fxfa/parser/cxfa_renderpolicy.cpp
index a8abdb3..6497eec 100644
--- a/xfa/fxfa/parser/cxfa_renderpolicy.cpp
+++ b/xfa/fxfa/parser/cxfa_renderpolicy.cpp
@@ -6,14 +6,15 @@
 
 #include "xfa/fxfa/parser/cxfa_renderpolicy.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kRenderPolicyAttributeData[] = {
     {XFA_Attribute::Desc, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Lock, XFA_AttributeType::Integer, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"renderPolicy";
+};
 
 }  // namespace
 
@@ -23,8 +24,8 @@
                 XFA_XDPPACKET_Config,
                 XFA_ObjectType::ContentNode,
                 XFA_Element::RenderPolicy,
-                nullptr,
-                kAttributeData,
-                kName) {}
+                {},
+                kRenderPolicyAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_RenderPolicy::~CXFA_RenderPolicy() {}
+CXFA_RenderPolicy::~CXFA_RenderPolicy() = default;
diff --git a/xfa/fxfa/parser/cxfa_renderpolicy.h b/xfa/fxfa/parser/cxfa_renderpolicy.h
index 24ddf46..4947289 100644
--- a/xfa/fxfa/parser/cxfa_renderpolicy.h
+++ b/xfa/fxfa/parser/cxfa_renderpolicy.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_RenderPolicy : public CXFA_Node {
+class CXFA_RenderPolicy final : public CXFA_Node {
  public:
   CXFA_RenderPolicy(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_RenderPolicy() override;
diff --git a/xfa/fxfa/parser/cxfa_rootelement.cpp b/xfa/fxfa/parser/cxfa_rootelement.cpp
index a9b8631..46d5aea 100644
--- a/xfa/fxfa/parser/cxfa_rootelement.cpp
+++ b/xfa/fxfa/parser/cxfa_rootelement.cpp
@@ -6,19 +6,17 @@
 
 #include "xfa/fxfa/parser/cxfa_rootelement.h"
 
-#include "fxjs/xfa/cjx_rootelement.h"
+#include "fxjs/xfa/cjx_textnode.h"
 #include "third_party/base/ptr_util.h"
 
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kRootElementAttributeData[] = {
     {XFA_Attribute::Id, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Name, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Use, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Usehref, XFA_AttributeType::CData, nullptr},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"rootElement";
+};
 
 }  // namespace
 
@@ -28,9 +26,8 @@
                 XFA_XDPPACKET_ConnectionSet,
                 XFA_ObjectType::TextNode,
                 XFA_Element::RootElement,
-                nullptr,
-                kAttributeData,
-                kName,
-                pdfium::MakeUnique<CJX_RootElement>(this)) {}
+                {},
+                kRootElementAttributeData,
+                pdfium::MakeUnique<CJX_TextNode>(this)) {}
 
-CXFA_RootElement::~CXFA_RootElement() {}
+CXFA_RootElement::~CXFA_RootElement() = default;
diff --git a/xfa/fxfa/parser/cxfa_rootelement.h b/xfa/fxfa/parser/cxfa_rootelement.h
index a995e8c..4a9218e 100644
--- a/xfa/fxfa/parser/cxfa_rootelement.h
+++ b/xfa/fxfa/parser/cxfa_rootelement.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_RootElement : public CXFA_Node {
+class CXFA_RootElement final : public CXFA_Node {
  public:
   CXFA_RootElement(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_RootElement() override;
diff --git a/xfa/fxfa/parser/cxfa_runscripts.cpp b/xfa/fxfa/parser/cxfa_runscripts.cpp
index 06c0d52..dbc6acc 100644
--- a/xfa/fxfa/parser/cxfa_runscripts.cpp
+++ b/xfa/fxfa/parser/cxfa_runscripts.cpp
@@ -6,14 +6,15 @@
 
 #include "xfa/fxfa/parser/cxfa_runscripts.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kRunScriptsAttributeData[] = {
     {XFA_Attribute::Desc, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Lock, XFA_AttributeType::Integer, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"runScripts";
+};
 
 }  // namespace
 
@@ -23,8 +24,8 @@
                 XFA_XDPPACKET_Config,
                 XFA_ObjectType::ContentNode,
                 XFA_Element::RunScripts,
-                nullptr,
-                kAttributeData,
-                kName) {}
+                {},
+                kRunScriptsAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_RunScripts::~CXFA_RunScripts() {}
+CXFA_RunScripts::~CXFA_RunScripts() = default;
diff --git a/xfa/fxfa/parser/cxfa_runscripts.h b/xfa/fxfa/parser/cxfa_runscripts.h
index d2ecaa0..2f80b0d 100644
--- a/xfa/fxfa/parser/cxfa_runscripts.h
+++ b/xfa/fxfa/parser/cxfa_runscripts.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_RunScripts : public CXFA_Node {
+class CXFA_RunScripts final : public CXFA_Node {
  public:
   CXFA_RunScripts(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_RunScripts() override;
diff --git a/xfa/fxfa/parser/cxfa_script.cpp b/xfa/fxfa/parser/cxfa_script.cpp
index 1e4eb7e..884f97d 100644
--- a/xfa/fxfa/parser/cxfa_script.cpp
+++ b/xfa/fxfa/parser/cxfa_script.cpp
@@ -11,25 +11,24 @@
 
 namespace {
 
-const CXFA_Node::PropertyData kPropertyData[] = {
+const CXFA_Node::PropertyData kScriptPropertyData[] = {
     {XFA_Element::Exclude, 1, 0},
     {XFA_Element::CurrentPage, 1, 0},
     {XFA_Element::RunScripts, 1, 0},
-    {XFA_Element::Unknown, 0, 0}};
-const CXFA_Node::AttributeData kAttributeData[] = {
+};
+
+const CXFA_Node::AttributeData kScriptAttributeData[] = {
     {XFA_Attribute::Id, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Name, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Use, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::ContentType, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::RunAt, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::Client},
+     (void*)XFA_AttributeValue::Client},
     {XFA_Attribute::Binding, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Usehref, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Desc, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Lock, XFA_AttributeType::Integer, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"script";
+};
 
 }  // namespace
 
@@ -40,24 +39,25 @@
           (XFA_XDPPACKET_Config | XFA_XDPPACKET_Template | XFA_XDPPACKET_Form),
           XFA_ObjectType::ContentNode,
           XFA_Element::Script,
-          kPropertyData,
-          kAttributeData,
-          kName,
+          kScriptPropertyData,
+          kScriptAttributeData,
           pdfium::MakeUnique<CJX_Script>(this)) {}
 
-CXFA_Script::~CXFA_Script() {}
+CXFA_Script::~CXFA_Script() = default;
 
 CXFA_Script::Type CXFA_Script::GetContentType() {
   Optional<WideString> cData =
       JSObject()->TryCData(XFA_Attribute::ContentType, false);
-  if (!cData || *cData == L"application/x-formcalc")
+  if (!cData.has_value())
     return Type::Formcalc;
-  if (*cData == L"application/x-javascript")
+  if (cData.value().EqualsASCII("application/x-formcalc"))
+    return Type::Formcalc;
+  if (cData.value().EqualsASCII("application/x-javascript"))
     return Type::Javascript;
   return Type::Unknown;
 }
 
-XFA_AttributeEnum CXFA_Script::GetRunAt() {
+XFA_AttributeValue CXFA_Script::GetRunAt() {
   return JSObject()->GetEnum(XFA_Attribute::RunAt);
 }
 
diff --git a/xfa/fxfa/parser/cxfa_script.h b/xfa/fxfa/parser/cxfa_script.h
index 8ea7aac..f559284 100644
--- a/xfa/fxfa/parser/cxfa_script.h
+++ b/xfa/fxfa/parser/cxfa_script.h
@@ -10,7 +10,7 @@
 #include "core/fxcrt/widestring.h"
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Script : public CXFA_Node {
+class CXFA_Script final : public CXFA_Node {
  public:
   enum class Type {
     Formcalc = 0,
@@ -22,7 +22,7 @@
   ~CXFA_Script() override;
 
   Type GetContentType();
-  XFA_AttributeEnum GetRunAt();
+  XFA_AttributeValue GetRunAt();
   WideString GetExpression();
 };
 
diff --git a/xfa/fxfa/parser/cxfa_scriptmodel.cpp b/xfa/fxfa/parser/cxfa_scriptmodel.cpp
index 868dac5..8de4901 100644
--- a/xfa/fxfa/parser/cxfa_scriptmodel.cpp
+++ b/xfa/fxfa/parser/cxfa_scriptmodel.cpp
@@ -6,14 +6,15 @@
 
 #include "xfa/fxfa/parser/cxfa_scriptmodel.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kScriptModelAttributeData[] = {
     {XFA_Attribute::Desc, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Lock, XFA_AttributeType::Integer, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"scriptModel";
+};
 
 }  // namespace
 
@@ -23,8 +24,8 @@
                 XFA_XDPPACKET_Config,
                 XFA_ObjectType::ContentNode,
                 XFA_Element::ScriptModel,
-                nullptr,
-                kAttributeData,
-                kName) {}
+                {},
+                kScriptModelAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_ScriptModel::~CXFA_ScriptModel() {}
+CXFA_ScriptModel::~CXFA_ScriptModel() = default;
diff --git a/xfa/fxfa/parser/cxfa_scriptmodel.h b/xfa/fxfa/parser/cxfa_scriptmodel.h
index 40bc96e..a71073e 100644
--- a/xfa/fxfa/parser/cxfa_scriptmodel.h
+++ b/xfa/fxfa/parser/cxfa_scriptmodel.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_ScriptModel : public CXFA_Node {
+class CXFA_ScriptModel final : public CXFA_Node {
  public:
   CXFA_ScriptModel(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_ScriptModel() override;
diff --git a/xfa/fxfa/parser/cxfa_select.cpp b/xfa/fxfa/parser/cxfa_select.cpp
index 92eca07..04e51dc 100644
--- a/xfa/fxfa/parser/cxfa_select.cpp
+++ b/xfa/fxfa/parser/cxfa_select.cpp
@@ -6,19 +6,17 @@
 
 #include "xfa/fxfa/parser/cxfa_select.h"
 
-#include "fxjs/xfa/cjx_select.h"
+#include "fxjs/xfa/cjx_textnode.h"
 #include "third_party/base/ptr_util.h"
 
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kSelectAttributeData[] = {
     {XFA_Attribute::Id, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Name, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Use, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Usehref, XFA_AttributeType::CData, nullptr},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"select";
+};
 
 }  // namespace
 
@@ -28,9 +26,8 @@
                 XFA_XDPPACKET_SourceSet,
                 XFA_ObjectType::TextNode,
                 XFA_Element::Select,
-                nullptr,
-                kAttributeData,
-                kName,
-                pdfium::MakeUnique<CJX_Select>(this)) {}
+                {},
+                kSelectAttributeData,
+                pdfium::MakeUnique<CJX_TextNode>(this)) {}
 
-CXFA_Select::~CXFA_Select() {}
+CXFA_Select::~CXFA_Select() = default;
diff --git a/xfa/fxfa/parser/cxfa_select.h b/xfa/fxfa/parser/cxfa_select.h
index 76651e0..82fc0d2 100644
--- a/xfa/fxfa/parser/cxfa_select.h
+++ b/xfa/fxfa/parser/cxfa_select.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Select : public CXFA_Node {
+class CXFA_Select final : public CXFA_Node {
  public:
   CXFA_Select(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Select() override;
diff --git a/xfa/fxfa/parser/cxfa_setproperty.cpp b/xfa/fxfa/parser/cxfa_setproperty.cpp
index 85d631b..a748d58 100644
--- a/xfa/fxfa/parser/cxfa_setproperty.cpp
+++ b/xfa/fxfa/parser/cxfa_setproperty.cpp
@@ -6,18 +6,16 @@
 
 #include "xfa/fxfa/parser/cxfa_setproperty.h"
 
-#include "fxjs/xfa/cjx_setproperty.h"
+#include "fxjs/xfa/cjx_node.h"
 #include "third_party/base/ptr_util.h"
 
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kSetPropertyAttributeData[] = {
     {XFA_Attribute::Ref, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Connection, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Target, XFA_AttributeType::CData, nullptr},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"setProperty";
+};
 
 }  // namespace
 
@@ -27,9 +25,8 @@
                 (XFA_XDPPACKET_Template | XFA_XDPPACKET_Form),
                 XFA_ObjectType::Node,
                 XFA_Element::SetProperty,
-                nullptr,
-                kAttributeData,
-                kName,
-                pdfium::MakeUnique<CJX_SetProperty>(this)) {}
+                {},
+                kSetPropertyAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_SetProperty::~CXFA_SetProperty() {}
+CXFA_SetProperty::~CXFA_SetProperty() = default;
diff --git a/xfa/fxfa/parser/cxfa_setproperty.h b/xfa/fxfa/parser/cxfa_setproperty.h
index 3f8f430..aab588b 100644
--- a/xfa/fxfa/parser/cxfa_setproperty.h
+++ b/xfa/fxfa/parser/cxfa_setproperty.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_SetProperty : public CXFA_Node {
+class CXFA_SetProperty final : public CXFA_Node {
  public:
   CXFA_SetProperty(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_SetProperty() override;
diff --git a/xfa/fxfa/parser/cxfa_severity.cpp b/xfa/fxfa/parser/cxfa_severity.cpp
index 53a91e8..78a0872 100644
--- a/xfa/fxfa/parser/cxfa_severity.cpp
+++ b/xfa/fxfa/parser/cxfa_severity.cpp
@@ -6,14 +6,15 @@
 
 #include "xfa/fxfa/parser/cxfa_severity.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kSeverityAttributeData[] = {
     {XFA_Attribute::Desc, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Lock, XFA_AttributeType::Integer, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"severity";
+};
 
 }  // namespace
 
@@ -23,8 +24,8 @@
                 XFA_XDPPACKET_Config,
                 XFA_ObjectType::NodeV,
                 XFA_Element::Severity,
-                nullptr,
-                kAttributeData,
-                kName) {}
+                {},
+                kSeverityAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_Severity::~CXFA_Severity() {}
+CXFA_Severity::~CXFA_Severity() = default;
diff --git a/xfa/fxfa/parser/cxfa_severity.h b/xfa/fxfa/parser/cxfa_severity.h
index 7114455..b2283c9 100644
--- a/xfa/fxfa/parser/cxfa_severity.h
+++ b/xfa/fxfa/parser/cxfa_severity.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Severity : public CXFA_Node {
+class CXFA_Severity final : public CXFA_Node {
  public:
   CXFA_Severity(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Severity() override;
diff --git a/xfa/fxfa/parser/cxfa_sharptext.cpp b/xfa/fxfa/parser/cxfa_sharptext.cpp
index 5300dfc..515e881 100644
--- a/xfa/fxfa/parser/cxfa_sharptext.cpp
+++ b/xfa/fxfa/parser/cxfa_sharptext.cpp
@@ -6,13 +6,14 @@
 
 #include "xfa/fxfa/parser/cxfa_sharptext.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kSharptextAttributeData[] = {
     {XFA_Attribute::Value, XFA_AttributeType::CData, nullptr},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"#text";
+};
 
 }  // namespace
 
@@ -24,8 +25,8 @@
                  XFA_XDPPACKET_SourceSet | XFA_XDPPACKET_Form),
                 XFA_ObjectType::NodeV,
                 XFA_Element::Sharptext,
-                nullptr,
-                kAttributeData,
-                kName) {}
+                {},
+                kSharptextAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_Sharptext::~CXFA_Sharptext() {}
+CXFA_Sharptext::~CXFA_Sharptext() = default;
diff --git a/xfa/fxfa/parser/cxfa_sharptext.h b/xfa/fxfa/parser/cxfa_sharptext.h
index 89a050b..f2a41e8 100644
--- a/xfa/fxfa/parser/cxfa_sharptext.h
+++ b/xfa/fxfa/parser/cxfa_sharptext.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Sharptext : public CXFA_Node {
+class CXFA_Sharptext final : public CXFA_Node {
  public:
   CXFA_Sharptext(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Sharptext() override;
diff --git a/xfa/fxfa/parser/cxfa_sharpxhtml.cpp b/xfa/fxfa/parser/cxfa_sharpxhtml.cpp
index 51829b7..6758b48 100644
--- a/xfa/fxfa/parser/cxfa_sharpxhtml.cpp
+++ b/xfa/fxfa/parser/cxfa_sharpxhtml.cpp
@@ -6,13 +6,14 @@
 
 #include "xfa/fxfa/parser/cxfa_sharpxhtml.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kSharpxHTMLAttributeData[] = {
     {XFA_Attribute::Value, XFA_AttributeType::CData, nullptr},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"#xHTML";
+};
 
 }  // namespace
 
@@ -24,8 +25,8 @@
                  XFA_XDPPACKET_SourceSet | XFA_XDPPACKET_Form),
                 XFA_ObjectType::NodeV,
                 XFA_Element::SharpxHTML,
-                nullptr,
-                kAttributeData,
-                kName) {}
+                {},
+                kSharpxHTMLAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_SharpxHTML::~CXFA_SharpxHTML() {}
+CXFA_SharpxHTML::~CXFA_SharpxHTML() = default;
diff --git a/xfa/fxfa/parser/cxfa_sharpxhtml.h b/xfa/fxfa/parser/cxfa_sharpxhtml.h
index 3f6cf79..b73789d 100644
--- a/xfa/fxfa/parser/cxfa_sharpxhtml.h
+++ b/xfa/fxfa/parser/cxfa_sharpxhtml.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_SharpxHTML : public CXFA_Node {
+class CXFA_SharpxHTML final : public CXFA_Node {
  public:
   CXFA_SharpxHTML(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_SharpxHTML() override;
diff --git a/xfa/fxfa/parser/cxfa_sharpxml.cpp b/xfa/fxfa/parser/cxfa_sharpxml.cpp
index 6ce220e..0e066b1 100644
--- a/xfa/fxfa/parser/cxfa_sharpxml.cpp
+++ b/xfa/fxfa/parser/cxfa_sharpxml.cpp
@@ -6,13 +6,14 @@
 
 #include "xfa/fxfa/parser/cxfa_sharpxml.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kSharpxmlAttributeData[] = {
     {XFA_Attribute::Value, XFA_AttributeType::CData, nullptr},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"#xml";
+};
 
 }  // namespace
 
@@ -22,8 +23,8 @@
                 (XFA_XDPPACKET_Template | XFA_XDPPACKET_Form),
                 XFA_ObjectType::NodeV,
                 XFA_Element::Sharpxml,
-                nullptr,
-                kAttributeData,
-                kName) {}
+                {},
+                kSharpxmlAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_Sharpxml::~CXFA_Sharpxml() {}
+CXFA_Sharpxml::~CXFA_Sharpxml() = default;
diff --git a/xfa/fxfa/parser/cxfa_sharpxml.h b/xfa/fxfa/parser/cxfa_sharpxml.h
index a065857..b2e467a 100644
--- a/xfa/fxfa/parser/cxfa_sharpxml.h
+++ b/xfa/fxfa/parser/cxfa_sharpxml.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Sharpxml : public CXFA_Node {
+class CXFA_Sharpxml final : public CXFA_Node {
  public:
   CXFA_Sharpxml(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Sharpxml() override;
diff --git a/xfa/fxfa/parser/cxfa_signature.cpp b/xfa/fxfa/parser/cxfa_signature.cpp
index baee044..d059808 100644
--- a/xfa/fxfa/parser/cxfa_signature.cpp
+++ b/xfa/fxfa/parser/cxfa_signature.cpp
@@ -6,24 +6,24 @@
 
 #include "xfa/fxfa/parser/cxfa_signature.h"
 
-#include "fxjs/xfa/cjx_signature.h"
+#include "fxjs/xfa/cjx_node.h"
 #include "third_party/base/ptr_util.h"
 
 namespace {
 
-const CXFA_Node::PropertyData kPropertyData[] = {
+const CXFA_Node::PropertyData kSignaturePropertyData[] = {
     {XFA_Element::Margin, 1, 0}, {XFA_Element::Filter, 1, 0},
     {XFA_Element::Border, 1, 0}, {XFA_Element::Manifest, 1, 0},
-    {XFA_Element::Extras, 1, 0}, {XFA_Element::Unknown, 0, 0}};
-const CXFA_Node::AttributeData kAttributeData[] = {
+    {XFA_Element::Extras, 1, 0},
+};
+
+const CXFA_Node::AttributeData kSignatureAttributeData[] = {
     {XFA_Attribute::Id, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Use, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Type, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::PDF1_3},
+     (void*)XFA_AttributeValue::PDF1_3},
     {XFA_Attribute::Usehref, XFA_AttributeType::CData, nullptr},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"signature";
+};
 
 }  // namespace
 
@@ -33,9 +33,12 @@
                 (XFA_XDPPACKET_Template | XFA_XDPPACKET_Form),
                 XFA_ObjectType::Node,
                 XFA_Element::Signature,
-                kPropertyData,
-                kAttributeData,
-                kName,
-                pdfium::MakeUnique<CJX_Signature>(this)) {}
+                kSignaturePropertyData,
+                kSignatureAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_Signature::~CXFA_Signature() {}
+CXFA_Signature::~CXFA_Signature() = default;
+
+XFA_FFWidgetType CXFA_Signature::GetDefaultFFWidgetType() const {
+  return XFA_FFWidgetType::kSignature;
+}
diff --git a/xfa/fxfa/parser/cxfa_signature.h b/xfa/fxfa/parser/cxfa_signature.h
index f55ce5a..678e892 100644
--- a/xfa/fxfa/parser/cxfa_signature.h
+++ b/xfa/fxfa/parser/cxfa_signature.h
@@ -9,10 +9,12 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Signature : public CXFA_Node {
+class CXFA_Signature final : public CXFA_Node {
  public:
   CXFA_Signature(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Signature() override;
+
+  XFA_FFWidgetType GetDefaultFFWidgetType() const override;
 };
 
 #endif  // XFA_FXFA_PARSER_CXFA_SIGNATURE_H_
diff --git a/xfa/fxfa/parser/cxfa_signatureproperties.cpp b/xfa/fxfa/parser/cxfa_signatureproperties.cpp
index c710cb4..63b2635 100644
--- a/xfa/fxfa/parser/cxfa_signatureproperties.cpp
+++ b/xfa/fxfa/parser/cxfa_signatureproperties.cpp
@@ -6,17 +6,15 @@
 
 #include "xfa/fxfa/parser/cxfa_signatureproperties.h"
 
-#include "fxjs/xfa/cjx_signatureproperties.h"
+#include "fxjs/xfa/cjx_node.h"
 #include "third_party/base/ptr_util.h"
 
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kSignaturePropertiesAttributeData[] = {
     {XFA_Attribute::Use, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Usehref, XFA_AttributeType::CData, nullptr},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"signatureProperties";
+};
 
 }  // namespace
 
@@ -27,9 +25,8 @@
                 (XFA_XDPPACKET_Template | XFA_XDPPACKET_Form),
                 XFA_ObjectType::Node,
                 XFA_Element::SignatureProperties,
-                nullptr,
-                kAttributeData,
-                kName,
-                pdfium::MakeUnique<CJX_SignatureProperties>(this)) {}
+                {},
+                kSignaturePropertiesAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_SignatureProperties::~CXFA_SignatureProperties() {}
+CXFA_SignatureProperties::~CXFA_SignatureProperties() = default;
diff --git a/xfa/fxfa/parser/cxfa_signatureproperties.h b/xfa/fxfa/parser/cxfa_signatureproperties.h
index 800b780..a66346e 100644
--- a/xfa/fxfa/parser/cxfa_signatureproperties.h
+++ b/xfa/fxfa/parser/cxfa_signatureproperties.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_SignatureProperties : public CXFA_Node {
+class CXFA_SignatureProperties final : public CXFA_Node {
  public:
   CXFA_SignatureProperties(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_SignatureProperties() override;
diff --git a/xfa/fxfa/parser/cxfa_signdata.cpp b/xfa/fxfa/parser/cxfa_signdata.cpp
index 796ae5c..3710325 100644
--- a/xfa/fxfa/parser/cxfa_signdata.cpp
+++ b/xfa/fxfa/parser/cxfa_signdata.cpp
@@ -6,25 +6,25 @@
 
 #include "xfa/fxfa/parser/cxfa_signdata.h"
 
-#include "fxjs/xfa/cjx_signdata.h"
+#include "fxjs/xfa/cjx_node.h"
 #include "third_party/base/ptr_util.h"
 
 namespace {
 
-const CXFA_Node::PropertyData kPropertyData[] = {{XFA_Element::Filter, 1, 0},
-                                                 {XFA_Element::Manifest, 1, 0},
-                                                 {XFA_Element::Unknown, 0, 0}};
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::PropertyData kSignDataPropertyData[] = {
+    {XFA_Element::Filter, 1, 0},
+    {XFA_Element::Manifest, 1, 0},
+};
+
+const CXFA_Node::AttributeData kSignDataAttributeData[] = {
     {XFA_Attribute::Id, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Ref, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Use, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Operation, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::Sign},
+     (void*)XFA_AttributeValue::Sign},
     {XFA_Attribute::Usehref, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Target, XFA_AttributeType::CData, nullptr},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"signData";
+};
 
 }  // namespace
 
@@ -34,9 +34,8 @@
                 (XFA_XDPPACKET_Template | XFA_XDPPACKET_Form),
                 XFA_ObjectType::Node,
                 XFA_Element::SignData,
-                kPropertyData,
-                kAttributeData,
-                kName,
-                pdfium::MakeUnique<CJX_SignData>(this)) {}
+                kSignDataPropertyData,
+                kSignDataAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_SignData::~CXFA_SignData() {}
+CXFA_SignData::~CXFA_SignData() = default;
diff --git a/xfa/fxfa/parser/cxfa_signdata.h b/xfa/fxfa/parser/cxfa_signdata.h
index 3ad39f5..e28460d 100644
--- a/xfa/fxfa/parser/cxfa_signdata.h
+++ b/xfa/fxfa/parser/cxfa_signdata.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_SignData : public CXFA_Node {
+class CXFA_SignData final : public CXFA_Node {
  public:
   CXFA_SignData(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_SignData() override;
diff --git a/xfa/fxfa/parser/cxfa_signing.cpp b/xfa/fxfa/parser/cxfa_signing.cpp
index 251e294..939d4f5 100644
--- a/xfa/fxfa/parser/cxfa_signing.cpp
+++ b/xfa/fxfa/parser/cxfa_signing.cpp
@@ -6,20 +6,18 @@
 
 #include "xfa/fxfa/parser/cxfa_signing.h"
 
-#include "fxjs/xfa/cjx_signing.h"
+#include "fxjs/xfa/cjx_node.h"
 #include "third_party/base/ptr_util.h"
 
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kSigningAttributeData[] = {
     {XFA_Attribute::Id, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Use, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Type, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::Optional},
+     (void*)XFA_AttributeValue::Optional},
     {XFA_Attribute::Usehref, XFA_AttributeType::CData, nullptr},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"signing";
+};
 
 }  // namespace
 
@@ -29,9 +27,8 @@
                 (XFA_XDPPACKET_Template | XFA_XDPPACKET_Form),
                 XFA_ObjectType::Node,
                 XFA_Element::Signing,
-                nullptr,
-                kAttributeData,
-                kName,
-                pdfium::MakeUnique<CJX_Signing>(this)) {}
+                {},
+                kSigningAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_Signing::~CXFA_Signing() {}
+CXFA_Signing::~CXFA_Signing() = default;
diff --git a/xfa/fxfa/parser/cxfa_signing.h b/xfa/fxfa/parser/cxfa_signing.h
index 6df9a18..7c37403 100644
--- a/xfa/fxfa/parser/cxfa_signing.h
+++ b/xfa/fxfa/parser/cxfa_signing.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Signing : public CXFA_Node {
+class CXFA_Signing final : public CXFA_Node {
  public:
   CXFA_Signing(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Signing() override;
diff --git a/xfa/fxfa/parser/cxfa_silentprint.cpp b/xfa/fxfa/parser/cxfa_silentprint.cpp
index ca0cf9f..1a417aa 100644
--- a/xfa/fxfa/parser/cxfa_silentprint.cpp
+++ b/xfa/fxfa/parser/cxfa_silentprint.cpp
@@ -6,18 +6,20 @@
 
 #include "xfa/fxfa/parser/cxfa_silentprint.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::PropertyData kPropertyData[] = {
+const CXFA_Node::PropertyData kSilentPrintPropertyData[] = {
     {XFA_Element::AddSilentPrint, 1, 0},
     {XFA_Element::PrinterName, 1, 0},
-    {XFA_Element::Unknown, 0, 0}};
-const CXFA_Node::AttributeData kAttributeData[] = {
+};
+
+const CXFA_Node::AttributeData kSilentPrintAttributeData[] = {
     {XFA_Attribute::Desc, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Lock, XFA_AttributeType::Integer, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"silentPrint";
+};
 
 }  // namespace
 
@@ -27,8 +29,8 @@
                 XFA_XDPPACKET_Config,
                 XFA_ObjectType::Node,
                 XFA_Element::SilentPrint,
-                kPropertyData,
-                kAttributeData,
-                kName) {}
+                kSilentPrintPropertyData,
+                kSilentPrintAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_SilentPrint::~CXFA_SilentPrint() {}
+CXFA_SilentPrint::~CXFA_SilentPrint() = default;
diff --git a/xfa/fxfa/parser/cxfa_silentprint.h b/xfa/fxfa/parser/cxfa_silentprint.h
index 6ef5fcf..378084d 100644
--- a/xfa/fxfa/parser/cxfa_silentprint.h
+++ b/xfa/fxfa/parser/cxfa_silentprint.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_SilentPrint : public CXFA_Node {
+class CXFA_SilentPrint final : public CXFA_Node {
  public:
   CXFA_SilentPrint(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_SilentPrint() override;
diff --git a/xfa/fxfa/parser/cxfa_simple_parser.cpp b/xfa/fxfa/parser/cxfa_simple_parser.cpp
deleted file mode 100644
index 1864532..0000000
--- a/xfa/fxfa/parser/cxfa_simple_parser.cpp
+++ /dev/null
@@ -1,1264 +0,0 @@
-// Copyright 2016 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
-
-#include "xfa/fxfa/parser/cxfa_simple_parser.h"
-
-#include <utility>
-#include <vector>
-
-#include "core/fxcrt/cfx_checksumcontext.h"
-#include "core/fxcrt/cfx_seekablestreamproxy.h"
-#include "core/fxcrt/cfx_widetextbuf.h"
-#include "core/fxcrt/fx_codepage.h"
-#include "core/fxcrt/fx_extension.h"
-#include "core/fxcrt/xml/cfx_xmlchardata.h"
-#include "core/fxcrt/xml/cfx_xmldoc.h"
-#include "core/fxcrt/xml/cfx_xmlelement.h"
-#include "core/fxcrt/xml/cfx_xmlinstruction.h"
-#include "core/fxcrt/xml/cfx_xmlnode.h"
-#include "core/fxcrt/xml/cfx_xmlparser.h"
-#include "core/fxcrt/xml/cfx_xmltext.h"
-#include "fxjs/xfa/cjx_object.h"
-#include "third_party/base/logging.h"
-#include "third_party/base/ptr_util.h"
-#include "xfa/fxfa/fxfa.h"
-#include "xfa/fxfa/parser/cxfa_document.h"
-#include "xfa/fxfa/parser/cxfa_node.h"
-#include "xfa/fxfa/parser/cxfa_subform.h"
-#include "xfa/fxfa/parser/cxfa_template.h"
-#include "xfa/fxfa/parser/xfa_basic_data.h"
-#include "xfa/fxfa/parser/xfa_utils.h"
-
-namespace {
-
-struct PacketInfo {
-  uint32_t hash;
-  const wchar_t* name;
-  XFA_PacketType packet_type;
-  const wchar_t* uri;
-  uint32_t flags;
-};
-const PacketInfo PacketData[] = {
-    {0x0, nullptr, XFA_PacketType::User, nullptr,
-     XFA_XDPPACKET_FLAGS_NOMATCH | XFA_XDPPACKET_FLAGS_SUPPORTMANY},
-    {0x811929d, L"sourceSet", XFA_PacketType::SourceSet,
-     L"http://www.xfa.org/schema/xfa-source-set/",
-     XFA_XDPPACKET_FLAGS_NOMATCH | XFA_XDPPACKET_FLAGS_SUPPORTONE},
-    {0xb843dba, L"pdf", XFA_PacketType::Pdf, L"http://ns.adobe.com/xdp/pdf/",
-     XFA_XDPPACKET_FLAGS_COMPLETEMATCH | XFA_XDPPACKET_FLAGS_SUPPORTONE},
-    {0xc56afbf, L"xdc", XFA_PacketType::Xdc, L"http://www.xfa.org/schema/xdc/",
-     XFA_XDPPACKET_FLAGS_NOMATCH | XFA_XDPPACKET_FLAGS_SUPPORTONE},
-    {0xc56afcc, L"xdp", XFA_PacketType::Xdp, L"http://ns.adobe.com/xdp/",
-     XFA_XDPPACKET_FLAGS_COMPLETEMATCH | XFA_XDPPACKET_FLAGS_SUPPORTONE},
-    {0x132a8fbc, L"xmpmeta", XFA_PacketType::Xmpmeta,
-     L"http://ns.adobe.com/xmpmeta/",
-     XFA_XDPPACKET_FLAGS_NOMATCH | XFA_XDPPACKET_FLAGS_SUPPORTMANY},
-    {0x48d004a8, L"xfdf", XFA_PacketType::Xfdf, L"http://ns.adobe.com/xfdf/",
-     XFA_XDPPACKET_FLAGS_NOMATCH | XFA_XDPPACKET_FLAGS_SUPPORTONE},
-    {0x4e1e39b6, L"config", XFA_PacketType::Config,
-     L"http://www.xfa.org/schema/xci/",
-     XFA_XDPPACKET_FLAGS_NOMATCH | XFA_XDPPACKET_FLAGS_SUPPORTONE},
-    {0x5473b6dc, L"localeSet", XFA_PacketType::LocaleSet,
-     L"http://www.xfa.org/schema/xfa-locale-set/",
-     XFA_XDPPACKET_FLAGS_NOMATCH | XFA_XDPPACKET_FLAGS_SUPPORTONE},
-    {0x6038580a, L"stylesheet", XFA_PacketType::Stylesheet,
-     L"http://www.w3.org/1999/XSL/Transform",
-     XFA_XDPPACKET_FLAGS_NOMATCH | XFA_XDPPACKET_FLAGS_SUPPORTMANY},
-    {0x803550fc, L"template", XFA_PacketType::Template,
-     L"http://www.xfa.org/schema/xfa-template/",
-     XFA_XDPPACKET_FLAGS_NOMATCH | XFA_XDPPACKET_FLAGS_SUPPORTONE},
-    {0x8b036f32, L"signature", XFA_PacketType::Signature,
-     L"http://www.w3.org/2000/09/xmldsig#",
-     XFA_XDPPACKET_FLAGS_NOMATCH | XFA_XDPPACKET_FLAGS_SUPPORTONE},
-    {0x99b95079, L"datasets", XFA_PacketType::Datasets,
-     L"http://www.xfa.org/schema/xfa-data/",
-     XFA_XDPPACKET_FLAGS_PREFIXMATCH | XFA_XDPPACKET_FLAGS_SUPPORTONE},
-    {0xcd309ff4, L"form", XFA_PacketType::Form,
-     L"http://www.xfa.org/schema/xfa-form/",
-     XFA_XDPPACKET_FLAGS_NOMATCH | XFA_XDPPACKET_FLAGS_SUPPORTONE},
-    {0xe14c801c, L"connectionSet", XFA_PacketType::ConnectionSet,
-     L"http://www.xfa.org/schema/xfa-connection-set/",
-     XFA_XDPPACKET_FLAGS_NOMATCH | XFA_XDPPACKET_FLAGS_SUPPORTONE},
-};
-
-const PacketInfo* GetPacketByIndex(XFA_PacketType ePacket) {
-  return PacketData + static_cast<uint8_t>(ePacket);
-}
-
-const PacketInfo* GetPacketByName(const WideStringView& wsName) {
-  if (wsName.IsEmpty())
-    return nullptr;
-
-  uint32_t hash = FX_HashCode_GetW(wsName, false);
-  auto* elem = std::lower_bound(
-      std::begin(PacketData), std::end(PacketData), hash,
-      [](const PacketInfo& a, uint32_t hash) { return a.hash < hash; });
-  if (elem != std::end(PacketData) && elem->hash == hash)
-    return elem;
-  return nullptr;
-}
-
-CFX_XMLNode* GetDocumentNode(CFX_XMLDoc* pXMLDoc,
-                             bool bVerifyWellFormness = false) {
-  if (!pXMLDoc)
-    return nullptr;
-
-  for (CFX_XMLNode* pXMLNode =
-           pXMLDoc->GetRoot()->GetNodeItem(CFX_XMLNode::FirstChild);
-       pXMLNode; pXMLNode = pXMLNode->GetNodeItem(CFX_XMLNode::NextSibling)) {
-    if (pXMLNode->GetType() != FX_XMLNODE_Element)
-      continue;
-
-    if (!bVerifyWellFormness)
-      return pXMLNode;
-
-    for (CFX_XMLNode* pNextNode =
-             pXMLNode->GetNodeItem(CFX_XMLNode::NextSibling);
-         pNextNode;
-         pNextNode = pNextNode->GetNodeItem(CFX_XMLNode::NextSibling)) {
-      if (pNextNode->GetType() == FX_XMLNODE_Element)
-        return nullptr;
-    }
-    return pXMLNode;
-  }
-  return nullptr;
-}
-
-WideString GetElementTagNamespaceURI(CFX_XMLElement* pElement) {
-  WideString wsNodeStr = pElement->GetNamespacePrefix();
-  WideString wsNamespaceURI;
-  if (!XFA_FDEExtension_ResolveNamespaceQualifier(pElement, wsNodeStr,
-                                                  &wsNamespaceURI)) {
-    return WideString();
-  }
-  return wsNamespaceURI;
-}
-
-bool MatchNodeName(CFX_XMLNode* pNode,
-                   const WideStringView& wsLocalTagName,
-                   const WideStringView& wsNamespaceURIPrefix,
-                   uint32_t eMatchFlags = XFA_XDPPACKET_FLAGS_NOMATCH) {
-  if (!pNode || pNode->GetType() != FX_XMLNODE_Element)
-    return false;
-
-  CFX_XMLElement* pElement = reinterpret_cast<CFX_XMLElement*>(pNode);
-  WideString wsNodeStr = pElement->GetLocalTagName();
-  if (wsNodeStr != wsLocalTagName)
-    return false;
-
-  wsNodeStr = GetElementTagNamespaceURI(pElement);
-  if (eMatchFlags & XFA_XDPPACKET_FLAGS_NOMATCH)
-    return true;
-  if (eMatchFlags & XFA_XDPPACKET_FLAGS_PREFIXMATCH) {
-    return wsNodeStr.Left(wsNamespaceURIPrefix.GetLength()) ==
-           wsNamespaceURIPrefix;
-  }
-
-  return wsNodeStr == wsNamespaceURIPrefix;
-}
-
-bool GetAttributeLocalName(const WideStringView& wsAttributeName,
-                           WideString& wsLocalAttrName) {
-  WideString wsAttrName(wsAttributeName);
-  auto pos = wsAttrName.Find(L':', 0);
-  if (!pos.has_value()) {
-    wsLocalAttrName = wsAttrName;
-    return false;
-  }
-  wsLocalAttrName = wsAttrName.Right(wsAttrName.GetLength() - pos.value() - 1);
-  return true;
-}
-
-bool ResolveAttribute(CFX_XMLElement* pElement,
-                      const WideString& wsAttrName,
-                      WideString& wsLocalAttrName,
-                      WideString& wsNamespaceURI) {
-  WideString wsNSPrefix;
-  if (GetAttributeLocalName(wsAttrName.AsStringView(), wsLocalAttrName)) {
-    wsNSPrefix = wsAttrName.Left(wsAttrName.GetLength() -
-                                 wsLocalAttrName.GetLength() - 1);
-  }
-  if (wsLocalAttrName == L"xmlns" || wsNSPrefix == L"xmlns" ||
-      wsNSPrefix == L"xml") {
-    return false;
-  }
-  if (!XFA_FDEExtension_ResolveNamespaceQualifier(pElement, wsNSPrefix,
-                                                  &wsNamespaceURI)) {
-    wsNamespaceURI.clear();
-    return false;
-  }
-  return true;
-}
-
-bool FindAttributeWithNS(CFX_XMLElement* pElement,
-                         const WideStringView& wsLocalAttributeName,
-                         const WideStringView& wsNamespaceURIPrefix,
-                         WideString& wsValue,
-                         bool bMatchNSAsPrefix = false) {
-  if (!pElement)
-    return false;
-
-  WideString wsAttrNS;
-  for (auto it : pElement->GetAttributes()) {
-    auto pos = it.first.Find(L':', 0);
-    WideString wsNSPrefix;
-    if (!pos.has_value()) {
-      if (wsLocalAttributeName != it.first)
-        continue;
-    } else {
-      if (wsLocalAttributeName !=
-          it.first.Right(it.first.GetLength() - pos.value() - 1)) {
-        continue;
-      }
-      wsNSPrefix = it.first.Left(pos.value());
-    }
-
-    if (!XFA_FDEExtension_ResolveNamespaceQualifier(pElement, wsNSPrefix,
-                                                    &wsAttrNS)) {
-      continue;
-    }
-    if (bMatchNSAsPrefix) {
-      if (wsAttrNS.Left(wsNamespaceURIPrefix.GetLength()) !=
-          wsNamespaceURIPrefix) {
-        continue;
-      }
-    } else {
-      if (wsAttrNS != wsNamespaceURIPrefix)
-        continue;
-    }
-    wsValue = it.second;
-    return true;
-  }
-  return false;
-}
-
-CFX_XMLNode* GetDataSetsFromXDP(CFX_XMLNode* pXMLDocumentNode) {
-  const PacketInfo* datasets_packet =
-      GetPacketByIndex(XFA_PacketType::Datasets);
-  if (MatchNodeName(pXMLDocumentNode, datasets_packet->name,
-                    datasets_packet->uri, datasets_packet->flags)) {
-    return pXMLDocumentNode;
-  }
-
-  const PacketInfo* packet = GetPacketByIndex(XFA_PacketType::Xdp);
-  if (!MatchNodeName(pXMLDocumentNode, packet->name, packet->uri,
-                     packet->flags)) {
-    return nullptr;
-  }
-
-  for (CFX_XMLNode* pDatasetsNode =
-           pXMLDocumentNode->GetNodeItem(CFX_XMLNode::FirstChild);
-       pDatasetsNode;
-       pDatasetsNode = pDatasetsNode->GetNodeItem(CFX_XMLNode::NextSibling)) {
-    if (MatchNodeName(pDatasetsNode, datasets_packet->name,
-                      datasets_packet->uri, datasets_packet->flags)) {
-      return pDatasetsNode;
-    }
-  }
-  return nullptr;
-}
-
-bool IsStringAllWhitespace(WideString wsText) {
-  wsText.TrimRight(L"\x20\x9\xD\xA");
-  return wsText.IsEmpty();
-}
-
-void ConvertXMLToPlainText(CFX_XMLElement* pRootXMLNode, WideString& wsOutput) {
-  for (CFX_XMLNode* pXMLChild =
-           pRootXMLNode->GetNodeItem(CFX_XMLNode::FirstChild);
-       pXMLChild;
-       pXMLChild = pXMLChild->GetNodeItem(CFX_XMLNode::NextSibling)) {
-    switch (pXMLChild->GetType()) {
-      case FX_XMLNODE_Element: {
-        WideString wsTextData =
-            static_cast<CFX_XMLElement*>(pXMLChild)->GetTextData();
-        wsTextData += L"\n";
-        wsOutput += wsTextData;
-        break;
-      }
-      case FX_XMLNODE_Text:
-      case FX_XMLNODE_CharData: {
-        WideString wsText = static_cast<CFX_XMLText*>(pXMLChild)->GetText();
-        if (IsStringAllWhitespace(wsText))
-          continue;
-
-        wsOutput = wsText;
-        break;
-      }
-      default:
-        NOTREACHED();
-        break;
-    }
-  }
-}
-
-WideString GetPlainTextFromRichText(CFX_XMLNode* pXMLNode) {
-  if (!pXMLNode)
-    return L"";
-
-  WideString wsPlainText;
-  switch (pXMLNode->GetType()) {
-    case FX_XMLNODE_Element: {
-      CFX_XMLElement* pXMLElement = static_cast<CFX_XMLElement*>(pXMLNode);
-      WideString wsTag = pXMLElement->GetLocalTagName();
-      uint32_t uTag = FX_HashCode_GetW(wsTag.AsStringView(), true);
-      if (uTag == 0x0001f714) {
-        wsPlainText += L"\n";
-      } else if (uTag == 0x00000070) {
-        if (!wsPlainText.IsEmpty()) {
-          wsPlainText += L"\n";
-        }
-      } else if (uTag == 0xa48ac63) {
-        if (!wsPlainText.IsEmpty() &&
-            wsPlainText[wsPlainText.GetLength() - 1] != '\n') {
-          wsPlainText += L"\n";
-        }
-      }
-      break;
-    }
-    case FX_XMLNODE_Text:
-    case FX_XMLNODE_CharData: {
-      WideString wsContent = static_cast<CFX_XMLText*>(pXMLNode)->GetText();
-      wsPlainText += wsContent;
-      break;
-    }
-    default:
-      break;
-  }
-  for (CFX_XMLNode* pChildXML = pXMLNode->GetNodeItem(CFX_XMLNode::FirstChild);
-       pChildXML;
-       pChildXML = pChildXML->GetNodeItem(CFX_XMLNode::NextSibling)) {
-    wsPlainText += GetPlainTextFromRichText(pChildXML);
-  }
-
-  return wsPlainText;
-}
-
-}  // namespace
-
-bool XFA_RecognizeRichText(CFX_XMLElement* pRichTextXMLNode) {
-  return pRichTextXMLNode && GetElementTagNamespaceURI(pRichTextXMLNode) ==
-                                 L"http://www.w3.org/1999/xhtml";
-}
-
-CXFA_SimpleParser::CXFA_SimpleParser() : m_bDocumentParser(true) {}
-
-CXFA_SimpleParser::CXFA_SimpleParser(CXFA_Document* pFactory)
-    : m_pFactory(pFactory), m_bDocumentParser(false) {}
-
-CXFA_SimpleParser::~CXFA_SimpleParser() {}
-
-void CXFA_SimpleParser::SetFactory(CXFA_Document* pFactory) {
-  ASSERT(m_bDocumentParser);
-  m_pFactory = pFactory;
-}
-
-int32_t CXFA_SimpleParser::StartParse(
-    const RetainPtr<IFX_SeekableStream>& pStream,
-    XFA_PacketType ePacketID) {
-  CloseParser();
-  m_pFileRead = pStream;
-  m_pStream = pdfium::MakeRetain<CFX_SeekableStreamProxy>(pStream, false);
-  uint16_t wCodePage = m_pStream->GetCodePage();
-  if (wCodePage != FX_CODEPAGE_UTF16LE && wCodePage != FX_CODEPAGE_UTF16BE &&
-      wCodePage != FX_CODEPAGE_UTF8) {
-    m_pStream->SetCodePage(FX_CODEPAGE_UTF8);
-  }
-  m_pXMLDoc = pdfium::MakeUnique<CFX_XMLDoc>();
-  auto pNewParser =
-      pdfium::MakeUnique<CFX_XMLParser>(m_pXMLDoc->GetRoot(), m_pStream);
-  m_pXMLParser = pNewParser.get();
-  if (!m_pXMLDoc->LoadXML(std::move(pNewParser)))
-    return XFA_PARSESTATUS_StatusErr;
-
-  m_bParseStarted = true;
-  m_ePacketID = ePacketID;
-  return XFA_PARSESTATUS_Ready;
-}
-
-int32_t CXFA_SimpleParser::DoParse() {
-  if (!m_pXMLDoc || !m_bParseStarted)
-    return XFA_PARSESTATUS_StatusErr;
-
-  int32_t iRet = m_pXMLDoc->DoLoad();
-  if (iRet < 0)
-    return XFA_PARSESTATUS_SyntaxErr;
-  if (iRet < 100)
-    return iRet / 2;
-
-  m_pRootNode = ParseAsXDPPacket(GetDocumentNode(m_pXMLDoc.get()), m_ePacketID);
-  m_pXMLParser.Release();
-  m_pXMLDoc->CloseXML();
-  m_pStream.Reset();
-
-  if (!m_pRootNode)
-    return XFA_PARSESTATUS_StatusErr;
-
-  return XFA_PARSESTATUS_Done;
-}
-
-CFX_XMLNode* CXFA_SimpleParser::ParseXMLData(const ByteString& wsXML) {
-  CloseParser();
-  m_pXMLDoc = pdfium::MakeUnique<CFX_XMLDoc>();
-
-  auto pStream = pdfium::MakeRetain<CFX_SeekableStreamProxy>(
-      const_cast<uint8_t*>(wsXML.raw_str()), wsXML.GetLength());
-  auto pParser =
-      pdfium::MakeUnique<CFX_XMLParser>(m_pXMLDoc->GetRoot(), pStream);
-  pParser->m_dwCheckStatus = 0x03;
-  if (!m_pXMLDoc->LoadXML(std::move(pParser)))
-    return nullptr;
-
-  int32_t iRet = m_pXMLDoc->DoLoad();
-  if (iRet < 0 || iRet >= 100)
-    m_pXMLDoc->CloseXML();
-  return iRet < 100 ? nullptr : GetDocumentNode(m_pXMLDoc.get());
-}
-
-void CXFA_SimpleParser::ConstructXFANode(CXFA_Node* pXFANode,
-                                         CFX_XMLNode* pXMLNode) {
-  XFA_PacketType ePacketID = pXFANode->GetPacketType();
-  if (ePacketID == XFA_PacketType::Datasets) {
-    if (pXFANode->GetElementType() == XFA_Element::DataValue) {
-      for (CFX_XMLNode* pXMLChild =
-               pXMLNode->GetNodeItem(CFX_XMLNode::FirstChild);
-           pXMLChild;
-           pXMLChild = pXMLChild->GetNodeItem(CFX_XMLNode::NextSibling)) {
-        FX_XMLNODETYPE eNodeType = pXMLChild->GetType();
-        if (eNodeType == FX_XMLNODE_Instruction)
-          continue;
-
-        if (eNodeType == FX_XMLNODE_Element) {
-          CXFA_Node* pXFAChild = m_pFactory->CreateNode(
-              XFA_PacketType::Datasets, XFA_Element::DataValue);
-          if (!pXFAChild)
-            return;
-
-          CFX_XMLElement* child = static_cast<CFX_XMLElement*>(pXMLChild);
-          WideString wsNodeStr = child->GetLocalTagName();
-          pXFAChild->JSObject()->SetCData(XFA_Attribute::Name, wsNodeStr, false,
-                                          false);
-          WideString wsChildValue = GetPlainTextFromRichText(child);
-          if (!wsChildValue.IsEmpty())
-            pXFAChild->JSObject()->SetCData(XFA_Attribute::Value, wsChildValue,
-                                            false, false);
-
-          pXFANode->InsertChild(pXFAChild, nullptr);
-          pXFAChild->SetXMLMappingNode(pXMLChild);
-          pXFAChild->SetFlag(XFA_NodeFlag_Initialized, false);
-          break;
-        }
-      }
-      m_pRootNode = pXFANode;
-    } else {
-      m_pRootNode = DataLoader(pXFANode, pXMLNode, true);
-    }
-  } else if (pXFANode->IsContentNode()) {
-    ParseContentNode(pXFANode, pXMLNode, ePacketID);
-    m_pRootNode = pXFANode;
-  } else {
-    m_pRootNode = NormalLoader(pXFANode, pXMLNode, ePacketID, true);
-  }
-}
-
-CXFA_Node* CXFA_SimpleParser::GetRootNode() const {
-  return m_pRootNode;
-}
-
-CFX_XMLDoc* CXFA_SimpleParser::GetXMLDoc() const {
-  return m_pXMLDoc.get();
-}
-
-CXFA_Node* CXFA_SimpleParser::ParseAsXDPPacket(CFX_XMLNode* pXMLDocumentNode,
-                                               XFA_PacketType ePacketID) {
-  switch (ePacketID) {
-    case XFA_PacketType::Xdp:
-      return ParseAsXDPPacket_XDP(pXMLDocumentNode);
-    case XFA_PacketType::Config:
-      return ParseAsXDPPacket_Config(pXMLDocumentNode);
-    case XFA_PacketType::Template:
-      return ParseAsXDPPacket_Template(pXMLDocumentNode);
-    case XFA_PacketType::Form:
-      return ParseAsXDPPacket_Form(pXMLDocumentNode);
-    case XFA_PacketType::Datasets:
-      return ParseAsXDPPacket_Data(pXMLDocumentNode);
-    case XFA_PacketType::Xdc:
-      return ParseAsXDPPacket_Xdc(pXMLDocumentNode);
-    case XFA_PacketType::LocaleSet:
-      return ParseAsXDPPacket_LocaleConnectionSourceSet(
-          pXMLDocumentNode, XFA_PacketType::LocaleSet, XFA_Element::LocaleSet);
-    case XFA_PacketType::ConnectionSet:
-      return ParseAsXDPPacket_LocaleConnectionSourceSet(
-          pXMLDocumentNode, XFA_PacketType::ConnectionSet,
-          XFA_Element::ConnectionSet);
-    case XFA_PacketType::SourceSet:
-      return ParseAsXDPPacket_LocaleConnectionSourceSet(
-          pXMLDocumentNode, XFA_PacketType::SourceSet, XFA_Element::SourceSet);
-    default:
-      return ParseAsXDPPacket_User(pXMLDocumentNode);
-  }
-}
-
-CXFA_Node* CXFA_SimpleParser::ParseAsXDPPacket_XDP(
-    CFX_XMLNode* pXMLDocumentNode) {
-  const PacketInfo* packet = GetPacketByIndex(XFA_PacketType::Xdp);
-  if (!MatchNodeName(pXMLDocumentNode, packet->name, packet->uri,
-                     packet->flags)) {
-    return nullptr;
-  }
-
-  CXFA_Node* pXFARootNode =
-      m_pFactory->CreateNode(XFA_PacketType::Xdp, XFA_Element::Xfa);
-  if (!pXFARootNode)
-    return nullptr;
-
-  m_pRootNode = pXFARootNode;
-  pXFARootNode->JSObject()->SetCData(XFA_Attribute::Name, L"xfa", false, false);
-
-  CFX_XMLElement* pElement = static_cast<CFX_XMLElement*>(pXMLDocumentNode);
-  for (auto it : pElement->GetAttributes()) {
-    if (it.first == L"uuid")
-      pXFARootNode->JSObject()->SetCData(XFA_Attribute::Uuid, it.second, false,
-                                         false);
-    else if (it.first == L"timeStamp")
-      pXFARootNode->JSObject()->SetCData(XFA_Attribute::TimeStamp, it.second,
-                                         false, false);
-  }
-
-  CFX_XMLNode* pXMLConfigDOMRoot = nullptr;
-  CXFA_Node* pXFAConfigDOMRoot = nullptr;
-  for (CFX_XMLNode* pChildItem =
-           pXMLDocumentNode->GetNodeItem(CFX_XMLNode::FirstChild);
-       pChildItem;
-       pChildItem = pChildItem->GetNodeItem(CFX_XMLNode::NextSibling)) {
-    const PacketInfo* pPacketInfo = GetPacketByIndex(XFA_PacketType::Config);
-    if (!MatchNodeName(pChildItem, pPacketInfo->name, pPacketInfo->uri,
-                       pPacketInfo->flags)) {
-      continue;
-    }
-    if (pXFARootNode->GetFirstChildByName(pPacketInfo->hash))
-      return nullptr;
-
-    pXMLConfigDOMRoot = pChildItem;
-    pXFAConfigDOMRoot = ParseAsXDPPacket_Config(pXMLConfigDOMRoot);
-    if (pXFAConfigDOMRoot)
-      pXFARootNode->InsertChild(pXFAConfigDOMRoot, nullptr);
-  }
-
-  CFX_XMLNode* pXMLDatasetsDOMRoot = nullptr;
-  CFX_XMLNode* pXMLFormDOMRoot = nullptr;
-  CFX_XMLNode* pXMLTemplateDOMRoot = nullptr;
-  for (CFX_XMLNode* pChildItem =
-           pXMLDocumentNode->GetNodeItem(CFX_XMLNode::FirstChild);
-       pChildItem;
-       pChildItem = pChildItem->GetNodeItem(CFX_XMLNode::NextSibling)) {
-    if (!pChildItem || pChildItem->GetType() != FX_XMLNODE_Element)
-      continue;
-    if (pChildItem == pXMLConfigDOMRoot)
-      continue;
-
-    CFX_XMLElement* pElement = reinterpret_cast<CFX_XMLElement*>(pChildItem);
-    WideString wsPacketName = pElement->GetLocalTagName();
-    const PacketInfo* pPacketInfo =
-        GetPacketByName(wsPacketName.AsStringView());
-    if (pPacketInfo && pPacketInfo->uri) {
-      if (!MatchNodeName(pElement, pPacketInfo->name, pPacketInfo->uri,
-                         pPacketInfo->flags)) {
-        pPacketInfo = nullptr;
-      }
-    }
-    XFA_PacketType ePacket =
-        pPacketInfo ? pPacketInfo->packet_type : XFA_PacketType::User;
-    if (ePacket == XFA_PacketType::Xdp)
-      continue;
-    if (ePacket == XFA_PacketType::Datasets) {
-      if (pXMLDatasetsDOMRoot)
-        return nullptr;
-
-      pXMLDatasetsDOMRoot = pElement;
-    } else if (ePacket == XFA_PacketType::Form) {
-      if (pXMLFormDOMRoot)
-        return nullptr;
-
-      pXMLFormDOMRoot = pElement;
-    } else if (ePacket == XFA_PacketType::Template) {
-      // Found a duplicate template packet.
-      if (pXMLTemplateDOMRoot)
-        return nullptr;
-
-      CXFA_Node* pPacketNode = ParseAsXDPPacket(pElement, ePacket);
-      if (pPacketNode) {
-        pXMLTemplateDOMRoot = pElement;
-        pXFARootNode->InsertChild(pPacketNode, nullptr);
-      }
-    } else {
-      CXFA_Node* pPacketNode = ParseAsXDPPacket(pElement, ePacket);
-      if (pPacketNode) {
-        if (pPacketInfo &&
-            (pPacketInfo->flags & XFA_XDPPACKET_FLAGS_SUPPORTONE) &&
-            pXFARootNode->GetFirstChildByName(pPacketInfo->hash)) {
-          return nullptr;
-        }
-        pXFARootNode->InsertChild(pPacketNode, nullptr);
-      }
-    }
-  }
-
-  // No template is found.
-  if (!pXMLTemplateDOMRoot)
-    return nullptr;
-
-  if (pXMLDatasetsDOMRoot) {
-    CXFA_Node* pPacketNode =
-        ParseAsXDPPacket(pXMLDatasetsDOMRoot, XFA_PacketType::Datasets);
-    if (pPacketNode)
-      pXFARootNode->InsertChild(pPacketNode, nullptr);
-  }
-  if (pXMLFormDOMRoot) {
-    CXFA_Node* pPacketNode =
-        ParseAsXDPPacket(pXMLFormDOMRoot, XFA_PacketType::Form);
-    if (pPacketNode)
-      pXFARootNode->InsertChild(pPacketNode, nullptr);
-  }
-
-  pXFARootNode->SetXMLMappingNode(pXMLDocumentNode);
-  return pXFARootNode;
-}
-
-CXFA_Node* CXFA_SimpleParser::ParseAsXDPPacket_Config(
-    CFX_XMLNode* pXMLDocumentNode) {
-  const PacketInfo* packet = GetPacketByIndex(XFA_PacketType::Config);
-  if (!MatchNodeName(pXMLDocumentNode, packet->name, packet->uri,
-                     packet->flags)) {
-    return nullptr;
-  }
-  CXFA_Node* pNode =
-      m_pFactory->CreateNode(XFA_PacketType::Config, XFA_Element::Config);
-  if (!pNode)
-    return nullptr;
-
-  pNode->JSObject()->SetCData(XFA_Attribute::Name, packet->name, false, false);
-  if (!NormalLoader(pNode, pXMLDocumentNode, XFA_PacketType::Config, true))
-    return nullptr;
-
-  pNode->SetXMLMappingNode(pXMLDocumentNode);
-  return pNode;
-}
-
-CXFA_Node* CXFA_SimpleParser::ParseAsXDPPacket_Template(
-    CFX_XMLNode* pXMLDocumentNode) {
-  const PacketInfo* packet = GetPacketByIndex(XFA_PacketType::Template);
-  if (!MatchNodeName(pXMLDocumentNode, packet->name, packet->uri,
-                     packet->flags)) {
-    return nullptr;
-  }
-
-  CXFA_Node* pNode =
-      m_pFactory->CreateNode(XFA_PacketType::Template, XFA_Element::Template);
-  if (!pNode)
-    return nullptr;
-
-  pNode->JSObject()->SetCData(XFA_Attribute::Name, packet->name, false, false);
-  if (m_bDocumentParser) {
-    CFX_XMLElement* pXMLDocumentElement =
-        static_cast<CFX_XMLElement*>(pXMLDocumentNode);
-    WideString wsNamespaceURI = pXMLDocumentElement->GetNamespaceURI();
-    if (wsNamespaceURI.IsEmpty())
-      wsNamespaceURI = pXMLDocumentElement->GetString(L"xmlns:xfa");
-
-    pNode->GetDocument()->RecognizeXFAVersionNumber(wsNamespaceURI);
-  }
-  if (!NormalLoader(pNode, pXMLDocumentNode, XFA_PacketType::Template, true))
-    return nullptr;
-
-  pNode->SetXMLMappingNode(pXMLDocumentNode);
-  return pNode;
-}
-
-CXFA_Node* CXFA_SimpleParser::ParseAsXDPPacket_Form(
-    CFX_XMLNode* pXMLDocumentNode) {
-  const PacketInfo* packet = GetPacketByIndex(XFA_PacketType::Form);
-  if (!MatchNodeName(pXMLDocumentNode, packet->name, packet->uri,
-                     packet->flags)) {
-    return nullptr;
-  }
-
-  CFX_XMLElement* pXMLDocumentElement =
-      static_cast<CFX_XMLElement*>(pXMLDocumentNode);
-  WideString wsChecksum = pXMLDocumentElement->GetString(L"checksum");
-  if (wsChecksum.GetLength() != 28 || m_pXMLParser->m_dwCheckStatus != 0x03) {
-    return nullptr;
-  }
-
-  auto pChecksum = pdfium::MakeUnique<CFX_ChecksumContext>();
-  pChecksum->StartChecksum();
-  pChecksum->UpdateChecksum(m_pFileRead, m_pXMLParser->m_nStart[0],
-                            m_pXMLParser->m_nSize[0]);
-  pChecksum->UpdateChecksum(m_pFileRead, m_pXMLParser->m_nStart[1],
-                            m_pXMLParser->m_nSize[1]);
-  pChecksum->FinishChecksum();
-  ByteString bsCheck = pChecksum->GetChecksum();
-  if (bsCheck != wsChecksum.UTF8Encode())
-    return nullptr;
-
-  CXFA_Node* pNode =
-      m_pFactory->CreateNode(XFA_PacketType::Form, XFA_Element::Form);
-  if (!pNode)
-    return nullptr;
-
-  pNode->JSObject()->SetCData(XFA_Attribute::Name, packet->name, false, false);
-  pNode->JSObject()->SetAttribute(XFA_Attribute::Checksum,
-                                  wsChecksum.AsStringView(), false);
-  CXFA_Template* pTemplateRoot =
-      m_pRootNode->GetFirstChildByClass<CXFA_Template>(XFA_Element::Template);
-  CXFA_Subform* pTemplateChosen =
-      pTemplateRoot ? pTemplateRoot->GetFirstChildByClass<CXFA_Subform>(
-                          XFA_Element::Subform)
-                    : nullptr;
-  bool bUseAttribute = true;
-  if (pTemplateChosen &&
-      pTemplateChosen->JSObject()->GetEnum(XFA_Attribute::RestoreState) !=
-          XFA_AttributeEnum::Auto) {
-    bUseAttribute = false;
-  }
-  if (!NormalLoader(pNode, pXMLDocumentNode, XFA_PacketType::Form,
-                    bUseAttribute))
-    return nullptr;
-
-  pNode->SetXMLMappingNode(pXMLDocumentNode);
-  return pNode;
-}
-
-CXFA_Node* CXFA_SimpleParser::ParseAsXDPPacket_Data(
-    CFX_XMLNode* pXMLDocumentNode) {
-  CFX_XMLNode* pDatasetsXMLNode = GetDataSetsFromXDP(pXMLDocumentNode);
-  const PacketInfo* packet = GetPacketByIndex(XFA_PacketType::Datasets);
-  if (pDatasetsXMLNode) {
-    CXFA_Node* pNode = m_pFactory->CreateNode(XFA_PacketType::Datasets,
-                                              XFA_Element::DataModel);
-    if (!pNode)
-      return nullptr;
-
-    pNode->JSObject()->SetCData(XFA_Attribute::Name, packet->name, false,
-                                false);
-    if (!DataLoader(pNode, pDatasetsXMLNode, false))
-      return nullptr;
-
-    pNode->SetXMLMappingNode(pDatasetsXMLNode);
-    return pNode;
-  }
-
-  CFX_XMLNode* pDataXMLNode = nullptr;
-  if (MatchNodeName(pXMLDocumentNode, L"data", packet->uri, packet->flags)) {
-    static_cast<CFX_XMLElement*>(pXMLDocumentNode)
-        ->RemoveAttribute(L"xmlns:xfa");
-    pDataXMLNode = pXMLDocumentNode;
-  } else {
-    CFX_XMLElement* pDataElement = new CFX_XMLElement(L"xfa:data");
-    CFX_XMLNode* pParentXMLNode =
-        pXMLDocumentNode->GetNodeItem(CFX_XMLNode::Parent);
-    if (pParentXMLNode)
-      pParentXMLNode->RemoveChildNode(pXMLDocumentNode);
-
-    ASSERT(pXMLDocumentNode->GetType() == FX_XMLNODE_Element);
-    if (pXMLDocumentNode->GetType() == FX_XMLNODE_Element) {
-      static_cast<CFX_XMLElement*>(pXMLDocumentNode)
-          ->RemoveAttribute(L"xmlns:xfa");
-    }
-    pDataElement->InsertChildNode(pXMLDocumentNode);
-    pDataXMLNode = pDataElement;
-  }
-
-  if (pDataXMLNode) {
-    CXFA_Node* pNode = m_pFactory->CreateNode(XFA_PacketType::Datasets,
-                                              XFA_Element::DataGroup);
-    if (!pNode) {
-      if (pDataXMLNode != pXMLDocumentNode)
-        delete pDataXMLNode;
-      return nullptr;
-    }
-    WideString wsLocalName =
-        static_cast<CFX_XMLElement*>(pDataXMLNode)->GetLocalTagName();
-    pNode->JSObject()->SetCData(XFA_Attribute::Name, wsLocalName, false, false);
-    if (!DataLoader(pNode, pDataXMLNode, true))
-      return nullptr;
-
-    pNode->SetXMLMappingNode(pDataXMLNode);
-    if (pDataXMLNode != pXMLDocumentNode)
-      pNode->SetFlag(XFA_NodeFlag_OwnXMLNode, false);
-    return pNode;
-  }
-  return nullptr;
-}
-
-CXFA_Node* CXFA_SimpleParser::ParseAsXDPPacket_LocaleConnectionSourceSet(
-    CFX_XMLNode* pXMLDocumentNode,
-    XFA_PacketType packet_type,
-    XFA_Element element) {
-  const PacketInfo* packet = GetPacketByIndex(packet_type);
-  if (!MatchNodeName(pXMLDocumentNode, packet->name, packet->uri,
-                     packet->flags)) {
-    return nullptr;
-  }
-
-  CXFA_Node* pNode = m_pFactory->CreateNode(packet_type, element);
-  if (!pNode)
-    return nullptr;
-
-  pNode->JSObject()->SetCData(XFA_Attribute::Name, packet->name, false, false);
-  if (!NormalLoader(pNode, pXMLDocumentNode, packet_type, true))
-    return nullptr;
-
-  pNode->SetXMLMappingNode(pXMLDocumentNode);
-  return pNode;
-}
-
-CXFA_Node* CXFA_SimpleParser::ParseAsXDPPacket_Xdc(
-    CFX_XMLNode* pXMLDocumentNode) {
-  const PacketInfo* packet = GetPacketByIndex(XFA_PacketType::Xdc);
-  if (!MatchNodeName(pXMLDocumentNode, packet->name, packet->uri,
-                     packet->flags))
-    return nullptr;
-
-  CXFA_Node* pNode =
-      m_pFactory->CreateNode(XFA_PacketType::Xdc, XFA_Element::Xdc);
-  if (!pNode)
-    return nullptr;
-
-  pNode->JSObject()->SetCData(XFA_Attribute::Name, packet->name, false, false);
-  pNode->SetXMLMappingNode(pXMLDocumentNode);
-  return pNode;
-}
-
-CXFA_Node* CXFA_SimpleParser::ParseAsXDPPacket_User(
-    CFX_XMLNode* pXMLDocumentNode) {
-  CXFA_Node* pNode =
-      m_pFactory->CreateNode(XFA_PacketType::Xdp, XFA_Element::Packet);
-  if (!pNode)
-    return nullptr;
-
-  WideString wsName =
-      static_cast<CFX_XMLElement*>(pXMLDocumentNode)->GetLocalTagName();
-  pNode->JSObject()->SetCData(XFA_Attribute::Name, wsName, false, false);
-  if (!UserPacketLoader(pNode, pXMLDocumentNode))
-    return nullptr;
-
-  pNode->SetXMLMappingNode(pXMLDocumentNode);
-  return pNode;
-}
-
-CXFA_Node* CXFA_SimpleParser::UserPacketLoader(CXFA_Node* pXFANode,
-                                               CFX_XMLNode* pXMLDoc) {
-  return pXFANode;
-}
-
-CXFA_Node* CXFA_SimpleParser::DataLoader(CXFA_Node* pXFANode,
-                                         CFX_XMLNode* pXMLDoc,
-                                         bool bDoTransform) {
-  ParseDataGroup(pXFANode, pXMLDoc, XFA_PacketType::Datasets);
-  return pXFANode;
-}
-
-CXFA_Node* CXFA_SimpleParser::NormalLoader(CXFA_Node* pXFANode,
-                                           CFX_XMLNode* pXMLDoc,
-                                           XFA_PacketType ePacketID,
-                                           bool bUseAttribute) {
-  bool bOneOfPropertyFound = false;
-  for (CFX_XMLNode* pXMLChild = pXMLDoc->GetNodeItem(CFX_XMLNode::FirstChild);
-       pXMLChild;
-       pXMLChild = pXMLChild->GetNodeItem(CFX_XMLNode::NextSibling)) {
-    switch (pXMLChild->GetType()) {
-      case FX_XMLNODE_Element: {
-        CFX_XMLElement* pXMLElement = static_cast<CFX_XMLElement*>(pXMLChild);
-        WideString wsTagName = pXMLElement->GetLocalTagName();
-        XFA_Element eType = CXFA_Node::NameToElement(wsTagName);
-        if (eType == XFA_Element::Unknown)
-          continue;
-
-        if (pXFANode->HasPropertyFlags(
-                eType,
-                XFA_PROPERTYFLAG_OneOf | XFA_PROPERTYFLAG_DefaultOneOf)) {
-          if (bOneOfPropertyFound)
-            break;
-          bOneOfPropertyFound = true;
-        }
-
-        CXFA_Node* pXFAChild = m_pFactory->CreateNode(ePacketID, eType);
-        if (!pXFAChild)
-          return nullptr;
-        if (ePacketID == XFA_PacketType::Config) {
-          pXFAChild->JSObject()->SetAttribute(XFA_Attribute::Name,
-                                              wsTagName.AsStringView(), false);
-        }
-
-        bool IsNeedValue = true;
-        for (auto it : pXMLElement->GetAttributes()) {
-          WideString wsAttrName;
-          GetAttributeLocalName(it.first.AsStringView(), wsAttrName);
-          if (wsAttrName == L"nil" && it.second == L"true")
-            IsNeedValue = false;
-
-          XFA_Attribute attr =
-              CXFA_Node::NameToAttribute(wsAttrName.AsStringView());
-          if (attr == XFA_Attribute::Unknown)
-            continue;
-
-          if (!bUseAttribute && attr != XFA_Attribute::Name &&
-              attr != XFA_Attribute::Save) {
-            continue;
-          }
-          pXFAChild->JSObject()->SetAttribute(attr, it.second.AsStringView(),
-                                              false);
-        }
-        pXFANode->InsertChild(pXFAChild, nullptr);
-        if (eType == XFA_Element::Validate || eType == XFA_Element::Locale) {
-          if (ePacketID == XFA_PacketType::Config)
-            ParseContentNode(pXFAChild, pXMLElement, ePacketID);
-          else
-            NormalLoader(pXFAChild, pXMLElement, ePacketID, bUseAttribute);
-
-          break;
-        }
-        switch (pXFAChild->GetObjectType()) {
-          case XFA_ObjectType::ContentNode:
-          case XFA_ObjectType::TextNode:
-          case XFA_ObjectType::NodeC:
-          case XFA_ObjectType::NodeV:
-            if (IsNeedValue)
-              ParseContentNode(pXFAChild, pXMLElement, ePacketID);
-            break;
-          default:
-            NormalLoader(pXFAChild, pXMLElement, ePacketID, bUseAttribute);
-            break;
-        }
-      } break;
-      case FX_XMLNODE_Instruction:
-        ParseInstruction(pXFANode, static_cast<CFX_XMLInstruction*>(pXMLChild),
-                         ePacketID);
-        break;
-      default:
-        break;
-    }
-  }
-  return pXFANode;
-}
-
-void CXFA_SimpleParser::ParseContentNode(CXFA_Node* pXFANode,
-                                         CFX_XMLNode* pXMLNode,
-                                         XFA_PacketType ePacketID) {
-  XFA_Element element = XFA_Element::Sharptext;
-  if (pXFANode->GetElementType() == XFA_Element::ExData) {
-    WideString wsContentType =
-        pXFANode->JSObject()->GetCData(XFA_Attribute::ContentType);
-    if (wsContentType == L"text/html")
-      element = XFA_Element::SharpxHTML;
-    else if (wsContentType == L"text/xml")
-      element = XFA_Element::Sharpxml;
-  }
-  if (element == XFA_Element::SharpxHTML)
-    pXFANode->SetXMLMappingNode(pXMLNode);
-
-  WideString wsValue;
-  for (CFX_XMLNode* pXMLChild = pXMLNode->GetNodeItem(CFX_XMLNode::FirstChild);
-       pXMLChild;
-       pXMLChild = pXMLChild->GetNodeItem(CFX_XMLNode::NextSibling)) {
-    FX_XMLNODETYPE eNodeType = pXMLChild->GetType();
-    if (eNodeType == FX_XMLNODE_Instruction)
-      continue;
-
-    if (element == XFA_Element::SharpxHTML) {
-      if (eNodeType != FX_XMLNODE_Element)
-        break;
-
-      if (XFA_RecognizeRichText(static_cast<CFX_XMLElement*>(pXMLChild)))
-        wsValue +=
-            GetPlainTextFromRichText(static_cast<CFX_XMLElement*>(pXMLChild));
-    } else if (element == XFA_Element::Sharpxml) {
-      if (eNodeType != FX_XMLNODE_Element)
-        break;
-
-      ConvertXMLToPlainText(static_cast<CFX_XMLElement*>(pXMLChild), wsValue);
-    } else {
-      if (eNodeType == FX_XMLNODE_Element)
-        break;
-      if (eNodeType == FX_XMLNODE_Text || eNodeType == FX_XMLNODE_CharData)
-        wsValue = static_cast<CFX_XMLText*>(pXMLChild)->GetText();
-    }
-    break;
-  }
-  if (!wsValue.IsEmpty()) {
-    if (pXFANode->IsContentNode()) {
-      CXFA_Node* pContentRawDataNode =
-          m_pFactory->CreateNode(ePacketID, element);
-      ASSERT(pContentRawDataNode);
-      pContentRawDataNode->JSObject()->SetCData(XFA_Attribute::Value, wsValue,
-                                                false, false);
-      pXFANode->InsertChild(pContentRawDataNode, nullptr);
-    } else {
-      pXFANode->JSObject()->SetCData(XFA_Attribute::Value, wsValue, false,
-                                     false);
-    }
-  }
-}
-
-void CXFA_SimpleParser::ParseDataGroup(CXFA_Node* pXFANode,
-                                       CFX_XMLNode* pXMLNode,
-                                       XFA_PacketType ePacketID) {
-  for (CFX_XMLNode* pXMLChild = pXMLNode->GetNodeItem(CFX_XMLNode::FirstChild);
-       pXMLChild;
-       pXMLChild = pXMLChild->GetNodeItem(CFX_XMLNode::NextSibling)) {
-    switch (pXMLChild->GetType()) {
-      case FX_XMLNODE_Element: {
-        CFX_XMLElement* pXMLElement = static_cast<CFX_XMLElement*>(pXMLChild);
-        {
-          WideString wsNamespaceURI = GetElementTagNamespaceURI(pXMLElement);
-          if (wsNamespaceURI == L"http://www.xfa.com/schema/xfa-package/" ||
-              wsNamespaceURI == L"http://www.xfa.org/schema/xfa-package/" ||
-              wsNamespaceURI == L"http://www.w3.org/2001/XMLSchema-instance") {
-            continue;
-          }
-        }
-
-        XFA_Element eNodeType = XFA_Element::DataModel;
-        if (eNodeType == XFA_Element::DataModel) {
-          WideString wsDataNodeAttr;
-          if (FindAttributeWithNS(pXMLElement, L"dataNode",
-                                  L"http://www.xfa.org/schema/xfa-data/1.0/",
-                                  wsDataNodeAttr)) {
-            if (wsDataNodeAttr == L"dataGroup")
-              eNodeType = XFA_Element::DataGroup;
-            else if (wsDataNodeAttr == L"dataValue")
-              eNodeType = XFA_Element::DataValue;
-          }
-        }
-        WideString wsContentType;
-        if (eNodeType == XFA_Element::DataModel) {
-          if (FindAttributeWithNS(pXMLElement, L"contentType",
-                                  L"http://www.xfa.org/schema/xfa-data/1.0/",
-                                  wsContentType)) {
-            if (!wsContentType.IsEmpty())
-              eNodeType = XFA_Element::DataValue;
-          }
-        }
-        if (eNodeType == XFA_Element::DataModel) {
-          for (CFX_XMLNode* pXMLDataChild =
-                   pXMLElement->GetNodeItem(CFX_XMLNode::FirstChild);
-               pXMLDataChild; pXMLDataChild = pXMLDataChild->GetNodeItem(
-                                  CFX_XMLNode::NextSibling)) {
-            if (pXMLDataChild->GetType() == FX_XMLNODE_Element) {
-              if (!XFA_RecognizeRichText(
-                      static_cast<CFX_XMLElement*>(pXMLDataChild))) {
-                eNodeType = XFA_Element::DataGroup;
-                break;
-              }
-            }
-          }
-        }
-        if (eNodeType == XFA_Element::DataModel)
-          eNodeType = XFA_Element::DataValue;
-
-        CXFA_Node* pXFAChild =
-            m_pFactory->CreateNode(XFA_PacketType::Datasets, eNodeType);
-        if (!pXFAChild)
-          return;
-
-        pXFAChild->JSObject()->SetCData(
-            XFA_Attribute::Name, pXMLElement->GetLocalTagName(), false, false);
-        bool bNeedValue = true;
-
-        for (auto it : pXMLElement->GetAttributes()) {
-          WideString wsName;
-          WideString wsNS;
-          if (!ResolveAttribute(pXMLElement, it.first, wsName, wsNS)) {
-            continue;
-          }
-          if (wsName == L"nil" && it.second == L"true") {
-            bNeedValue = false;
-            continue;
-          }
-          if (wsNS == L"http://www.xfa.com/schema/xfa-package/" ||
-              wsNS == L"http://www.xfa.org/schema/xfa-package/" ||
-              wsNS == L"http://www.w3.org/2001/XMLSchema-instance" ||
-              wsNS == L"http://www.xfa.org/schema/xfa-data/1.0/") {
-            continue;
-          }
-          CXFA_Node* pXFAMetaData = m_pFactory->CreateNode(
-              XFA_PacketType::Datasets, XFA_Element::DataValue);
-          if (!pXFAMetaData)
-            return;
-
-          pXFAMetaData->JSObject()->SetCData(XFA_Attribute::Name, wsName, false,
-                                             false);
-          pXFAMetaData->JSObject()->SetCData(XFA_Attribute::QualifiedName,
-                                             it.first, false, false);
-          pXFAMetaData->JSObject()->SetCData(XFA_Attribute::Value, it.second,
-                                             false, false);
-          pXFAMetaData->JSObject()->SetEnum(XFA_Attribute::Contains,
-                                            XFA_AttributeEnum::MetaData, false);
-          pXFAChild->InsertChild(pXFAMetaData, nullptr);
-          pXFAMetaData->SetXMLMappingNode(pXMLElement);
-          pXFAMetaData->SetFlag(XFA_NodeFlag_Initialized, false);
-        }
-
-        if (!bNeedValue) {
-          WideString wsNilName(L"xsi:nil");
-          pXMLElement->RemoveAttribute(wsNilName.c_str());
-        }
-        pXFANode->InsertChild(pXFAChild, nullptr);
-        if (eNodeType == XFA_Element::DataGroup)
-          ParseDataGroup(pXFAChild, pXMLElement, ePacketID);
-        else if (bNeedValue)
-          ParseDataValue(pXFAChild, pXMLChild, XFA_PacketType::Datasets);
-
-        pXFAChild->SetXMLMappingNode(pXMLElement);
-        pXFAChild->SetFlag(XFA_NodeFlag_Initialized, false);
-        continue;
-      }
-      case FX_XMLNODE_CharData:
-      case FX_XMLNODE_Text: {
-        CFX_XMLText* pXMLText = static_cast<CFX_XMLText*>(pXMLChild);
-        WideString wsText = pXMLText->GetText();
-        if (IsStringAllWhitespace(wsText))
-          continue;
-
-        CXFA_Node* pXFAChild = m_pFactory->CreateNode(XFA_PacketType::Datasets,
-                                                      XFA_Element::DataValue);
-        if (!pXFAChild)
-          return;
-
-        pXFAChild->JSObject()->SetCData(XFA_Attribute::Value, wsText, false,
-                                        false);
-        pXFANode->InsertChild(pXFAChild, nullptr);
-        pXFAChild->SetXMLMappingNode(pXMLText);
-        pXFAChild->SetFlag(XFA_NodeFlag_Initialized, false);
-        continue;
-      }
-      default:
-        continue;
-    }
-  }
-}
-
-void CXFA_SimpleParser::ParseDataValue(CXFA_Node* pXFANode,
-                                       CFX_XMLNode* pXMLNode,
-                                       XFA_PacketType ePacketID) {
-  CFX_WideTextBuf wsValueTextBuf;
-  CFX_WideTextBuf wsCurValueTextBuf;
-  bool bMarkAsCompound = false;
-  CFX_XMLNode* pXMLCurValueNode = nullptr;
-  for (CFX_XMLNode* pXMLChild = pXMLNode->GetNodeItem(CFX_XMLNode::FirstChild);
-       pXMLChild;
-       pXMLChild = pXMLChild->GetNodeItem(CFX_XMLNode::NextSibling)) {
-    FX_XMLNODETYPE eNodeType = pXMLChild->GetType();
-    if (eNodeType == FX_XMLNODE_Instruction)
-      continue;
-
-    if (eNodeType == FX_XMLNODE_Text || eNodeType == FX_XMLNODE_CharData) {
-      WideString wsText = static_cast<CFX_XMLText*>(pXMLChild)->GetText();
-      if (!pXMLCurValueNode)
-        pXMLCurValueNode = pXMLChild;
-
-      wsCurValueTextBuf << wsText;
-    } else if (XFA_RecognizeRichText(static_cast<CFX_XMLElement*>(pXMLChild))) {
-      WideString wsText =
-          GetPlainTextFromRichText(static_cast<CFX_XMLElement*>(pXMLChild));
-      if (!pXMLCurValueNode)
-        pXMLCurValueNode = pXMLChild;
-
-      wsCurValueTextBuf << wsText;
-    } else {
-      bMarkAsCompound = true;
-      if (pXMLCurValueNode) {
-        WideString wsCurValue = wsCurValueTextBuf.MakeString();
-        if (!wsCurValue.IsEmpty()) {
-          CXFA_Node* pXFAChild =
-              m_pFactory->CreateNode(ePacketID, XFA_Element::DataValue);
-          if (!pXFAChild)
-            return;
-
-          pXFAChild->JSObject()->SetCData(XFA_Attribute::Name, L"", false,
-                                          false);
-          pXFAChild->JSObject()->SetCData(XFA_Attribute::Value, wsCurValue,
-                                          false, false);
-          pXFANode->InsertChild(pXFAChild, nullptr);
-          pXFAChild->SetXMLMappingNode(pXMLCurValueNode);
-          pXFAChild->SetFlag(XFA_NodeFlag_Initialized, false);
-          wsValueTextBuf << wsCurValue;
-          wsCurValueTextBuf.Clear();
-        }
-        pXMLCurValueNode = nullptr;
-      }
-      CXFA_Node* pXFAChild =
-          m_pFactory->CreateNode(ePacketID, XFA_Element::DataValue);
-      if (!pXFAChild)
-        return;
-
-      WideString wsNodeStr =
-          static_cast<CFX_XMLElement*>(pXMLChild)->GetLocalTagName();
-      pXFAChild->JSObject()->SetCData(XFA_Attribute::Name, wsNodeStr, false,
-                                      false);
-      ParseDataValue(pXFAChild, pXMLChild, ePacketID);
-      pXFANode->InsertChild(pXFAChild, nullptr);
-      pXFAChild->SetXMLMappingNode(pXMLChild);
-      pXFAChild->SetFlag(XFA_NodeFlag_Initialized, false);
-      WideString wsCurValue =
-          pXFAChild->JSObject()->GetCData(XFA_Attribute::Value);
-      wsValueTextBuf << wsCurValue;
-    }
-  }
-  if (pXMLCurValueNode) {
-    WideString wsCurValue = wsCurValueTextBuf.MakeString();
-    if (!wsCurValue.IsEmpty()) {
-      if (bMarkAsCompound) {
-        CXFA_Node* pXFAChild =
-            m_pFactory->CreateNode(ePacketID, XFA_Element::DataValue);
-        if (!pXFAChild)
-          return;
-
-        pXFAChild->JSObject()->SetCData(XFA_Attribute::Name, L"", false, false);
-        pXFAChild->JSObject()->SetCData(XFA_Attribute::Value, wsCurValue, false,
-                                        false);
-        pXFANode->InsertChild(pXFAChild, nullptr);
-        pXFAChild->SetXMLMappingNode(pXMLCurValueNode);
-        pXFAChild->SetFlag(XFA_NodeFlag_Initialized, false);
-      }
-      wsValueTextBuf << wsCurValue;
-      wsCurValueTextBuf.Clear();
-    }
-    pXMLCurValueNode = nullptr;
-  }
-  WideString wsNodeValue = wsValueTextBuf.MakeString();
-  pXFANode->JSObject()->SetCData(XFA_Attribute::Value, wsNodeValue, false,
-                                 false);
-}
-
-void CXFA_SimpleParser::ParseInstruction(CXFA_Node* pXFANode,
-                                         CFX_XMLInstruction* pXMLInstruction,
-                                         XFA_PacketType ePacketID) {
-  if (!m_bDocumentParser)
-    return;
-
-  WideString wsTargetName = pXMLInstruction->GetName();
-  const std::vector<WideString>& target_data = pXMLInstruction->GetTargetData();
-  if (wsTargetName == L"originalXFAVersion") {
-    if (target_data.size() > 1 &&
-        (pXFANode->GetDocument()->RecognizeXFAVersionNumber(target_data[0]) !=
-         XFA_VERSION_UNKNOWN) &&
-        target_data[1] == L"v2.7-scripting:1") {
-      pXFANode->GetDocument()->SetFlag(XFA_DOCFLAG_Scripting, true);
-    }
-  } else if (wsTargetName == L"acrobat") {
-    if (target_data.size() > 1 && target_data[0] == L"JavaScript" &&
-        target_data[1] == L"strictScoping") {
-      pXFANode->GetDocument()->SetFlag(XFA_DOCFLAG_StrictScoping, true);
-    }
-  }
-}
-
-void CXFA_SimpleParser::CloseParser() {
-  m_pXMLDoc.reset();
-  m_pStream.Reset();
-}
diff --git a/xfa/fxfa/parser/cxfa_simple_parser.h b/xfa/fxfa/parser/cxfa_simple_parser.h
deleted file mode 100644
index 7a20de3..0000000
--- a/xfa/fxfa/parser/cxfa_simple_parser.h
+++ /dev/null
@@ -1,88 +0,0 @@
-// Copyright 2014 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_SIMPLE_PARSER_H_
-#define XFA_FXFA_PARSER_CXFA_SIMPLE_PARSER_H_
-
-#include <memory>
-
-#include "xfa/fxfa/fxfa_basic.h"
-
-class CXFA_Document;
-class CXFA_Node;
-class CFX_XMLDoc;
-class CFX_XMLInstruction;
-class CFX_XMLNode;
-class CFX_XMLParser;
-class IFX_SeekableStream;
-class CFX_SeekableStreamProxy;
-
-class CXFA_SimpleParser {
- public:
-  CXFA_SimpleParser();
-  explicit CXFA_SimpleParser(CXFA_Document* pFactory);
-  ~CXFA_SimpleParser();
-
-  int32_t StartParse(const RetainPtr<IFX_SeekableStream>& pStream,
-                     XFA_PacketType ePacketID);
-  int32_t DoParse();
-  CFX_XMLNode* ParseXMLData(const ByteString& wsXML);
-  void ConstructXFANode(CXFA_Node* pXFANode, CFX_XMLNode* pXMLNode);
-  CXFA_Node* GetRootNode() const;
-  CFX_XMLDoc* GetXMLDoc() const;
-  void CloseParser();
-
-  // Called later for the ctor with no parameters.
-  void SetFactory(CXFA_Document* pFactory);
-
- private:
-  CXFA_Node* ParseAsXDPPacket(CFX_XMLNode* pXMLDocumentNode,
-                              XFA_PacketType ePacketID);
-  CXFA_Node* ParseAsXDPPacket_XDP(CFX_XMLNode* pXMLDocumentNode);
-  CXFA_Node* ParseAsXDPPacket_Config(CFX_XMLNode* pXMLDocumentNode);
-  CXFA_Node* ParseAsXDPPacket_Template(CFX_XMLNode* pXMLDocumentNode);
-  CXFA_Node* ParseAsXDPPacket_Form(CFX_XMLNode* pXMLDocumentNode);
-  CXFA_Node* ParseAsXDPPacket_Data(CFX_XMLNode* pXMLDocumentNode);
-  CXFA_Node* ParseAsXDPPacket_LocaleConnectionSourceSet(
-      CFX_XMLNode* pXMLDocumentNode,
-      XFA_PacketType packet_type,
-      XFA_Element element);
-  CXFA_Node* ParseAsXDPPacket_Xdc(CFX_XMLNode* pXMLDocumentNode);
-  CXFA_Node* ParseAsXDPPacket_User(CFX_XMLNode* pXMLDocumentNode);
-  CXFA_Node* NormalLoader(CXFA_Node* pXFANode,
-                          CFX_XMLNode* pXMLDoc,
-                          XFA_PacketType ePacketID,
-                          bool bUseAttribute);
-  CXFA_Node* DataLoader(CXFA_Node* pXFANode,
-                        CFX_XMLNode* pXMLDoc,
-                        bool bDoTransform);
-  CXFA_Node* UserPacketLoader(CXFA_Node* pXFANode, CFX_XMLNode* pXMLDoc);
-  void ParseContentNode(CXFA_Node* pXFANode,
-                        CFX_XMLNode* pXMLNode,
-                        XFA_PacketType ePacketID);
-  void ParseDataValue(CXFA_Node* pXFANode,
-                      CFX_XMLNode* pXMLNode,
-                      XFA_PacketType ePacketID);
-  void ParseDataGroup(CXFA_Node* pXFANode,
-                      CFX_XMLNode* pXMLNode,
-                      XFA_PacketType ePacketID);
-  void ParseInstruction(CXFA_Node* pXFANode,
-                        CFX_XMLInstruction* pXMLInstruction,
-                        XFA_PacketType ePacketID);
-
-  std::unique_ptr<CFX_XMLDoc> m_pXMLDoc;
-  UnownedPtr<CFX_XMLParser> m_pXMLParser;  // Owned by |m_pXMLDoc|
-  RetainPtr<CFX_SeekableStreamProxy> m_pStream;
-  RetainPtr<IFX_SeekableStream> m_pFileRead;
-  UnownedPtr<CXFA_Document> m_pFactory;
-  // TODO(dsinclair): Figure out who owns this.
-  CXFA_Node* m_pRootNode = nullptr;
-  XFA_PacketType m_ePacketID = XFA_PacketType::User;
-  bool m_bParseStarted = false;
-  const bool m_bDocumentParser;
-};
-
-#endif  // XFA_FXFA_PARSER_CXFA_SIMPLE_PARSER_H_
diff --git a/xfa/fxfa/parser/cxfa_soapaction.cpp b/xfa/fxfa/parser/cxfa_soapaction.cpp
index b53a653..514c667 100644
--- a/xfa/fxfa/parser/cxfa_soapaction.cpp
+++ b/xfa/fxfa/parser/cxfa_soapaction.cpp
@@ -6,19 +6,17 @@
 
 #include "xfa/fxfa/parser/cxfa_soapaction.h"
 
-#include "fxjs/xfa/cjx_soapaction.h"
+#include "fxjs/xfa/cjx_textnode.h"
 #include "third_party/base/ptr_util.h"
 
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kSoapActionAttributeData[] = {
     {XFA_Attribute::Id, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Name, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Use, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Usehref, XFA_AttributeType::CData, nullptr},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"soapAction";
+};
 
 }  // namespace
 
@@ -28,9 +26,8 @@
                 XFA_XDPPACKET_ConnectionSet,
                 XFA_ObjectType::TextNode,
                 XFA_Element::SoapAction,
-                nullptr,
-                kAttributeData,
-                kName,
-                pdfium::MakeUnique<CJX_SoapAction>(this)) {}
+                {},
+                kSoapActionAttributeData,
+                pdfium::MakeUnique<CJX_TextNode>(this)) {}
 
-CXFA_SoapAction::~CXFA_SoapAction() {}
+CXFA_SoapAction::~CXFA_SoapAction() = default;
diff --git a/xfa/fxfa/parser/cxfa_soapaction.h b/xfa/fxfa/parser/cxfa_soapaction.h
index b803eae..b7f7526 100644
--- a/xfa/fxfa/parser/cxfa_soapaction.h
+++ b/xfa/fxfa/parser/cxfa_soapaction.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_SoapAction : public CXFA_Node {
+class CXFA_SoapAction final : public CXFA_Node {
  public:
   CXFA_SoapAction(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_SoapAction() override;
diff --git a/xfa/fxfa/parser/cxfa_soapaddress.cpp b/xfa/fxfa/parser/cxfa_soapaddress.cpp
index 39f91a5..08fd142 100644
--- a/xfa/fxfa/parser/cxfa_soapaddress.cpp
+++ b/xfa/fxfa/parser/cxfa_soapaddress.cpp
@@ -6,19 +6,17 @@
 
 #include "xfa/fxfa/parser/cxfa_soapaddress.h"
 
-#include "fxjs/xfa/cjx_soapaddress.h"
+#include "fxjs/xfa/cjx_textnode.h"
 #include "third_party/base/ptr_util.h"
 
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kSoapAddressAttributeData[] = {
     {XFA_Attribute::Id, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Name, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Use, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Usehref, XFA_AttributeType::CData, nullptr},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"soapAddress";
+};
 
 }  // namespace
 
@@ -28,9 +26,8 @@
                 XFA_XDPPACKET_ConnectionSet,
                 XFA_ObjectType::TextNode,
                 XFA_Element::SoapAddress,
-                nullptr,
-                kAttributeData,
-                kName,
-                pdfium::MakeUnique<CJX_SoapAddress>(this)) {}
+                {},
+                kSoapAddressAttributeData,
+                pdfium::MakeUnique<CJX_TextNode>(this)) {}
 
-CXFA_SoapAddress::~CXFA_SoapAddress() {}
+CXFA_SoapAddress::~CXFA_SoapAddress() = default;
diff --git a/xfa/fxfa/parser/cxfa_soapaddress.h b/xfa/fxfa/parser/cxfa_soapaddress.h
index b0feff4..130ddf3 100644
--- a/xfa/fxfa/parser/cxfa_soapaddress.h
+++ b/xfa/fxfa/parser/cxfa_soapaddress.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_SoapAddress : public CXFA_Node {
+class CXFA_SoapAddress final : public CXFA_Node {
  public:
   CXFA_SoapAddress(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_SoapAddress() override;
diff --git a/xfa/fxfa/parser/cxfa_solid.cpp b/xfa/fxfa/parser/cxfa_solid.cpp
index 4a20194..3ab0e1d 100644
--- a/xfa/fxfa/parser/cxfa_solid.cpp
+++ b/xfa/fxfa/parser/cxfa_solid.cpp
@@ -6,20 +6,20 @@
 
 #include "xfa/fxfa/parser/cxfa_solid.h"
 
-#include "fxjs/xfa/cjx_solid.h"
+#include "fxjs/xfa/cjx_node.h"
 #include "third_party/base/ptr_util.h"
 
 namespace {
 
-const CXFA_Node::PropertyData kPropertyData[] = {{XFA_Element::Extras, 1, 0},
-                                                 {XFA_Element::Unknown, 0, 0}};
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::PropertyData kSolidPropertyData[] = {
+    {XFA_Element::Extras, 1, 0},
+};
+
+const CXFA_Node::AttributeData kSolidAttributeData[] = {
     {XFA_Attribute::Id, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Use, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Usehref, XFA_AttributeType::CData, nullptr},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"solid";
+};
 
 }  // namespace
 
@@ -29,9 +29,8 @@
                 (XFA_XDPPACKET_Template | XFA_XDPPACKET_Form),
                 XFA_ObjectType::Node,
                 XFA_Element::Solid,
-                kPropertyData,
-                kAttributeData,
-                kName,
-                pdfium::MakeUnique<CJX_Solid>(this)) {}
+                kSolidPropertyData,
+                kSolidAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_Solid::~CXFA_Solid() {}
+CXFA_Solid::~CXFA_Solid() = default;
diff --git a/xfa/fxfa/parser/cxfa_solid.h b/xfa/fxfa/parser/cxfa_solid.h
index ec1e2d0..28666ef 100644
--- a/xfa/fxfa/parser/cxfa_solid.h
+++ b/xfa/fxfa/parser/cxfa_solid.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Solid : public CXFA_Node {
+class CXFA_Solid final : public CXFA_Node {
  public:
   CXFA_Solid(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Solid() override;
diff --git a/xfa/fxfa/parser/cxfa_source.cpp b/xfa/fxfa/parser/cxfa_source.cpp
index 95d3736..eb7773c 100644
--- a/xfa/fxfa/parser/cxfa_source.cpp
+++ b/xfa/fxfa/parser/cxfa_source.cpp
@@ -11,16 +11,16 @@
 
 namespace {
 
-const CXFA_Node::PropertyData kPropertyData[] = {{XFA_Element::Connect, 1, 0},
-                                                 {XFA_Element::Unknown, 0, 0}};
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::PropertyData kSourcePropertyData[] = {
+    {XFA_Element::Connect, 1, 0},
+};
+
+const CXFA_Node::AttributeData kSourceAttributeData[] = {
     {XFA_Attribute::Id, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Name, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Use, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Usehref, XFA_AttributeType::CData, nullptr},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"source";
+};
 
 }  // namespace
 
@@ -30,9 +30,8 @@
                 XFA_XDPPACKET_SourceSet,
                 XFA_ObjectType::Node,
                 XFA_Element::Source,
-                kPropertyData,
-                kAttributeData,
-                kName,
+                kSourcePropertyData,
+                kSourceAttributeData,
                 pdfium::MakeUnique<CJX_Source>(this)) {}
 
-CXFA_Source::~CXFA_Source() {}
+CXFA_Source::~CXFA_Source() = default;
diff --git a/xfa/fxfa/parser/cxfa_source.h b/xfa/fxfa/parser/cxfa_source.h
index af74be8..96af083 100644
--- a/xfa/fxfa/parser/cxfa_source.h
+++ b/xfa/fxfa/parser/cxfa_source.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Source : public CXFA_Node {
+class CXFA_Source final : public CXFA_Node {
  public:
   CXFA_Source(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Source() override;
diff --git a/xfa/fxfa/parser/cxfa_sourceset.cpp b/xfa/fxfa/parser/cxfa_sourceset.cpp
index 3deabc6..ba66cdf 100644
--- a/xfa/fxfa/parser/cxfa_sourceset.cpp
+++ b/xfa/fxfa/parser/cxfa_sourceset.cpp
@@ -6,19 +6,17 @@
 
 #include "xfa/fxfa/parser/cxfa_sourceset.h"
 
-#include "fxjs/xfa/cjx_sourceset.h"
+#include "fxjs/xfa/cjx_model.h"
 #include "third_party/base/ptr_util.h"
 
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kSourceSetAttributeData[] = {
     {XFA_Attribute::Id, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Name, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Use, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Usehref, XFA_AttributeType::CData, nullptr},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"sourceSet";
+};
 
 }  // namespace
 
@@ -28,9 +26,8 @@
                 XFA_XDPPACKET_SourceSet,
                 XFA_ObjectType::ModelNode,
                 XFA_Element::SourceSet,
-                nullptr,
-                kAttributeData,
-                kName,
-                pdfium::MakeUnique<CJX_SourceSet>(this)) {}
+                {},
+                kSourceSetAttributeData,
+                pdfium::MakeUnique<CJX_Model>(this)) {}
 
-CXFA_SourceSet::~CXFA_SourceSet() {}
+CXFA_SourceSet::~CXFA_SourceSet() = default;
diff --git a/xfa/fxfa/parser/cxfa_sourceset.h b/xfa/fxfa/parser/cxfa_sourceset.h
index b07e12b..c31b94c 100644
--- a/xfa/fxfa/parser/cxfa_sourceset.h
+++ b/xfa/fxfa/parser/cxfa_sourceset.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_SourceSet : public CXFA_Node {
+class CXFA_SourceSet final : public CXFA_Node {
  public:
   CXFA_SourceSet(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_SourceSet() override;
diff --git a/xfa/fxfa/parser/cxfa_speak.cpp b/xfa/fxfa/parser/cxfa_speak.cpp
index ce05682..605b929 100644
--- a/xfa/fxfa/parser/cxfa_speak.cpp
+++ b/xfa/fxfa/parser/cxfa_speak.cpp
@@ -6,22 +6,20 @@
 
 #include "xfa/fxfa/parser/cxfa_speak.h"
 
-#include "fxjs/xfa/cjx_speak.h"
+#include "fxjs/xfa/cjx_textnode.h"
 #include "third_party/base/ptr_util.h"
 
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kSpeakAttributeData[] = {
     {XFA_Attribute::Id, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Rid, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Use, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Priority, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::Custom},
+     (void*)XFA_AttributeValue::Custom},
     {XFA_Attribute::Usehref, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Disable, XFA_AttributeType::Boolean, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"speak";
+};
 
 }  // namespace
 
@@ -31,9 +29,8 @@
                 (XFA_XDPPACKET_Template | XFA_XDPPACKET_Form),
                 XFA_ObjectType::TextNode,
                 XFA_Element::Speak,
-                nullptr,
-                kAttributeData,
-                kName,
-                pdfium::MakeUnique<CJX_Speak>(this)) {}
+                {},
+                kSpeakAttributeData,
+                pdfium::MakeUnique<CJX_TextNode>(this)) {}
 
-CXFA_Speak::~CXFA_Speak() {}
+CXFA_Speak::~CXFA_Speak() = default;
diff --git a/xfa/fxfa/parser/cxfa_speak.h b/xfa/fxfa/parser/cxfa_speak.h
index 80ef54b..5497927 100644
--- a/xfa/fxfa/parser/cxfa_speak.h
+++ b/xfa/fxfa/parser/cxfa_speak.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Speak : public CXFA_Node {
+class CXFA_Speak final : public CXFA_Node {
  public:
   CXFA_Speak(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Speak() override;
diff --git a/xfa/fxfa/parser/cxfa_staple.cpp b/xfa/fxfa/parser/cxfa_staple.cpp
index 31736d1..436518c 100644
--- a/xfa/fxfa/parser/cxfa_staple.cpp
+++ b/xfa/fxfa/parser/cxfa_staple.cpp
@@ -6,16 +6,17 @@
 
 #include "xfa/fxfa/parser/cxfa_staple.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kStapleAttributeData[] = {
     {XFA_Attribute::Mode, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::UsePrinterSetting},
+     (void*)XFA_AttributeValue::UsePrinterSetting},
     {XFA_Attribute::Desc, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Lock, XFA_AttributeType::Integer, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"staple";
+};
 
 }  // namespace
 
@@ -25,8 +26,8 @@
                 XFA_XDPPACKET_Config,
                 XFA_ObjectType::Node,
                 XFA_Element::Staple,
-                nullptr,
-                kAttributeData,
-                kName) {}
+                {},
+                kStapleAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_Staple::~CXFA_Staple() {}
+CXFA_Staple::~CXFA_Staple() = default;
diff --git a/xfa/fxfa/parser/cxfa_staple.h b/xfa/fxfa/parser/cxfa_staple.h
index 9651fa4..44ef654 100644
--- a/xfa/fxfa/parser/cxfa_staple.h
+++ b/xfa/fxfa/parser/cxfa_staple.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Staple : public CXFA_Node {
+class CXFA_Staple final : public CXFA_Node {
  public:
   CXFA_Staple(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Staple() override;
diff --git a/xfa/fxfa/parser/cxfa_startnode.cpp b/xfa/fxfa/parser/cxfa_startnode.cpp
index f49b595..f415b29 100644
--- a/xfa/fxfa/parser/cxfa_startnode.cpp
+++ b/xfa/fxfa/parser/cxfa_startnode.cpp
@@ -6,14 +6,15 @@
 
 #include "xfa/fxfa/parser/cxfa_startnode.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kStartNodeAttributeData[] = {
     {XFA_Attribute::Desc, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Lock, XFA_AttributeType::Integer, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"startNode";
+};
 
 }  // namespace
 
@@ -23,8 +24,8 @@
                 XFA_XDPPACKET_Config,
                 XFA_ObjectType::NodeV,
                 XFA_Element::StartNode,
-                nullptr,
-                kAttributeData,
-                kName) {}
+                {},
+                kStartNodeAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_StartNode::~CXFA_StartNode() {}
+CXFA_StartNode::~CXFA_StartNode() = default;
diff --git a/xfa/fxfa/parser/cxfa_startnode.h b/xfa/fxfa/parser/cxfa_startnode.h
index 51815e5..b8bab06 100644
--- a/xfa/fxfa/parser/cxfa_startnode.h
+++ b/xfa/fxfa/parser/cxfa_startnode.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_StartNode : public CXFA_Node {
+class CXFA_StartNode final : public CXFA_Node {
  public:
   CXFA_StartNode(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_StartNode() override;
diff --git a/xfa/fxfa/parser/cxfa_startpage.cpp b/xfa/fxfa/parser/cxfa_startpage.cpp
index c52daf2..b8e31cd 100644
--- a/xfa/fxfa/parser/cxfa_startpage.cpp
+++ b/xfa/fxfa/parser/cxfa_startpage.cpp
@@ -6,14 +6,15 @@
 
 #include "xfa/fxfa/parser/cxfa_startpage.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kStartPageAttributeData[] = {
     {XFA_Attribute::Desc, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Lock, XFA_AttributeType::Integer, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"startPage";
+};
 
 }  // namespace
 
@@ -23,8 +24,8 @@
                 XFA_XDPPACKET_Config,
                 XFA_ObjectType::NodeV,
                 XFA_Element::StartPage,
-                nullptr,
-                kAttributeData,
-                kName) {}
+                {},
+                kStartPageAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_StartPage::~CXFA_StartPage() {}
+CXFA_StartPage::~CXFA_StartPage() = default;
diff --git a/xfa/fxfa/parser/cxfa_startpage.h b/xfa/fxfa/parser/cxfa_startpage.h
index 6262aa7..ae0ecee 100644
--- a/xfa/fxfa/parser/cxfa_startpage.h
+++ b/xfa/fxfa/parser/cxfa_startpage.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_StartPage : public CXFA_Node {
+class CXFA_StartPage final : public CXFA_Node {
  public:
   CXFA_StartPage(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_StartPage() override;
diff --git a/xfa/fxfa/parser/cxfa_stipple.cpp b/xfa/fxfa/parser/cxfa_stipple.cpp
index f8c059e..024d111 100644
--- a/xfa/fxfa/parser/cxfa_stipple.cpp
+++ b/xfa/fxfa/parser/cxfa_stipple.cpp
@@ -6,23 +6,24 @@
 
 #include "xfa/fxfa/parser/cxfa_stipple.h"
 
-#include "fxjs/xfa/cjx_stipple.h"
+#include "core/fxge/render_defines.h"
+#include "fxjs/xfa/cjx_node.h"
 #include "third_party/base/ptr_util.h"
 #include "xfa/fxfa/parser/cxfa_color.h"
 
 namespace {
 
-const CXFA_Node::PropertyData kPropertyData[] = {{XFA_Element::Color, 1, 0},
-                                                 {XFA_Element::Extras, 1, 0},
-                                                 {XFA_Element::Unknown, 0, 0}};
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::PropertyData kStipplePropertyData[] = {
+    {XFA_Element::Color, 1, 0},
+    {XFA_Element::Extras, 1, 0},
+};
+
+const CXFA_Node::AttributeData kStippleAttributeData[] = {
     {XFA_Attribute::Id, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Use, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Rate, XFA_AttributeType::Integer, (void*)50},
     {XFA_Attribute::Usehref, XFA_AttributeType::CData, nullptr},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"stipple";
+};
 
 }  // namespace
 
@@ -32,12 +33,11 @@
                 (XFA_XDPPACKET_Template | XFA_XDPPACKET_Form),
                 XFA_ObjectType::Node,
                 XFA_Element::Stipple,
-                kPropertyData,
-                kAttributeData,
-                kName,
-                pdfium::MakeUnique<CJX_Stipple>(this)) {}
+                kStipplePropertyData,
+                kStippleAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_Stipple::~CXFA_Stipple() {}
+CXFA_Stipple::~CXFA_Stipple() = default;
 
 CXFA_Color* CXFA_Stipple::GetColorIfExists() {
   return GetChild<CXFA_Color>(0, XFA_Element::Color, false);
@@ -60,10 +60,10 @@
   CXFA_Color* pColor = GetColorIfExists();
   FX_ARGB crColor = pColor ? pColor->GetValue() : CXFA_Color::kBlackColor;
 
-  int32_t a;
-  FX_COLORREF rgb;
-  std::tie(a, rgb) = ArgbToColorRef(crColor);
-  FX_ARGB cr = ArgbEncode(iRate * a / 100, rgb);
+  int32_t alpha;
+  FX_COLORREF colorref;
+  std::tie(alpha, colorref) = ArgbToAlphaAndColorRef(crColor);
+  FX_ARGB cr = AlphaAndColorRefToArgb(iRate * alpha / 100, colorref);
 
   pGS->SaveGraphState();
   pGS->SetFillColor(CXFA_GEColor(cr));
diff --git a/xfa/fxfa/parser/cxfa_stipple.h b/xfa/fxfa/parser/cxfa_stipple.h
index 839534b..af5581f 100644
--- a/xfa/fxfa/parser/cxfa_stipple.h
+++ b/xfa/fxfa/parser/cxfa_stipple.h
@@ -14,7 +14,7 @@
 class CXFA_Color;
 class CXFA_Graphics;
 
-class CXFA_Stipple : public CXFA_Node {
+class CXFA_Stipple final : public CXFA_Node {
  public:
   static int32_t GetDefaultRate() { return 50; }
 
diff --git a/xfa/fxfa/parser/cxfa_stroke.cpp b/xfa/fxfa/parser/cxfa_stroke.cpp
index 9d5916a..65301c0 100644
--- a/xfa/fxfa/parser/cxfa_stroke.cpp
+++ b/xfa/fxfa/parser/cxfa_stroke.cpp
@@ -17,42 +17,42 @@
 #include "xfa/fxgraphics/cxfa_graphics.h"
 
 void XFA_StrokeTypeSetLineDash(CXFA_Graphics* pGraphics,
-                               XFA_AttributeEnum iStrokeType,
-                               XFA_AttributeEnum iCapType) {
+                               XFA_AttributeValue iStrokeType,
+                               XFA_AttributeValue iCapType) {
   switch (iStrokeType) {
-    case XFA_AttributeEnum::DashDot: {
+    case XFA_AttributeValue::DashDot: {
       float dashArray[] = {4, 1, 2, 1};
-      if (iCapType != XFA_AttributeEnum::Butt) {
+      if (iCapType != XFA_AttributeValue::Butt) {
         dashArray[1] = 2;
         dashArray[3] = 2;
       }
-      pGraphics->SetLineDash(0, dashArray, 4);
+      pGraphics->SetLineDash(0, dashArray, FX_ArraySize(dashArray));
       break;
     }
-    case XFA_AttributeEnum::DashDotDot: {
+    case XFA_AttributeValue::DashDotDot: {
       float dashArray[] = {4, 1, 2, 1, 2, 1};
-      if (iCapType != XFA_AttributeEnum::Butt) {
+      if (iCapType != XFA_AttributeValue::Butt) {
         dashArray[1] = 2;
         dashArray[3] = 2;
         dashArray[5] = 2;
       }
-      pGraphics->SetLineDash(0, dashArray, 6);
+      pGraphics->SetLineDash(0, dashArray, FX_ArraySize(dashArray));
       break;
     }
-    case XFA_AttributeEnum::Dashed: {
+    case XFA_AttributeValue::Dashed: {
       float dashArray[] = {5, 1};
-      if (iCapType != XFA_AttributeEnum::Butt)
+      if (iCapType != XFA_AttributeValue::Butt)
         dashArray[1] = 2;
 
-      pGraphics->SetLineDash(0, dashArray, 2);
+      pGraphics->SetLineDash(0, dashArray, FX_ArraySize(dashArray));
       break;
     }
-    case XFA_AttributeEnum::Dotted: {
+    case XFA_AttributeValue::Dotted: {
       float dashArray[] = {2, 1};
-      if (iCapType != XFA_AttributeEnum::Butt)
+      if (iCapType != XFA_AttributeValue::Butt)
         dashArray[1] = 2;
 
-      pGraphics->SetLineDash(0, dashArray, 2);
+      pGraphics->SetLineDash(0, dashArray, FX_ArraySize(dashArray));
       break;
     }
     default:
@@ -66,9 +66,8 @@
                          uint32_t validPackets,
                          XFA_ObjectType oType,
                          XFA_Element eType,
-                         const PropertyData* properties,
-                         const AttributeData* attributes,
-                         const WideStringView& elementName,
+                         pdfium::span<const PropertyData> properties,
+                         pdfium::span<const AttributeData> attributes,
                          std::unique_ptr<CJX_Object> js_node)
     : CXFA_Node(pDoc,
                 ePacket,
@@ -77,23 +76,22 @@
                 eType,
                 properties,
                 attributes,
-                elementName,
                 std::move(js_node)) {}
 
 CXFA_Stroke::~CXFA_Stroke() = default;
 
 bool CXFA_Stroke::IsVisible() {
-  XFA_AttributeEnum presence = JSObject()
-                                   ->TryEnum(XFA_Attribute::Presence, true)
-                                   .value_or(XFA_AttributeEnum::Visible);
-  return presence == XFA_AttributeEnum::Visible;
+  XFA_AttributeValue presence = JSObject()
+                                    ->TryEnum(XFA_Attribute::Presence, true)
+                                    .value_or(XFA_AttributeValue::Visible);
+  return presence == XFA_AttributeValue::Visible;
 }
 
-XFA_AttributeEnum CXFA_Stroke::GetCapType() {
+XFA_AttributeValue CXFA_Stroke::GetCapType() {
   return JSObject()->GetEnum(XFA_Attribute::Cap);
 }
 
-XFA_AttributeEnum CXFA_Stroke::GetStrokeType() {
+XFA_AttributeValue CXFA_Stroke::GetStrokeType() {
   return JSObject()->GetEnum(XFA_Attribute::Stroke);
 }
 
@@ -134,7 +132,7 @@
                               false);
 }
 
-XFA_AttributeEnum CXFA_Stroke::GetJoinType() {
+XFA_AttributeValue CXFA_Stroke::GetJoinType() {
   return JSObject()->GetEnum(XFA_Attribute::Join);
 }
 
@@ -186,7 +184,7 @@
   pGS->SetLineWidth(fThickness);
   pGS->EnableActOnDash();
   pGS->SetLineCap(CFX_GraphStateData::LineCapButt);
-  XFA_StrokeTypeSetLineDash(pGS, GetStrokeType(), XFA_AttributeEnum::Butt);
+  XFA_StrokeTypeSetLineDash(pGS, GetStrokeType(), XFA_AttributeValue::Butt);
   pGS->SetStrokeColor(CXFA_GEColor(GetColor()));
   pGS->StrokePath(pPath, &matrix);
   pGS->RestoreGraphState();
diff --git a/xfa/fxfa/parser/cxfa_stroke.h b/xfa/fxfa/parser/cxfa_stroke.h
index ed41997..c87bc50 100644
--- a/xfa/fxfa/parser/cxfa_stroke.h
+++ b/xfa/fxfa/parser/cxfa_stroke.h
@@ -23,8 +23,8 @@
 class CXFA_Node;
 
 void XFA_StrokeTypeSetLineDash(CXFA_Graphics* pGraphics,
-                               XFA_AttributeEnum iStrokeType,
-                               XFA_AttributeEnum iCapType);
+                               XFA_AttributeValue iStrokeType,
+                               XFA_AttributeValue iCapType);
 
 class CXFA_Stroke : public CXFA_Node {
  public:
@@ -34,9 +34,9 @@
   bool IsVisible();
   bool IsInverted();
 
-  XFA_AttributeEnum GetCapType();
-  XFA_AttributeEnum GetStrokeType();
-  XFA_AttributeEnum GetJoinType();
+  XFA_AttributeValue GetCapType();
+  XFA_AttributeValue GetStrokeType();
+  XFA_AttributeValue GetJoinType();
   float GetRadius() const;
   float GetThickness() const;
 
@@ -56,9 +56,8 @@
               uint32_t validPackets,
               XFA_ObjectType oType,
               XFA_Element eType,
-              const PropertyData* properties,
-              const AttributeData* attributes,
-              const WideStringView& elementName,
+              pdfium::span<const PropertyData> properties,
+              pdfium::span<const AttributeData> attributes,
               std::unique_ptr<CJX_Object> js_node);
 };
 
diff --git a/xfa/fxfa/parser/cxfa_subform.cpp b/xfa/fxfa/parser/cxfa_subform.cpp
index 7bb7fa7..37d99ec 100644
--- a/xfa/fxfa/parser/cxfa_subform.cpp
+++ b/xfa/fxfa/parser/cxfa_subform.cpp
@@ -11,7 +11,7 @@
 
 namespace {
 
-const CXFA_Node::PropertyData kPropertyData[] = {
+const CXFA_Node::PropertyData kSubformPropertyData[] = {
     {XFA_Element::Break, 1, 0},   {XFA_Element::Margin, 1, 0},
     {XFA_Element::Para, 1, 0},    {XFA_Element::Border, 1, 0},
     {XFA_Element::Assist, 1, 0},  {XFA_Element::Traversal, 1, 0},
@@ -20,46 +20,46 @@
     {XFA_Element::Bind, 1, 0},    {XFA_Element::Desc, 1, 0},
     {XFA_Element::Bookend, 1, 0}, {XFA_Element::Calculate, 1, 0},
     {XFA_Element::Extras, 1, 0},  {XFA_Element::Variables, 1, 0},
-    {XFA_Element::Occur, 1, 0},   {XFA_Element::Unknown, 0, 0}};
-const CXFA_Node::AttributeData kAttributeData[] = {
+    {XFA_Element::Occur, 1, 0},
+};
+
+const CXFA_Node::AttributeData kSubformAttributeData[] = {
     {XFA_Attribute::H, XFA_AttributeType::Measure, (void*)L"0in"},
     {XFA_Attribute::W, XFA_AttributeType::Measure, (void*)L"0in"},
     {XFA_Attribute::X, XFA_AttributeType::Measure, (void*)L"0in"},
     {XFA_Attribute::Y, XFA_AttributeType::Measure, (void*)L"0in"},
     {XFA_Attribute::Id, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::HAlign, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::Left},
+     (void*)XFA_AttributeValue::Left},
     {XFA_Attribute::Name, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Use, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::AllowMacro, XFA_AttributeType::Boolean, (void*)0},
     {XFA_Attribute::ColumnWidths, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Access, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::Open},
+     (void*)XFA_AttributeValue::Open},
     {XFA_Attribute::Presence, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::Visible},
+     (void*)XFA_AttributeValue::Visible},
     {XFA_Attribute::VAlign, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::Top},
+     (void*)XFA_AttributeValue::Top},
     {XFA_Attribute::MaxH, XFA_AttributeType::Measure, (void*)L"0in"},
     {XFA_Attribute::MaxW, XFA_AttributeType::Measure, (void*)L"0in"},
     {XFA_Attribute::MinH, XFA_AttributeType::Measure, (void*)L"0in"},
     {XFA_Attribute::MinW, XFA_AttributeType::Measure, (void*)L"0in"},
     {XFA_Attribute::Layout, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::Position},
+     (void*)XFA_AttributeValue::Position},
     {XFA_Attribute::Relevant, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::MergeMode, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::ConsumeData},
+     (void*)XFA_AttributeValue::ConsumeData},
     {XFA_Attribute::ColSpan, XFA_AttributeType::Integer, (void*)1},
     {XFA_Attribute::Usehref, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Locale, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::AnchorType, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::TopLeft},
+     (void*)XFA_AttributeValue::TopLeft},
     {XFA_Attribute::RestoreState, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::Manual},
+     (void*)XFA_AttributeValue::Manual},
     {XFA_Attribute::Scope, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::Name},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"subform";
+     (void*)XFA_AttributeValue::Name},
+};
 
 }  // namespace
 
@@ -69,9 +69,8 @@
                 (XFA_XDPPACKET_Template | XFA_XDPPACKET_Form),
                 XFA_ObjectType::ContainerNode,
                 XFA_Element::Subform,
-                kPropertyData,
-                kAttributeData,
-                kName,
+                kSubformPropertyData,
+                kSubformAttributeData,
                 pdfium::MakeUnique<CJX_Subform>(this)) {}
 
-CXFA_Subform::~CXFA_Subform() {}
+CXFA_Subform::~CXFA_Subform() = default;
diff --git a/xfa/fxfa/parser/cxfa_subform.h b/xfa/fxfa/parser/cxfa_subform.h
index 00b2e17..3d16d10 100644
--- a/xfa/fxfa/parser/cxfa_subform.h
+++ b/xfa/fxfa/parser/cxfa_subform.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Subform : public CXFA_Node {
+class CXFA_Subform final : public CXFA_Node {
  public:
   CXFA_Subform(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Subform() override;
diff --git a/xfa/fxfa/parser/cxfa_subformset.cpp b/xfa/fxfa/parser/cxfa_subformset.cpp
index 0c9c3b0..d1f6ba5 100644
--- a/xfa/fxfa/parser/cxfa_subformset.cpp
+++ b/xfa/fxfa/parser/cxfa_subformset.cpp
@@ -6,27 +6,26 @@
 
 #include "xfa/fxfa/parser/cxfa_subformset.h"
 
-#include "fxjs/xfa/cjx_subformset.h"
+#include "fxjs/xfa/cjx_container.h"
 #include "third_party/base/ptr_util.h"
 
 namespace {
 
-const CXFA_Node::PropertyData kPropertyData[] = {
+const CXFA_Node::PropertyData kSubformSetPropertyData[] = {
     {XFA_Element::Break, 1, 0},  {XFA_Element::Overflow, 1, 0},
     {XFA_Element::Desc, 1, 0},   {XFA_Element::Bookend, 1, 0},
     {XFA_Element::Extras, 1, 0}, {XFA_Element::Occur, 1, 0},
-    {XFA_Element::Unknown, 0, 0}};
-const CXFA_Node::AttributeData kAttributeData[] = {
+};
+
+const CXFA_Node::AttributeData kSubformSetAttributeData[] = {
     {XFA_Attribute::Id, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Name, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Use, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Relation, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::Ordered},
+     (void*)XFA_AttributeValue::Ordered},
     {XFA_Attribute::Relevant, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Usehref, XFA_AttributeType::CData, nullptr},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"subformSet";
+};
 
 }  // namespace
 
@@ -36,9 +35,8 @@
                 (XFA_XDPPACKET_Template | XFA_XDPPACKET_Form),
                 XFA_ObjectType::ContainerNode,
                 XFA_Element::SubformSet,
-                kPropertyData,
-                kAttributeData,
-                kName,
-                pdfium::MakeUnique<CJX_SubformSet>(this)) {}
+                kSubformSetPropertyData,
+                kSubformSetAttributeData,
+                pdfium::MakeUnique<CJX_Container>(this)) {}
 
-CXFA_SubformSet::~CXFA_SubformSet() {}
+CXFA_SubformSet::~CXFA_SubformSet() = default;
diff --git a/xfa/fxfa/parser/cxfa_subformset.h b/xfa/fxfa/parser/cxfa_subformset.h
index 8e0f3ea..12b9e9f 100644
--- a/xfa/fxfa/parser/cxfa_subformset.h
+++ b/xfa/fxfa/parser/cxfa_subformset.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_SubformSet : public CXFA_Node {
+class CXFA_SubformSet final : public CXFA_Node {
  public:
   CXFA_SubformSet(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_SubformSet() override;
diff --git a/xfa/fxfa/parser/cxfa_subjectdn.cpp b/xfa/fxfa/parser/cxfa_subjectdn.cpp
index 29ab2fa..1130739 100644
--- a/xfa/fxfa/parser/cxfa_subjectdn.cpp
+++ b/xfa/fxfa/parser/cxfa_subjectdn.cpp
@@ -6,20 +6,18 @@
 
 #include "xfa/fxfa/parser/cxfa_subjectdn.h"
 
-#include "fxjs/xfa/cjx_subjectdn.h"
+#include "fxjs/xfa/cjx_node.h"
 #include "third_party/base/ptr_util.h"
 
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kSubjectDNAttributeData[] = {
     {XFA_Attribute::Id, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Name, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Use, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Delimiter, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Usehref, XFA_AttributeType::CData, nullptr},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"subjectDN";
+};
 
 }  // namespace
 
@@ -29,9 +27,8 @@
                 (XFA_XDPPACKET_Template | XFA_XDPPACKET_Form),
                 XFA_ObjectType::NodeC,
                 XFA_Element::SubjectDN,
-                nullptr,
-                kAttributeData,
-                kName,
-                pdfium::MakeUnique<CJX_SubjectDN>(this)) {}
+                {},
+                kSubjectDNAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_SubjectDN::~CXFA_SubjectDN() {}
+CXFA_SubjectDN::~CXFA_SubjectDN() = default;
diff --git a/xfa/fxfa/parser/cxfa_subjectdn.h b/xfa/fxfa/parser/cxfa_subjectdn.h
index 0861d75..a4d94d7 100644
--- a/xfa/fxfa/parser/cxfa_subjectdn.h
+++ b/xfa/fxfa/parser/cxfa_subjectdn.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_SubjectDN : public CXFA_Node {
+class CXFA_SubjectDN final : public CXFA_Node {
  public:
   CXFA_SubjectDN(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_SubjectDN() override;
diff --git a/xfa/fxfa/parser/cxfa_subjectdns.cpp b/xfa/fxfa/parser/cxfa_subjectdns.cpp
index 8f714b0..524bc96 100644
--- a/xfa/fxfa/parser/cxfa_subjectdns.cpp
+++ b/xfa/fxfa/parser/cxfa_subjectdns.cpp
@@ -6,20 +6,18 @@
 
 #include "xfa/fxfa/parser/cxfa_subjectdns.h"
 
-#include "fxjs/xfa/cjx_subjectdns.h"
+#include "fxjs/xfa/cjx_node.h"
 #include "third_party/base/ptr_util.h"
 
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kSubjectDNsAttributeData[] = {
     {XFA_Attribute::Id, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Use, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Type, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::Optional},
+     (void*)XFA_AttributeValue::Optional},
     {XFA_Attribute::Usehref, XFA_AttributeType::CData, nullptr},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"subjectDNs";
+};
 
 }  // namespace
 
@@ -29,9 +27,8 @@
                 (XFA_XDPPACKET_Template | XFA_XDPPACKET_Form),
                 XFA_ObjectType::Node,
                 XFA_Element::SubjectDNs,
-                nullptr,
-                kAttributeData,
-                kName,
-                pdfium::MakeUnique<CJX_SubjectDNs>(this)) {}
+                {},
+                kSubjectDNsAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_SubjectDNs::~CXFA_SubjectDNs() {}
+CXFA_SubjectDNs::~CXFA_SubjectDNs() = default;
diff --git a/xfa/fxfa/parser/cxfa_subjectdns.h b/xfa/fxfa/parser/cxfa_subjectdns.h
index e9d739c..03d770b 100644
--- a/xfa/fxfa/parser/cxfa_subjectdns.h
+++ b/xfa/fxfa/parser/cxfa_subjectdns.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_SubjectDNs : public CXFA_Node {
+class CXFA_SubjectDNs final : public CXFA_Node {
  public:
   CXFA_SubjectDNs(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_SubjectDNs() override;
diff --git a/xfa/fxfa/parser/cxfa_submit.cpp b/xfa/fxfa/parser/cxfa_submit.cpp
index e4558e8..82eed83 100644
--- a/xfa/fxfa/parser/cxfa_submit.cpp
+++ b/xfa/fxfa/parser/cxfa_submit.cpp
@@ -6,26 +6,26 @@
 
 #include "xfa/fxfa/parser/cxfa_submit.h"
 
-#include "fxjs/xfa/cjx_submit.h"
+#include "fxjs/xfa/cjx_node.h"
 #include "third_party/base/ptr_util.h"
 
 namespace {
 
-const CXFA_Node::PropertyData kPropertyData[] = {{XFA_Element::Encrypt, 1, 0},
-                                                 {XFA_Element::Unknown, 0, 0}};
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::PropertyData kSubmitPropertyData[] = {
+    {XFA_Element::Encrypt, 1, 0},
+};
+
+const CXFA_Node::AttributeData kSubmitAttributeData[] = {
     {XFA_Attribute::Id, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Use, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Format, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::Xdp},
+     (void*)XFA_AttributeValue::Xdp},
     {XFA_Attribute::EmbedPDF, XFA_AttributeType::Boolean, (void*)0},
     {XFA_Attribute::Usehref, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Target, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::TextEncoding, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::XdpContent, XFA_AttributeType::CData, nullptr},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"submit";
+};
 
 }  // namespace
 
@@ -35,18 +35,17 @@
                 (XFA_XDPPACKET_Template | XFA_XDPPACKET_Form),
                 XFA_ObjectType::Node,
                 XFA_Element::Submit,
-                kPropertyData,
-                kAttributeData,
-                kName,
-                pdfium::MakeUnique<CJX_Submit>(this)) {}
+                kSubmitPropertyData,
+                kSubmitAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_Submit::~CXFA_Submit() {}
+CXFA_Submit::~CXFA_Submit() = default;
 
 bool CXFA_Submit::IsSubmitEmbedPDF() {
   return JSObject()->GetBoolean(XFA_Attribute::EmbedPDF);
 }
 
-XFA_AttributeEnum CXFA_Submit::GetSubmitFormat() {
+XFA_AttributeValue CXFA_Submit::GetSubmitFormat() {
   return JSObject()->GetEnum(XFA_Attribute::Format);
 }
 
diff --git a/xfa/fxfa/parser/cxfa_submit.h b/xfa/fxfa/parser/cxfa_submit.h
index 24d5f11..13cad86 100644
--- a/xfa/fxfa/parser/cxfa_submit.h
+++ b/xfa/fxfa/parser/cxfa_submit.h
@@ -10,13 +10,13 @@
 #include "core/fxcrt/widestring.h"
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Submit : public CXFA_Node {
+class CXFA_Submit final : public CXFA_Node {
  public:
   CXFA_Submit(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Submit() override;
 
   bool IsSubmitEmbedPDF();
-  XFA_AttributeEnum GetSubmitFormat();
+  XFA_AttributeValue GetSubmitFormat();
   WideString GetSubmitTarget();
   WideString GetSubmitXDPContent();
 };
diff --git a/xfa/fxfa/parser/cxfa_submitformat.cpp b/xfa/fxfa/parser/cxfa_submitformat.cpp
index 30daf89..551b92b 100644
--- a/xfa/fxfa/parser/cxfa_submitformat.cpp
+++ b/xfa/fxfa/parser/cxfa_submitformat.cpp
@@ -6,14 +6,15 @@
 
 #include "xfa/fxfa/parser/cxfa_submitformat.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kSubmitFormatAttributeData[] = {
     {XFA_Attribute::Desc, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Lock, XFA_AttributeType::Integer, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"submitFormat";
+};
 
 }  // namespace
 
@@ -23,8 +24,8 @@
                 XFA_XDPPACKET_Config,
                 XFA_ObjectType::ContentNode,
                 XFA_Element::SubmitFormat,
-                nullptr,
-                kAttributeData,
-                kName) {}
+                {},
+                kSubmitFormatAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_SubmitFormat::~CXFA_SubmitFormat() {}
+CXFA_SubmitFormat::~CXFA_SubmitFormat() = default;
diff --git a/xfa/fxfa/parser/cxfa_submitformat.h b/xfa/fxfa/parser/cxfa_submitformat.h
index adca1e9..bd6df26 100644
--- a/xfa/fxfa/parser/cxfa_submitformat.h
+++ b/xfa/fxfa/parser/cxfa_submitformat.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_SubmitFormat : public CXFA_Node {
+class CXFA_SubmitFormat final : public CXFA_Node {
  public:
   CXFA_SubmitFormat(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_SubmitFormat() override;
diff --git a/xfa/fxfa/parser/cxfa_submiturl.cpp b/xfa/fxfa/parser/cxfa_submiturl.cpp
index 591dd99..3212acb 100644
--- a/xfa/fxfa/parser/cxfa_submiturl.cpp
+++ b/xfa/fxfa/parser/cxfa_submiturl.cpp
@@ -6,14 +6,15 @@
 
 #include "xfa/fxfa/parser/cxfa_submiturl.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kSubmitUrlAttributeData[] = {
     {XFA_Attribute::Desc, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Lock, XFA_AttributeType::Integer, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"submitUrl";
+};
 
 }  // namespace
 
@@ -23,8 +24,8 @@
                 XFA_XDPPACKET_Config,
                 XFA_ObjectType::ContentNode,
                 XFA_Element::SubmitUrl,
-                nullptr,
-                kAttributeData,
-                kName) {}
+                {},
+                kSubmitUrlAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_SubmitUrl::~CXFA_SubmitUrl() {}
+CXFA_SubmitUrl::~CXFA_SubmitUrl() = default;
diff --git a/xfa/fxfa/parser/cxfa_submiturl.h b/xfa/fxfa/parser/cxfa_submiturl.h
index 8d87db9..f1914db 100644
--- a/xfa/fxfa/parser/cxfa_submiturl.h
+++ b/xfa/fxfa/parser/cxfa_submiturl.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_SubmitUrl : public CXFA_Node {
+class CXFA_SubmitUrl final : public CXFA_Node {
  public:
   CXFA_SubmitUrl(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_SubmitUrl() override;
diff --git a/xfa/fxfa/parser/cxfa_subsetbelow.cpp b/xfa/fxfa/parser/cxfa_subsetbelow.cpp
index 90dbd06..ed179c9 100644
--- a/xfa/fxfa/parser/cxfa_subsetbelow.cpp
+++ b/xfa/fxfa/parser/cxfa_subsetbelow.cpp
@@ -6,14 +6,15 @@
 
 #include "xfa/fxfa/parser/cxfa_subsetbelow.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kSubsetBelowAttributeData[] = {
     {XFA_Attribute::Desc, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Lock, XFA_AttributeType::Integer, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"subsetBelow";
+};
 
 }  // namespace
 
@@ -23,8 +24,8 @@
                 XFA_XDPPACKET_Config,
                 XFA_ObjectType::ContentNode,
                 XFA_Element::SubsetBelow,
-                nullptr,
-                kAttributeData,
-                kName) {}
+                {},
+                kSubsetBelowAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_SubsetBelow::~CXFA_SubsetBelow() {}
+CXFA_SubsetBelow::~CXFA_SubsetBelow() = default;
diff --git a/xfa/fxfa/parser/cxfa_subsetbelow.h b/xfa/fxfa/parser/cxfa_subsetbelow.h
index db912fe..230a563 100644
--- a/xfa/fxfa/parser/cxfa_subsetbelow.h
+++ b/xfa/fxfa/parser/cxfa_subsetbelow.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_SubsetBelow : public CXFA_Node {
+class CXFA_SubsetBelow final : public CXFA_Node {
  public:
   CXFA_SubsetBelow(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_SubsetBelow() override;
diff --git a/xfa/fxfa/parser/cxfa_suppressbanner.cpp b/xfa/fxfa/parser/cxfa_suppressbanner.cpp
index 46c42a5..3371170 100644
--- a/xfa/fxfa/parser/cxfa_suppressbanner.cpp
+++ b/xfa/fxfa/parser/cxfa_suppressbanner.cpp
@@ -6,14 +6,15 @@
 
 #include "xfa/fxfa/parser/cxfa_suppressbanner.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kSuppressBannerAttributeData[] = {
     {XFA_Attribute::Desc, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Lock, XFA_AttributeType::Integer, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"suppressBanner";
+};
 
 }  // namespace
 
@@ -24,8 +25,8 @@
                 XFA_XDPPACKET_Config,
                 XFA_ObjectType::ContentNode,
                 XFA_Element::SuppressBanner,
-                nullptr,
-                kAttributeData,
-                kName) {}
+                {},
+                kSuppressBannerAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_SuppressBanner::~CXFA_SuppressBanner() {}
+CXFA_SuppressBanner::~CXFA_SuppressBanner() = default;
diff --git a/xfa/fxfa/parser/cxfa_suppressbanner.h b/xfa/fxfa/parser/cxfa_suppressbanner.h
index 79013a2..40057d0 100644
--- a/xfa/fxfa/parser/cxfa_suppressbanner.h
+++ b/xfa/fxfa/parser/cxfa_suppressbanner.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_SuppressBanner : public CXFA_Node {
+class CXFA_SuppressBanner final : public CXFA_Node {
  public:
   CXFA_SuppressBanner(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_SuppressBanner() override;
diff --git a/xfa/fxfa/parser/cxfa_tagged.cpp b/xfa/fxfa/parser/cxfa_tagged.cpp
index 0f46b62..940b12c 100644
--- a/xfa/fxfa/parser/cxfa_tagged.cpp
+++ b/xfa/fxfa/parser/cxfa_tagged.cpp
@@ -6,14 +6,15 @@
 
 #include "xfa/fxfa/parser/cxfa_tagged.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kTaggedAttributeData[] = {
     {XFA_Attribute::Desc, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Lock, XFA_AttributeType::Integer, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"tagged";
+};
 
 }  // namespace
 
@@ -23,8 +24,8 @@
                 XFA_XDPPACKET_Config,
                 XFA_ObjectType::ContentNode,
                 XFA_Element::Tagged,
-                nullptr,
-                kAttributeData,
-                kName) {}
+                {},
+                kTaggedAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_Tagged::~CXFA_Tagged() {}
+CXFA_Tagged::~CXFA_Tagged() = default;
diff --git a/xfa/fxfa/parser/cxfa_tagged.h b/xfa/fxfa/parser/cxfa_tagged.h
index 50b1ba4..ff54423 100644
--- a/xfa/fxfa/parser/cxfa_tagged.h
+++ b/xfa/fxfa/parser/cxfa_tagged.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Tagged : public CXFA_Node {
+class CXFA_Tagged final : public CXFA_Node {
  public:
   CXFA_Tagged(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Tagged() override;
diff --git a/xfa/fxfa/parser/cxfa_template.cpp b/xfa/fxfa/parser/cxfa_template.cpp
index 3f9afa1..bc5c444 100644
--- a/xfa/fxfa/parser/cxfa_template.cpp
+++ b/xfa/fxfa/parser/cxfa_template.cpp
@@ -11,19 +11,18 @@
 
 namespace {
 
-const CXFA_Node::PropertyData kPropertyData[] = {
+const CXFA_Node::PropertyData kTemplatePropertyData[] = {
     {XFA_Element::Uri, 1, 0},       {XFA_Element::Xsl, 1, 0},
     {XFA_Element::StartPage, 1, 0}, {XFA_Element::Relevant, 1, 0},
     {XFA_Element::Base, 1, 0},      {XFA_Element::Extras, 1, 0},
-    {XFA_Element::Unknown, 0, 0}};
-const CXFA_Node::AttributeData kAttributeData[] = {
+};
+
+const CXFA_Node::AttributeData kTemplateAttributeData[] = {
     {XFA_Attribute::Desc, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::BaseProfile, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::Full},
+     (void*)XFA_AttributeValue::Full},
     {XFA_Attribute::Lock, XFA_AttributeType::Integer, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"template";
+};
 
 }  // namespace
 
@@ -34,9 +33,8 @@
           (XFA_XDPPACKET_Config | XFA_XDPPACKET_Template | XFA_XDPPACKET_Form),
           XFA_ObjectType::ModelNode,
           XFA_Element::Template,
-          kPropertyData,
-          kAttributeData,
-          kName,
+          kTemplatePropertyData,
+          kTemplateAttributeData,
           pdfium::MakeUnique<CJX_Template>(this)) {}
 
-CXFA_Template::~CXFA_Template() {}
+CXFA_Template::~CXFA_Template() = default;
diff --git a/xfa/fxfa/parser/cxfa_template.h b/xfa/fxfa/parser/cxfa_template.h
index 34b035f..fa9b999 100644
--- a/xfa/fxfa/parser/cxfa_template.h
+++ b/xfa/fxfa/parser/cxfa_template.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Template : public CXFA_Node {
+class CXFA_Template final : public CXFA_Node {
  public:
   CXFA_Template(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Template() override;
diff --git a/xfa/fxfa/parser/cxfa_templatecache.cpp b/xfa/fxfa/parser/cxfa_templatecache.cpp
index e22ed65..bfc19b3 100644
--- a/xfa/fxfa/parser/cxfa_templatecache.cpp
+++ b/xfa/fxfa/parser/cxfa_templatecache.cpp
@@ -6,15 +6,16 @@
 
 #include "xfa/fxfa/parser/cxfa_templatecache.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kTemplateCacheAttributeData[] = {
     {XFA_Attribute::Desc, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::MaxEntries, XFA_AttributeType::Integer, (void*)5},
     {XFA_Attribute::Lock, XFA_AttributeType::Integer, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"templateCache";
+};
 
 }  // namespace
 
@@ -25,8 +26,8 @@
                 XFA_XDPPACKET_Config,
                 XFA_ObjectType::Node,
                 XFA_Element::TemplateCache,
-                nullptr,
-                kAttributeData,
-                kName) {}
+                {},
+                kTemplateCacheAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_TemplateCache::~CXFA_TemplateCache() {}
+CXFA_TemplateCache::~CXFA_TemplateCache() = default;
diff --git a/xfa/fxfa/parser/cxfa_templatecache.h b/xfa/fxfa/parser/cxfa_templatecache.h
index 45953fe..dd0136d 100644
--- a/xfa/fxfa/parser/cxfa_templatecache.h
+++ b/xfa/fxfa/parser/cxfa_templatecache.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_TemplateCache : public CXFA_Node {
+class CXFA_TemplateCache final : public CXFA_Node {
  public:
   CXFA_TemplateCache(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_TemplateCache() override;
diff --git a/xfa/fxfa/parser/cxfa_text.cpp b/xfa/fxfa/parser/cxfa_text.cpp
index e000493..bb921a0 100644
--- a/xfa/fxfa/parser/cxfa_text.cpp
+++ b/xfa/fxfa/parser/cxfa_text.cpp
@@ -6,21 +6,19 @@
 
 #include "xfa/fxfa/parser/cxfa_text.h"
 
-#include "fxjs/xfa/cjx_text.h"
+#include "fxjs/xfa/cjx_object.h"
 #include "third_party/base/ptr_util.h"
 
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kTextAttributeData[] = {
     {XFA_Attribute::Id, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Name, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Rid, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Use, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::MaxChars, XFA_AttributeType::Integer, (void*)0},
     {XFA_Attribute::Usehref, XFA_AttributeType::CData, nullptr},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"text";
+};
 
 }  // namespace
 
@@ -31,12 +29,11 @@
                  XFA_XDPPACKET_Form),
                 XFA_ObjectType::ContentNode,
                 XFA_Element::Text,
-                nullptr,
-                kAttributeData,
-                kName,
-                pdfium::MakeUnique<CJX_Text>(this)) {}
+                {},
+                kTextAttributeData,
+                pdfium::MakeUnique<CJX_Object>(this)) {}
 
-CXFA_Text::~CXFA_Text() {}
+CXFA_Text::~CXFA_Text() = default;
 
 WideString CXFA_Text::GetContent() {
   return JSObject()->GetContent(false);
diff --git a/xfa/fxfa/parser/cxfa_text.h b/xfa/fxfa/parser/cxfa_text.h
index a75aef2..811ce1a 100644
--- a/xfa/fxfa/parser/cxfa_text.h
+++ b/xfa/fxfa/parser/cxfa_text.h
@@ -10,7 +10,7 @@
 #include "core/fxcrt/fx_string.h"
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Text : public CXFA_Node {
+class CXFA_Text final : public CXFA_Node {
  public:
   CXFA_Text(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Text() override;
diff --git a/xfa/fxfa/parser/cxfa_textedit.cpp b/xfa/fxfa/parser/cxfa_textedit.cpp
index 3b2767a..7ff47c7 100644
--- a/xfa/fxfa/parser/cxfa_textedit.cpp
+++ b/xfa/fxfa/parser/cxfa_textedit.cpp
@@ -6,29 +6,29 @@
 
 #include "xfa/fxfa/parser/cxfa_textedit.h"
 
-#include "fxjs/xfa/cjx_textedit.h"
+#include "fxjs/xfa/cjx_node.h"
 #include "third_party/base/ptr_util.h"
 
 namespace {
 
-const CXFA_Node::PropertyData kPropertyData[] = {{XFA_Element::Margin, 1, 0},
-                                                 {XFA_Element::Border, 1, 0},
-                                                 {XFA_Element::Comb, 1, 0},
-                                                 {XFA_Element::Extras, 1, 0},
-                                                 {XFA_Element::Unknown, 0, 0}};
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::PropertyData kTextEditPropertyData[] = {
+    {XFA_Element::Margin, 1, 0},
+    {XFA_Element::Border, 1, 0},
+    {XFA_Element::Comb, 1, 0},
+    {XFA_Element::Extras, 1, 0},
+};
+
+const CXFA_Node::AttributeData kTextEditAttributeData[] = {
     {XFA_Attribute::Id, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::VScrollPolicy, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::Auto},
+     (void*)XFA_AttributeValue::Auto},
     {XFA_Attribute::Use, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::AllowRichText, XFA_AttributeType::Boolean, (void*)0},
     {XFA_Attribute::MultiLine, XFA_AttributeType::Boolean, (void*)0},
     {XFA_Attribute::Usehref, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::HScrollPolicy, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::Auto},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"textEdit";
+     (void*)XFA_AttributeValue::Auto},
+};
 
 }  // namespace
 
@@ -38,9 +38,12 @@
                 (XFA_XDPPACKET_Template | XFA_XDPPACKET_Form),
                 XFA_ObjectType::Node,
                 XFA_Element::TextEdit,
-                kPropertyData,
-                kAttributeData,
-                kName,
-                pdfium::MakeUnique<CJX_TextEdit>(this)) {}
+                kTextEditPropertyData,
+                kTextEditAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_TextEdit::~CXFA_TextEdit() {}
+CXFA_TextEdit::~CXFA_TextEdit() = default;
+
+XFA_FFWidgetType CXFA_TextEdit::GetDefaultFFWidgetType() const {
+  return XFA_FFWidgetType::kTextEdit;
+}
diff --git a/xfa/fxfa/parser/cxfa_textedit.h b/xfa/fxfa/parser/cxfa_textedit.h
index 972ede4..d4cafa4 100644
--- a/xfa/fxfa/parser/cxfa_textedit.h
+++ b/xfa/fxfa/parser/cxfa_textedit.h
@@ -9,10 +9,12 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_TextEdit : public CXFA_Node {
+class CXFA_TextEdit final : public CXFA_Node {
  public:
   CXFA_TextEdit(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_TextEdit() override;
+
+  XFA_FFWidgetType GetDefaultFFWidgetType() const override;
 };
 
 #endif  // XFA_FXFA_PARSER_CXFA_TEXTEDIT_H_
diff --git a/xfa/fxfa/parser/cxfa_thisproxy.cpp b/xfa/fxfa/parser/cxfa_thisproxy.cpp
index 314c98c..3654409 100644
--- a/xfa/fxfa/parser/cxfa_thisproxy.cpp
+++ b/xfa/fxfa/parser/cxfa_thisproxy.cpp
@@ -12,11 +12,10 @@
 
 CXFA_ThisProxy::CXFA_ThisProxy(CXFA_Node* pThisNode, CXFA_Node* pScriptNode)
     : CXFA_Object(pThisNode->GetDocument(),
-                  XFA_ObjectType::VariablesThis,
-                  XFA_Element::Unknown,
-                  WideStringView(),
+                  XFA_ObjectType::ThisProxy,
+                  XFA_Element::Object,
                   pdfium::MakeUnique<CJX_Object>(this)),
       m_pThisNode(pThisNode),
       m_pScriptNode(pScriptNode) {}
 
-CXFA_ThisProxy::~CXFA_ThisProxy() {}
+CXFA_ThisProxy::~CXFA_ThisProxy() = default;
diff --git a/xfa/fxfa/parser/cxfa_thisproxy.h b/xfa/fxfa/parser/cxfa_thisproxy.h
index 4bb0f5a..4ec6e4a 100644
--- a/xfa/fxfa/parser/cxfa_thisproxy.h
+++ b/xfa/fxfa/parser/cxfa_thisproxy.h
@@ -7,21 +7,22 @@
 #ifndef XFA_FXFA_PARSER_CXFA_THISPROXY_H_
 #define XFA_FXFA_PARSER_CXFA_THISPROXY_H_
 
+#include "core/fxcrt/unowned_ptr.h"
 #include "xfa/fxfa/parser/cxfa_object.h"
 
 class CXFA_Node;
 
-class CXFA_ThisProxy : public CXFA_Object {
+class CXFA_ThisProxy final : public CXFA_Object {
  public:
   CXFA_ThisProxy(CXFA_Node* pThisNode, CXFA_Node* pScriptNode);
   ~CXFA_ThisProxy() override;
 
-  CXFA_Node* GetThisNode() const { return m_pThisNode; }
-  CXFA_Node* GetScriptNode() const { return m_pScriptNode; }
+  CXFA_Node* GetThisNode() const { return m_pThisNode.Get(); }
+  CXFA_Node* GetScriptNode() const { return m_pScriptNode.Get(); }
 
  private:
-  CXFA_Node* m_pThisNode;
-  CXFA_Node* m_pScriptNode;
+  UnownedPtr<CXFA_Node> m_pThisNode;
+  UnownedPtr<CXFA_Node> m_pScriptNode;
 };
 
 #endif  // XFA_FXFA_PARSER_CXFA_THISPROXY_H_
diff --git a/xfa/fxfa/parser/cxfa_threshold.cpp b/xfa/fxfa/parser/cxfa_threshold.cpp
index 2047d52..3d1863a 100644
--- a/xfa/fxfa/parser/cxfa_threshold.cpp
+++ b/xfa/fxfa/parser/cxfa_threshold.cpp
@@ -6,14 +6,15 @@
 
 #include "xfa/fxfa/parser/cxfa_threshold.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kThresholdAttributeData[] = {
     {XFA_Attribute::Desc, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Lock, XFA_AttributeType::Integer, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"threshold";
+};
 
 }  // namespace
 
@@ -23,8 +24,8 @@
                 XFA_XDPPACKET_Config,
                 XFA_ObjectType::NodeV,
                 XFA_Element::Threshold,
-                nullptr,
-                kAttributeData,
-                kName) {}
+                {},
+                kThresholdAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_Threshold::~CXFA_Threshold() {}
+CXFA_Threshold::~CXFA_Threshold() = default;
diff --git a/xfa/fxfa/parser/cxfa_threshold.h b/xfa/fxfa/parser/cxfa_threshold.h
index 4bde01a..597b134 100644
--- a/xfa/fxfa/parser/cxfa_threshold.h
+++ b/xfa/fxfa/parser/cxfa_threshold.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Threshold : public CXFA_Node {
+class CXFA_Threshold final : public CXFA_Node {
  public:
   CXFA_Threshold(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Threshold() override;
diff --git a/xfa/fxfa/parser/cxfa_time.cpp b/xfa/fxfa/parser/cxfa_time.cpp
index f3a64ce..ea33713 100644
--- a/xfa/fxfa/parser/cxfa_time.cpp
+++ b/xfa/fxfa/parser/cxfa_time.cpp
@@ -6,19 +6,17 @@
 
 #include "xfa/fxfa/parser/cxfa_time.h"
 
-#include "fxjs/xfa/cjx_time.h"
+#include "fxjs/xfa/cjx_object.h"
 #include "third_party/base/ptr_util.h"
 
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kTimeAttributeData[] = {
     {XFA_Attribute::Id, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Name, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Use, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Usehref, XFA_AttributeType::CData, nullptr},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"time";
+};
 
 }  // namespace
 
@@ -28,9 +26,8 @@
                 (XFA_XDPPACKET_Template | XFA_XDPPACKET_Form),
                 XFA_ObjectType::ContentNode,
                 XFA_Element::Time,
-                nullptr,
-                kAttributeData,
-                kName,
-                pdfium::MakeUnique<CJX_Time>(this)) {}
+                {},
+                kTimeAttributeData,
+                pdfium::MakeUnique<CJX_Object>(this)) {}
 
-CXFA_Time::~CXFA_Time() {}
+CXFA_Time::~CXFA_Time() = default;
diff --git a/xfa/fxfa/parser/cxfa_time.h b/xfa/fxfa/parser/cxfa_time.h
index efc6d02..c189bc5 100644
--- a/xfa/fxfa/parser/cxfa_time.h
+++ b/xfa/fxfa/parser/cxfa_time.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Time : public CXFA_Node {
+class CXFA_Time final : public CXFA_Node {
  public:
   CXFA_Time(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Time() override;
diff --git a/xfa/fxfa/parser/cxfa_timepattern.cpp b/xfa/fxfa/parser/cxfa_timepattern.cpp
index 76e3a53..9264da2 100644
--- a/xfa/fxfa/parser/cxfa_timepattern.cpp
+++ b/xfa/fxfa/parser/cxfa_timepattern.cpp
@@ -6,14 +6,15 @@
 
 #include "xfa/fxfa/parser/cxfa_timepattern.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kTimePatternAttributeData[] = {
     {XFA_Attribute::Name, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::Med},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"timePattern";
+     (void*)XFA_AttributeValue::Med},
+};
 
 }  // namespace
 
@@ -23,8 +24,8 @@
                 XFA_XDPPACKET_LocaleSet,
                 XFA_ObjectType::ContentNode,
                 XFA_Element::TimePattern,
-                nullptr,
-                kAttributeData,
-                kName) {}
+                {},
+                kTimePatternAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_TimePattern::~CXFA_TimePattern() {}
+CXFA_TimePattern::~CXFA_TimePattern() = default;
diff --git a/xfa/fxfa/parser/cxfa_timepattern.h b/xfa/fxfa/parser/cxfa_timepattern.h
index f796047..7c150a9 100644
--- a/xfa/fxfa/parser/cxfa_timepattern.h
+++ b/xfa/fxfa/parser/cxfa_timepattern.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_TimePattern : public CXFA_Node {
+class CXFA_TimePattern final : public CXFA_Node {
  public:
   CXFA_TimePattern(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_TimePattern() override;
diff --git a/xfa/fxfa/parser/cxfa_timepatterns.cpp b/xfa/fxfa/parser/cxfa_timepatterns.cpp
index c3a8dde..1c92303 100644
--- a/xfa/fxfa/parser/cxfa_timepatterns.cpp
+++ b/xfa/fxfa/parser/cxfa_timepatterns.cpp
@@ -6,13 +6,14 @@
 
 #include "xfa/fxfa/parser/cxfa_timepatterns.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::PropertyData kPropertyData[] = {
+const CXFA_Node::PropertyData kTimePatternsPropertyData[] = {
     {XFA_Element::TimePattern, 4, 0},
-    {XFA_Element::Unknown, 0, 0}};
-
-constexpr wchar_t kName[] = L"timePatterns";
+};
 
 }  // namespace
 
@@ -22,8 +23,8 @@
                 XFA_XDPPACKET_LocaleSet,
                 XFA_ObjectType::Node,
                 XFA_Element::TimePatterns,
-                kPropertyData,
-                nullptr,
-                kName) {}
+                kTimePatternsPropertyData,
+                {},
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_TimePatterns::~CXFA_TimePatterns() {}
+CXFA_TimePatterns::~CXFA_TimePatterns() = default;
diff --git a/xfa/fxfa/parser/cxfa_timepatterns.h b/xfa/fxfa/parser/cxfa_timepatterns.h
index be9337d..13c05c8 100644
--- a/xfa/fxfa/parser/cxfa_timepatterns.h
+++ b/xfa/fxfa/parser/cxfa_timepatterns.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_TimePatterns : public CXFA_Node {
+class CXFA_TimePatterns final : public CXFA_Node {
  public:
   CXFA_TimePatterns(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_TimePatterns() override;
diff --git a/xfa/fxfa/parser/cxfa_timestamp.cpp b/xfa/fxfa/parser/cxfa_timestamp.cpp
index 1c86961..68f1c50 100644
--- a/xfa/fxfa/parser/cxfa_timestamp.cpp
+++ b/xfa/fxfa/parser/cxfa_timestamp.cpp
@@ -6,21 +6,19 @@
 
 #include "xfa/fxfa/parser/cxfa_timestamp.h"
 
-#include "fxjs/xfa/cjx_timestamp.h"
+#include "fxjs/xfa/cjx_node.h"
 #include "third_party/base/ptr_util.h"
 
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kTimeStampAttributeData[] = {
     {XFA_Attribute::Id, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Use, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Type, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::Optional},
+     (void*)XFA_AttributeValue::Optional},
     {XFA_Attribute::Server, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Usehref, XFA_AttributeType::CData, nullptr},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"timeStamp";
+};
 
 }  // namespace
 
@@ -30,8 +28,8 @@
                 (XFA_XDPPACKET_Template | XFA_XDPPACKET_Form),
                 XFA_ObjectType::Node,
                 XFA_Element::TimeStamp,
-                nullptr,
-                kAttributeData,
-                kName) {}
+                {},
+                kTimeStampAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_TimeStamp::~CXFA_TimeStamp() {}
+CXFA_TimeStamp::~CXFA_TimeStamp() = default;
diff --git a/xfa/fxfa/parser/cxfa_timestamp.h b/xfa/fxfa/parser/cxfa_timestamp.h
index 7db73e9..6a6c1ac 100644
--- a/xfa/fxfa/parser/cxfa_timestamp.h
+++ b/xfa/fxfa/parser/cxfa_timestamp.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_TimeStamp : public CXFA_Node {
+class CXFA_TimeStamp final : public CXFA_Node {
  public:
   CXFA_TimeStamp(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_TimeStamp() override;
diff --git a/xfa/fxfa/parser/cxfa_timezoneprovider.cpp b/xfa/fxfa/parser/cxfa_timezoneprovider.cpp
index ff5ecce..0469563 100644
--- a/xfa/fxfa/parser/cxfa_timezoneprovider.cpp
+++ b/xfa/fxfa/parser/cxfa_timezoneprovider.cpp
@@ -8,10 +8,12 @@
 
 #include <time.h>
 
+#include "build/build_config.h"
+
 static bool g_bProviderTimeZoneSet = false;
 
 CXFA_TimeZoneProvider::CXFA_TimeZoneProvider() {
-#if _FX_PLATFORM_ == _FX_PLATFORM_WINDOWS_
+#if defined(OS_WIN)
   if (!g_bProviderTimeZoneSet) {
     g_bProviderTimeZoneSet = true;
     _tzset();
diff --git a/xfa/fxfa/parser/cxfa_to.cpp b/xfa/fxfa/parser/cxfa_to.cpp
index a30c015..cb400c0 100644
--- a/xfa/fxfa/parser/cxfa_to.cpp
+++ b/xfa/fxfa/parser/cxfa_to.cpp
@@ -6,14 +6,15 @@
 
 #include "xfa/fxfa/parser/cxfa_to.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kToAttributeData[] = {
     {XFA_Attribute::Desc, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Lock, XFA_AttributeType::Integer, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"to";
+};
 
 }  // namespace
 
@@ -23,8 +24,8 @@
                 XFA_XDPPACKET_Config,
                 XFA_ObjectType::ContentNode,
                 XFA_Element::To,
-                nullptr,
-                kAttributeData,
-                kName) {}
+                {},
+                kToAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_To::~CXFA_To() {}
+CXFA_To::~CXFA_To() = default;
diff --git a/xfa/fxfa/parser/cxfa_to.h b/xfa/fxfa/parser/cxfa_to.h
index f418f59..8510bc2 100644
--- a/xfa/fxfa/parser/cxfa_to.h
+++ b/xfa/fxfa/parser/cxfa_to.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_To : public CXFA_Node {
+class CXFA_To final : public CXFA_Node {
  public:
   CXFA_To(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_To() override;
diff --git a/xfa/fxfa/parser/cxfa_tooltip.cpp b/xfa/fxfa/parser/cxfa_tooltip.cpp
index 04f27c9..2fecedd 100644
--- a/xfa/fxfa/parser/cxfa_tooltip.cpp
+++ b/xfa/fxfa/parser/cxfa_tooltip.cpp
@@ -6,19 +6,17 @@
 
 #include "xfa/fxfa/parser/cxfa_tooltip.h"
 
-#include "fxjs/xfa/cjx_tooltip.h"
+#include "fxjs/xfa/cjx_textnode.h"
 #include "third_party/base/ptr_util.h"
 
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kToolTipAttributeData[] = {
     {XFA_Attribute::Id, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Rid, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Use, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Usehref, XFA_AttributeType::CData, nullptr},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"toolTip";
+};
 
 }  // namespace
 
@@ -28,9 +26,8 @@
                 (XFA_XDPPACKET_Template | XFA_XDPPACKET_Form),
                 XFA_ObjectType::TextNode,
                 XFA_Element::ToolTip,
-                nullptr,
-                kAttributeData,
-                kName,
-                pdfium::MakeUnique<CJX_ToolTip>(this)) {}
+                {},
+                kToolTipAttributeData,
+                pdfium::MakeUnique<CJX_TextNode>(this)) {}
 
-CXFA_ToolTip::~CXFA_ToolTip() {}
+CXFA_ToolTip::~CXFA_ToolTip() = default;
diff --git a/xfa/fxfa/parser/cxfa_tooltip.h b/xfa/fxfa/parser/cxfa_tooltip.h
index 0b13282..f46ca62 100644
--- a/xfa/fxfa/parser/cxfa_tooltip.h
+++ b/xfa/fxfa/parser/cxfa_tooltip.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_ToolTip : public CXFA_Node {
+class CXFA_ToolTip final : public CXFA_Node {
  public:
   CXFA_ToolTip(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_ToolTip() override;
diff --git a/xfa/fxfa/parser/cxfa_trace.cpp b/xfa/fxfa/parser/cxfa_trace.cpp
index 7de01fc..741805d 100644
--- a/xfa/fxfa/parser/cxfa_trace.cpp
+++ b/xfa/fxfa/parser/cxfa_trace.cpp
@@ -6,14 +6,15 @@
 
 #include "xfa/fxfa/parser/cxfa_trace.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kTraceAttributeData[] = {
     {XFA_Attribute::Desc, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Lock, XFA_AttributeType::Integer, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"trace";
+};
 
 }  // namespace
 
@@ -23,8 +24,8 @@
                 XFA_XDPPACKET_Config,
                 XFA_ObjectType::Node,
                 XFA_Element::Trace,
-                nullptr,
-                kAttributeData,
-                kName) {}
+                {},
+                kTraceAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_Trace::~CXFA_Trace() {}
+CXFA_Trace::~CXFA_Trace() = default;
diff --git a/xfa/fxfa/parser/cxfa_trace.h b/xfa/fxfa/parser/cxfa_trace.h
index dec95da..1d76f73 100644
--- a/xfa/fxfa/parser/cxfa_trace.h
+++ b/xfa/fxfa/parser/cxfa_trace.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Trace : public CXFA_Node {
+class CXFA_Trace final : public CXFA_Node {
  public:
   CXFA_Trace(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Trace() override;
diff --git a/xfa/fxfa/parser/cxfa_transform.cpp b/xfa/fxfa/parser/cxfa_transform.cpp
index 5bfa476..e00ddc3 100644
--- a/xfa/fxfa/parser/cxfa_transform.cpp
+++ b/xfa/fxfa/parser/cxfa_transform.cpp
@@ -6,20 +6,23 @@
 
 #include "xfa/fxfa/parser/cxfa_transform.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::PropertyData kPropertyData[] = {
+const CXFA_Node::PropertyData kTransformPropertyData[] = {
     {XFA_Element::Whitespace, 1, 0},  {XFA_Element::Rename, 1, 0},
     {XFA_Element::IfEmpty, 1, 0},     {XFA_Element::Presence, 1, 0},
     {XFA_Element::Picture, 1, 0},     {XFA_Element::NameAttr, 1, 0},
-    {XFA_Element::GroupParent, 1, 0}, {XFA_Element::Unknown, 0, 0}};
-const CXFA_Node::AttributeData kAttributeData[] = {
+    {XFA_Element::GroupParent, 1, 0},
+};
+
+const CXFA_Node::AttributeData kTransformAttributeData[] = {
     {XFA_Attribute::Ref, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Desc, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Lock, XFA_AttributeType::Integer, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"transform";
+};
 
 }  // namespace
 
@@ -29,8 +32,8 @@
                 XFA_XDPPACKET_Config,
                 XFA_ObjectType::Node,
                 XFA_Element::Transform,
-                kPropertyData,
-                kAttributeData,
-                kName) {}
+                kTransformPropertyData,
+                kTransformAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_Transform::~CXFA_Transform() {}
+CXFA_Transform::~CXFA_Transform() = default;
diff --git a/xfa/fxfa/parser/cxfa_transform.h b/xfa/fxfa/parser/cxfa_transform.h
index fde54e6..6409c6c 100644
--- a/xfa/fxfa/parser/cxfa_transform.h
+++ b/xfa/fxfa/parser/cxfa_transform.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Transform : public CXFA_Node {
+class CXFA_Transform final : public CXFA_Node {
  public:
   CXFA_Transform(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Transform() override;
diff --git a/xfa/fxfa/parser/cxfa_traversal.cpp b/xfa/fxfa/parser/cxfa_traversal.cpp
index b5ffd3f..ad367e9 100644
--- a/xfa/fxfa/parser/cxfa_traversal.cpp
+++ b/xfa/fxfa/parser/cxfa_traversal.cpp
@@ -6,20 +6,20 @@
 
 #include "xfa/fxfa/parser/cxfa_traversal.h"
 
-#include "fxjs/xfa/cjx_traversal.h"
+#include "fxjs/xfa/cjx_node.h"
 #include "third_party/base/ptr_util.h"
 
 namespace {
 
-const CXFA_Node::PropertyData kPropertyData[] = {{XFA_Element::Extras, 1, 0},
-                                                 {XFA_Element::Unknown, 0, 0}};
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::PropertyData kTraversalPropertyData[] = {
+    {XFA_Element::Extras, 1, 0},
+};
+
+const CXFA_Node::AttributeData kTraversalAttributeData[] = {
     {XFA_Attribute::Id, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Use, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Usehref, XFA_AttributeType::CData, nullptr},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"traversal";
+};
 
 }  // namespace
 
@@ -29,9 +29,8 @@
                 (XFA_XDPPACKET_Template | XFA_XDPPACKET_Form),
                 XFA_ObjectType::Node,
                 XFA_Element::Traversal,
-                kPropertyData,
-                kAttributeData,
-                kName,
-                pdfium::MakeUnique<CJX_Traversal>(this)) {}
+                kTraversalPropertyData,
+                kTraversalAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_Traversal::~CXFA_Traversal() {}
+CXFA_Traversal::~CXFA_Traversal() = default;
diff --git a/xfa/fxfa/parser/cxfa_traversal.h b/xfa/fxfa/parser/cxfa_traversal.h
index 47422b2..154211b 100644
--- a/xfa/fxfa/parser/cxfa_traversal.h
+++ b/xfa/fxfa/parser/cxfa_traversal.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Traversal : public CXFA_Node {
+class CXFA_Traversal final : public CXFA_Node {
  public:
   CXFA_Traversal(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Traversal() override;
diff --git a/xfa/fxfa/parser/cxfa_traverse.cpp b/xfa/fxfa/parser/cxfa_traverse.cpp
index d771b37..7afc59f 100644
--- a/xfa/fxfa/parser/cxfa_traverse.cpp
+++ b/xfa/fxfa/parser/cxfa_traverse.cpp
@@ -6,24 +6,24 @@
 
 #include "xfa/fxfa/parser/cxfa_traverse.h"
 
-#include "fxjs/xfa/cjx_traverse.h"
+#include "fxjs/xfa/cjx_node.h"
 #include "third_party/base/ptr_util.h"
 
 namespace {
 
-const CXFA_Node::PropertyData kPropertyData[] = {{XFA_Element::Script, 1, 0},
-                                                 {XFA_Element::Extras, 1, 0},
-                                                 {XFA_Element::Unknown, 0, 0}};
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::PropertyData kTraversePropertyData[] = {
+    {XFA_Element::Script, 1, 0},
+    {XFA_Element::Extras, 1, 0},
+};
+
+const CXFA_Node::AttributeData kTraverseAttributeData[] = {
     {XFA_Attribute::Id, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Ref, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Use, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Operation, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::Next},
+     (void*)XFA_AttributeValue::Next},
     {XFA_Attribute::Usehref, XFA_AttributeType::CData, nullptr},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"traverse";
+};
 
 }  // namespace
 
@@ -33,9 +33,8 @@
                 (XFA_XDPPACKET_Template | XFA_XDPPACKET_Form),
                 XFA_ObjectType::Node,
                 XFA_Element::Traverse,
-                kPropertyData,
-                kAttributeData,
-                kName,
-                pdfium::MakeUnique<CJX_Traverse>(this)) {}
+                kTraversePropertyData,
+                kTraverseAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
 CXFA_Traverse::~CXFA_Traverse() {}
diff --git a/xfa/fxfa/parser/cxfa_traverse.h b/xfa/fxfa/parser/cxfa_traverse.h
index de33cb7..dec5b89 100644
--- a/xfa/fxfa/parser/cxfa_traverse.h
+++ b/xfa/fxfa/parser/cxfa_traverse.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Traverse : public CXFA_Node {
+class CXFA_Traverse final : public CXFA_Node {
  public:
   CXFA_Traverse(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Traverse() override;
diff --git a/xfa/fxfa/parser/cxfa_traversestrategy_contentareacontainerlayoutitem.h b/xfa/fxfa/parser/cxfa_traversestrategy_contentareacontainerlayoutitem.h
deleted file mode 100644
index e0a584e..0000000
--- a/xfa/fxfa/parser/cxfa_traversestrategy_contentareacontainerlayoutitem.h
+++ /dev/null
@@ -1,44 +0,0 @@
-// Copyright 2016 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_TRAVERSESTRATEGY_CONTENTAREACONTAINERLAYOUTITEM_H_
-#define XFA_FXFA_PARSER_CXFA_TRAVERSESTRATEGY_CONTENTAREACONTAINERLAYOUTITEM_H_
-
-#include "xfa/fxfa/parser/cxfa_containerlayoutitem.h"
-
-class CXFA_TraverseStrategy_ContentAreaContainerLayoutItem {
- public:
-  static CXFA_ContainerLayoutItem* GetFirstChild(
-      CXFA_ContainerLayoutItem* pLayoutItem) {
-    for (CXFA_LayoutItem* pChildItem = pLayoutItem->m_pFirstChild; pChildItem;
-         pChildItem = pChildItem->m_pNextSibling) {
-      if (CXFA_ContainerLayoutItem* pContainer =
-              pChildItem->AsContainerLayoutItem()) {
-        return pContainer;
-      }
-    }
-    return nullptr;
-  }
-
-  static CXFA_ContainerLayoutItem* GetNextSibling(
-      CXFA_ContainerLayoutItem* pLayoutItem) {
-    for (CXFA_LayoutItem* pChildItem = pLayoutItem->m_pNextSibling; pChildItem;
-         pChildItem = pChildItem->m_pNextSibling) {
-      if (CXFA_ContainerLayoutItem* pContainer =
-              pChildItem->AsContainerLayoutItem()) {
-        return pContainer;
-      }
-    }
-    return nullptr;
-  }
-
-  static CXFA_ContainerLayoutItem* GetParent(
-      CXFA_ContainerLayoutItem* pLayoutItem) {
-    return static_cast<CXFA_ContainerLayoutItem*>(pLayoutItem->m_pParent);
-  }
-};
-
-#endif  // XFA_FXFA_PARSER_CXFA_TRAVERSESTRATEGY_CONTENTAREACONTAINERLAYOUTITEM_H_
diff --git a/xfa/fxfa/parser/cxfa_traversestrategy_contentlayoutitem.h b/xfa/fxfa/parser/cxfa_traversestrategy_contentlayoutitem.h
deleted file mode 100644
index de0d52a..0000000
--- a/xfa/fxfa/parser/cxfa_traversestrategy_contentlayoutitem.h
+++ /dev/null
@@ -1,30 +0,0 @@
-// Copyright 2016 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_TRAVERSESTRATEGY_CONTENTLAYOUTITEM_H_
-#define XFA_FXFA_PARSER_CXFA_TRAVERSESTRATEGY_CONTENTLAYOUTITEM_H_
-
-#include "xfa/fxfa/parser/cxfa_contentlayoutitem.h"
-
-class CXFA_TraverseStrategy_ContentLayoutItem {
- public:
-  static CXFA_ContentLayoutItem* GetFirstChild(
-      CXFA_ContentLayoutItem* pLayoutItem) {
-    return static_cast<CXFA_ContentLayoutItem*>(pLayoutItem->m_pFirstChild);
-  }
-
-  static CXFA_ContentLayoutItem* GetNextSibling(
-      CXFA_ContentLayoutItem* pLayoutItem) {
-    return static_cast<CXFA_ContentLayoutItem*>(pLayoutItem->m_pNextSibling);
-  }
-
-  static CXFA_ContentLayoutItem* GetParent(
-      CXFA_ContentLayoutItem* pLayoutItem) {
-    return static_cast<CXFA_ContentLayoutItem*>(pLayoutItem->m_pParent);
-  }
-};
-
-#endif  // XFA_FXFA_PARSER_CXFA_TRAVERSESTRATEGY_CONTENTLAYOUTITEM_H_
diff --git a/xfa/fxfa/parser/cxfa_traversestrategy_layoutitem.h b/xfa/fxfa/parser/cxfa_traversestrategy_layoutitem.h
deleted file mode 100644
index 7b39826..0000000
--- a/xfa/fxfa/parser/cxfa_traversestrategy_layoutitem.h
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright 2016 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_TRAVERSESTRATEGY_LAYOUTITEM_H_
-#define XFA_FXFA_PARSER_CXFA_TRAVERSESTRATEGY_LAYOUTITEM_H_
-
-#include "xfa/fxfa/parser/cxfa_layoutitem.h"
-
-class CXFA_TraverseStrategy_LayoutItem {
- public:
-  static CXFA_LayoutItem* GetFirstChild(CXFA_LayoutItem* pLayoutItem) {
-    return pLayoutItem->m_pFirstChild;
-  }
-  static CXFA_LayoutItem* GetNextSibling(CXFA_LayoutItem* pLayoutItem) {
-    return pLayoutItem->m_pNextSibling;
-  }
-  static CXFA_LayoutItem* GetParent(CXFA_LayoutItem* pLayoutItem) {
-    return pLayoutItem->m_pParent;
-  }
-};
-
-#endif  // XFA_FXFA_PARSER_CXFA_TRAVERSESTRATEGY_LAYOUTITEM_H_
diff --git a/xfa/fxfa/parser/cxfa_traversestrategy_xfacontainernode.h b/xfa/fxfa/parser/cxfa_traversestrategy_xfacontainernode.h
index 3ca632a..d867f9f 100644
--- a/xfa/fxfa/parser/cxfa_traversestrategy_xfacontainernode.h
+++ b/xfa/fxfa/parser/cxfa_traversestrategy_xfacontainernode.h
@@ -23,8 +23,8 @@
   }
 };
 
-typedef CXFA_NodeIteratorTemplate<CXFA_Node,
-                                  CXFA_TraverseStrategy_XFAContainerNode>
-    CXFA_ContainerIterator;
+using CXFA_ContainerIterator =
+    CXFA_NodeIteratorTemplate<CXFA_Node,
+                              CXFA_TraverseStrategy_XFAContainerNode>;
 
 #endif  // XFA_FXFA_PARSER_CXFA_TRAVERSESTRATEGY_XFACONTAINERNODE_H_
diff --git a/xfa/fxfa/parser/cxfa_traversestrategy_xfanode.h b/xfa/fxfa/parser/cxfa_traversestrategy_xfanode.h
index fc98d18..90f39a8 100644
--- a/xfa/fxfa/parser/cxfa_traversestrategy_xfanode.h
+++ b/xfa/fxfa/parser/cxfa_traversestrategy_xfanode.h
@@ -22,7 +22,7 @@
   }
 };
 
-typedef CXFA_NodeIteratorTemplate<CXFA_Node, CXFA_TraverseStrategy_XFANode>
-    CXFA_NodeIterator;
+using CXFA_NodeIterator =
+    CXFA_NodeIteratorTemplate<CXFA_Node, CXFA_TraverseStrategy_XFANode>;
 
 #endif  // XFA_FXFA_PARSER_CXFA_TRAVERSESTRATEGY_XFANODE_H_
diff --git a/xfa/fxfa/parser/cxfa_treelist.cpp b/xfa/fxfa/parser/cxfa_treelist.cpp
index 5db9ecb..2dbec60 100644
--- a/xfa/fxfa/parser/cxfa_treelist.cpp
+++ b/xfa/fxfa/parser/cxfa_treelist.cpp
@@ -9,23 +9,19 @@
 #include <memory>
 
 #include "core/fxcrt/fx_extension.h"
-#include "fxjs/cfxjse_engine.h"
 #include "fxjs/xfa/cjx_treelist.h"
-#include "third_party/base/numerics/safe_conversions.h"
-#include "xfa/fxfa/parser/cxfa_document.h"
-#include "xfa/fxfa/parser/cxfa_list.h"
+#include "third_party/base/ptr_util.h"
 #include "xfa/fxfa/parser/cxfa_node.h"
 
 CXFA_TreeList::CXFA_TreeList(CXFA_Document* pDocument)
     : CXFA_List(pDocument,
                 XFA_ObjectType::TreeList,
                 XFA_Element::TreeList,
-                WideStringView(L"treeList"),
                 pdfium::MakeUnique<CJX_TreeList>(this)) {}
 
-CXFA_TreeList::~CXFA_TreeList() {}
+CXFA_TreeList::~CXFA_TreeList() = default;
 
-CXFA_Node* CXFA_TreeList::NamedItem(const WideStringView& wsName) {
+CXFA_Node* CXFA_TreeList::NamedItem(WideStringView wsName) {
   uint32_t dwHashCode = FX_HashCode_GetW(wsName, false);
   size_t count = GetLength();
   for (size_t i = 0; i < count; i++) {
diff --git a/xfa/fxfa/parser/cxfa_treelist.h b/xfa/fxfa/parser/cxfa_treelist.h
index 3c65ca5..a194e32 100644
--- a/xfa/fxfa/parser/cxfa_treelist.h
+++ b/xfa/fxfa/parser/cxfa_treelist.h
@@ -7,8 +7,7 @@
 #ifndef XFA_FXFA_PARSER_CXFA_TREELIST_H_
 #define XFA_FXFA_PARSER_CXFA_TREELIST_H_
 
-#include "fxjs/xfa/cjx_treelist.h"
-#include "xfa/fxfa/fxfa_basic.h"
+#include "core/fxcrt/fx_string.h"
 #include "xfa/fxfa/parser/cxfa_list.h"
 
 class CXFA_Node;
@@ -18,7 +17,7 @@
   explicit CXFA_TreeList(CXFA_Document* pDocument);
   ~CXFA_TreeList() override;
 
-  CXFA_Node* NamedItem(const WideStringView& wsName);
+  CXFA_Node* NamedItem(WideStringView wsName);
 };
 
 #endif  // XFA_FXFA_PARSER_CXFA_TREELIST_H_
diff --git a/xfa/fxfa/parser/cxfa_type.cpp b/xfa/fxfa/parser/cxfa_type.cpp
index ac1c193..ba36158 100644
--- a/xfa/fxfa/parser/cxfa_type.cpp
+++ b/xfa/fxfa/parser/cxfa_type.cpp
@@ -6,14 +6,15 @@
 
 #include "xfa/fxfa/parser/cxfa_type.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kTypeAttributeData[] = {
     {XFA_Attribute::Desc, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Lock, XFA_AttributeType::Integer, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"type";
+};
 
 }  // namespace
 
@@ -23,8 +24,8 @@
                 XFA_XDPPACKET_Config,
                 XFA_ObjectType::ContentNode,
                 XFA_Element::Type,
-                nullptr,
-                kAttributeData,
-                kName) {}
+                {},
+                kTypeAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_Type::~CXFA_Type() {}
+CXFA_Type::~CXFA_Type() = default;
diff --git a/xfa/fxfa/parser/cxfa_type.h b/xfa/fxfa/parser/cxfa_type.h
index 5e7d467..ef696fd 100644
--- a/xfa/fxfa/parser/cxfa_type.h
+++ b/xfa/fxfa/parser/cxfa_type.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Type : public CXFA_Node {
+class CXFA_Type final : public CXFA_Node {
  public:
   CXFA_Type(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Type() override;
diff --git a/xfa/fxfa/parser/cxfa_typeface.cpp b/xfa/fxfa/parser/cxfa_typeface.cpp
index 3bf69bd..0d2c2dc 100644
--- a/xfa/fxfa/parser/cxfa_typeface.cpp
+++ b/xfa/fxfa/parser/cxfa_typeface.cpp
@@ -6,13 +6,14 @@
 
 #include "xfa/fxfa/parser/cxfa_typeface.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kTypefaceAttributeData[] = {
     {XFA_Attribute::Name, XFA_AttributeType::CData, nullptr},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"typeface";
+};
 
 }  // namespace
 
@@ -22,8 +23,8 @@
                 XFA_XDPPACKET_LocaleSet,
                 XFA_ObjectType::Node,
                 XFA_Element::Typeface,
-                nullptr,
-                kAttributeData,
-                kName) {}
+                {},
+                kTypefaceAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_Typeface::~CXFA_Typeface() {}
+CXFA_Typeface::~CXFA_Typeface() = default;
diff --git a/xfa/fxfa/parser/cxfa_typeface.h b/xfa/fxfa/parser/cxfa_typeface.h
index cbc90c4..7b07cae 100644
--- a/xfa/fxfa/parser/cxfa_typeface.h
+++ b/xfa/fxfa/parser/cxfa_typeface.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Typeface : public CXFA_Node {
+class CXFA_Typeface final : public CXFA_Node {
  public:
   CXFA_Typeface(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Typeface() override;
diff --git a/xfa/fxfa/parser/cxfa_typefaces.cpp b/xfa/fxfa/parser/cxfa_typefaces.cpp
index 525919d..dfc35e0 100644
--- a/xfa/fxfa/parser/cxfa_typefaces.cpp
+++ b/xfa/fxfa/parser/cxfa_typefaces.cpp
@@ -6,11 +6,8 @@
 
 #include "xfa/fxfa/parser/cxfa_typefaces.h"
 
-namespace {
-
-constexpr wchar_t kName[] = L"typefaces";
-
-}  // namespace
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
 
 CXFA_Typefaces::CXFA_Typefaces(CXFA_Document* doc, XFA_PacketType packet)
     : CXFA_Node(doc,
@@ -18,8 +15,8 @@
                 XFA_XDPPACKET_LocaleSet,
                 XFA_ObjectType::Node,
                 XFA_Element::Typefaces,
-                nullptr,
-                nullptr,
-                kName) {}
+                {},
+                {},
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_Typefaces::~CXFA_Typefaces() {}
+CXFA_Typefaces::~CXFA_Typefaces() = default;
diff --git a/xfa/fxfa/parser/cxfa_typefaces.h b/xfa/fxfa/parser/cxfa_typefaces.h
index fa4b43f..b65c57d 100644
--- a/xfa/fxfa/parser/cxfa_typefaces.h
+++ b/xfa/fxfa/parser/cxfa_typefaces.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Typefaces : public CXFA_Node {
+class CXFA_Typefaces final : public CXFA_Node {
  public:
   CXFA_Typefaces(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Typefaces() override;
diff --git a/xfa/fxfa/parser/cxfa_ui.cpp b/xfa/fxfa/parser/cxfa_ui.cpp
index 883e79a..1630a3d 100644
--- a/xfa/fxfa/parser/cxfa_ui.cpp
+++ b/xfa/fxfa/parser/cxfa_ui.cpp
@@ -6,12 +6,12 @@
 
 #include "xfa/fxfa/parser/cxfa_ui.h"
 
-#include "fxjs/xfa/cjx_ui.h"
+#include "fxjs/xfa/cjx_node.h"
 #include "third_party/base/ptr_util.h"
 
 namespace {
 
-const CXFA_Node::PropertyData kPropertyData[] = {
+const CXFA_Node::PropertyData kUiPropertyData[] = {
     {XFA_Element::CheckButton, 1, XFA_PROPERTYFLAG_OneOf},
     {XFA_Element::ChoiceList, 1, XFA_PROPERTYFLAG_OneOf},
     {XFA_Element::DefaultUi, 1, XFA_PROPERTYFLAG_OneOf},
@@ -24,16 +24,14 @@
     {XFA_Element::NumericEdit, 1, XFA_PROPERTYFLAG_OneOf},
     {XFA_Element::Signature, 1, XFA_PROPERTYFLAG_OneOf},
     {XFA_Element::TextEdit, 1, XFA_PROPERTYFLAG_OneOf},
-    {XFA_Element::ExObject, 1, XFA_PROPERTYFLAG_OneOf},
     {XFA_Element::Extras, 1, 0},
-    {XFA_Element::Unknown, 0, 0}};
-const CXFA_Node::AttributeData kAttributeData[] = {
+};
+
+const CXFA_Node::AttributeData kUiAttributeData[] = {
     {XFA_Attribute::Id, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Use, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Usehref, XFA_AttributeType::CData, nullptr},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"ui";
+};
 
 }  // namespace
 
@@ -43,9 +41,18 @@
                 (XFA_XDPPACKET_Template | XFA_XDPPACKET_Form),
                 XFA_ObjectType::Node,
                 XFA_Element::Ui,
-                kPropertyData,
-                kAttributeData,
-                kName,
-                pdfium::MakeUnique<CJX_Ui>(this)) {}
+                kUiPropertyData,
+                kUiAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_Ui::~CXFA_Ui() {}
+CXFA_Ui::~CXFA_Ui() = default;
+
+bool CXFA_Ui::IsAOneOfChild(CXFA_Node* child) const {
+  for (auto& prop : kUiPropertyData) {
+    if (prop.property != child->GetElementType())
+      continue;
+    if (!!(prop.flags & XFA_PROPERTYFLAG_OneOf))
+      return true;
+  }
+  return false;
+}
diff --git a/xfa/fxfa/parser/cxfa_ui.h b/xfa/fxfa/parser/cxfa_ui.h
index 0824d6b..d479e95 100644
--- a/xfa/fxfa/parser/cxfa_ui.h
+++ b/xfa/fxfa/parser/cxfa_ui.h
@@ -9,10 +9,12 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Ui : public CXFA_Node {
+class CXFA_Ui final : public CXFA_Node {
  public:
   CXFA_Ui(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Ui() override;
+
+  bool IsAOneOfChild(CXFA_Node* child) const;
 };
 
 #endif  // XFA_FXFA_PARSER_CXFA_UI_H_
diff --git a/xfa/fxfa/parser/cxfa_update.cpp b/xfa/fxfa/parser/cxfa_update.cpp
index 986e110..6150ff5 100644
--- a/xfa/fxfa/parser/cxfa_update.cpp
+++ b/xfa/fxfa/parser/cxfa_update.cpp
@@ -6,19 +6,17 @@
 
 #include "xfa/fxfa/parser/cxfa_update.h"
 
-#include "fxjs/xfa/cjx_update.h"
+#include "fxjs/xfa/cjx_textnode.h"
 #include "third_party/base/ptr_util.h"
 
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kUpdateAttributeData[] = {
     {XFA_Attribute::Id, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Name, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Use, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Usehref, XFA_AttributeType::CData, nullptr},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"update";
+};
 
 }  // namespace
 
@@ -28,9 +26,8 @@
                 XFA_XDPPACKET_SourceSet,
                 XFA_ObjectType::TextNode,
                 XFA_Element::Update,
-                nullptr,
-                kAttributeData,
-                kName,
-                pdfium::MakeUnique<CJX_Update>(this)) {}
+                {},
+                kUpdateAttributeData,
+                pdfium::MakeUnique<CJX_TextNode>(this)) {}
 
-CXFA_Update::~CXFA_Update() {}
+CXFA_Update::~CXFA_Update() = default;
diff --git a/xfa/fxfa/parser/cxfa_update.h b/xfa/fxfa/parser/cxfa_update.h
index 9e652ea..3e6bb6c 100644
--- a/xfa/fxfa/parser/cxfa_update.h
+++ b/xfa/fxfa/parser/cxfa_update.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Update : public CXFA_Node {
+class CXFA_Update final : public CXFA_Node {
  public:
   CXFA_Update(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Update() override;
diff --git a/xfa/fxfa/parser/cxfa_uri.cpp b/xfa/fxfa/parser/cxfa_uri.cpp
index 96cc3ec..79d1ea6 100644
--- a/xfa/fxfa/parser/cxfa_uri.cpp
+++ b/xfa/fxfa/parser/cxfa_uri.cpp
@@ -6,21 +6,19 @@
 
 #include "xfa/fxfa/parser/cxfa_uri.h"
 
-#include "fxjs/xfa/cjx_uri.h"
+#include "fxjs/xfa/cjx_textnode.h"
 #include "third_party/base/ptr_util.h"
 
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kUriAttributeData[] = {
     {XFA_Attribute::Id, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Name, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Use, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Usehref, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Desc, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Lock, XFA_AttributeType::Integer, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"uri";
+};
 
 }  // namespace
 
@@ -30,9 +28,8 @@
                 (XFA_XDPPACKET_Config | XFA_XDPPACKET_ConnectionSet),
                 XFA_ObjectType::TextNode,
                 XFA_Element::Uri,
-                nullptr,
-                kAttributeData,
-                kName,
-                pdfium::MakeUnique<CJX_Uri>(this)) {}
+                {},
+                kUriAttributeData,
+                pdfium::MakeUnique<CJX_TextNode>(this)) {}
 
-CXFA_Uri::~CXFA_Uri() {}
+CXFA_Uri::~CXFA_Uri() = default;
diff --git a/xfa/fxfa/parser/cxfa_uri.h b/xfa/fxfa/parser/cxfa_uri.h
index bb31596..96252fc 100644
--- a/xfa/fxfa/parser/cxfa_uri.h
+++ b/xfa/fxfa/parser/cxfa_uri.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Uri : public CXFA_Node {
+class CXFA_Uri final : public CXFA_Node {
  public:
   CXFA_Uri(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Uri() override;
diff --git a/xfa/fxfa/parser/cxfa_user.cpp b/xfa/fxfa/parser/cxfa_user.cpp
index 09ec608..fb36d34 100644
--- a/xfa/fxfa/parser/cxfa_user.cpp
+++ b/xfa/fxfa/parser/cxfa_user.cpp
@@ -6,19 +6,17 @@
 
 #include "xfa/fxfa/parser/cxfa_user.h"
 
-#include "fxjs/xfa/cjx_user.h"
+#include "fxjs/xfa/cjx_textnode.h"
 #include "third_party/base/ptr_util.h"
 
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kUserAttributeData[] = {
     {XFA_Attribute::Id, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Name, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Use, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Usehref, XFA_AttributeType::CData, nullptr},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"user";
+};
 
 }  // namespace
 
@@ -28,9 +26,8 @@
                 XFA_XDPPACKET_SourceSet,
                 XFA_ObjectType::TextNode,
                 XFA_Element::User,
-                nullptr,
-                kAttributeData,
-                kName,
-                pdfium::MakeUnique<CJX_User>(this)) {}
+                {},
+                kUserAttributeData,
+                pdfium::MakeUnique<CJX_TextNode>(this)) {}
 
-CXFA_User::~CXFA_User() {}
+CXFA_User::~CXFA_User() = default;
diff --git a/xfa/fxfa/parser/cxfa_user.h b/xfa/fxfa/parser/cxfa_user.h
index 3aad173..eca1a37 100644
--- a/xfa/fxfa/parser/cxfa_user.h
+++ b/xfa/fxfa/parser/cxfa_user.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_User : public CXFA_Node {
+class CXFA_User final : public CXFA_Node {
  public:
   CXFA_User(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_User() override;
diff --git a/xfa/fxfa/parser/cxfa_validate.cpp b/xfa/fxfa/parser/cxfa_validate.cpp
index 868e805..d65b170 100644
--- a/xfa/fxfa/parser/cxfa_validate.cpp
+++ b/xfa/fxfa/parser/cxfa_validate.cpp
@@ -6,35 +6,36 @@
 
 #include "xfa/fxfa/parser/cxfa_validate.h"
 
+#include "fxjs/xfa/cjx_node.h"
 #include "fxjs/xfa/cjx_object.h"
-#include "fxjs/xfa/cjx_validate.h"
 #include "third_party/base/ptr_util.h"
 #include "xfa/fxfa/parser/cxfa_message.h"
 #include "xfa/fxfa/parser/cxfa_picture.h"
 #include "xfa/fxfa/parser/cxfa_script.h"
+#include "xfa/fxfa/parser/xfa_basic_data.h"
 
 namespace {
 
-const CXFA_Node::PropertyData kPropertyData[] = {{XFA_Element::Message, 1, 0},
-                                                 {XFA_Element::Picture, 1, 0},
-                                                 {XFA_Element::Script, 1, 0},
-                                                 {XFA_Element::Extras, 1, 0},
-                                                 {XFA_Element::Unknown, 0, 0}};
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::PropertyData kValidatePropertyData[] = {
+    {XFA_Element::Message, 1, 0},
+    {XFA_Element::Picture, 1, 0},
+    {XFA_Element::Script, 1, 0},
+    {XFA_Element::Extras, 1, 0},
+};
+const CXFA_Node::AttributeData kValidateAttributeData[] = {
     {XFA_Attribute::Id, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Use, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::ScriptTest, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::Error},
+     (void*)XFA_AttributeValue::Error},
     {XFA_Attribute::NullTest, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::Disabled},
+     (void*)XFA_AttributeValue::Disabled},
     {XFA_Attribute::Usehref, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Desc, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::FormatTest, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::Warning},
+     (void*)XFA_AttributeValue::Warning},
     {XFA_Attribute::Lock, XFA_AttributeType::Integer, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
+};
 
-constexpr wchar_t kName[] = L"validate";
 constexpr wchar_t kFormatTest[] = L"formatTest";
 constexpr wchar_t kNullTest[] = L"nullTest";
 constexpr wchar_t kScriptTest[] = L"scriptTest";
@@ -48,29 +49,28 @@
           (XFA_XDPPACKET_Config | XFA_XDPPACKET_Template | XFA_XDPPACKET_Form),
           XFA_ObjectType::ContentNode,
           XFA_Element::Validate,
-          kPropertyData,
-          kAttributeData,
-          kName,
-          pdfium::MakeUnique<CJX_Validate>(this)) {}
+          kValidatePropertyData,
+          kValidateAttributeData,
+          pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_Validate::~CXFA_Validate() {}
+CXFA_Validate::~CXFA_Validate() = default;
 
-XFA_AttributeEnum CXFA_Validate::GetFormatTest() {
+XFA_AttributeValue CXFA_Validate::GetFormatTest() {
   return JSObject()->GetEnum(XFA_Attribute::FormatTest);
 }
 
 void CXFA_Validate::SetNullTest(const WideString& wsValue) {
-  Optional<XFA_AttributeEnum> item =
-      CXFA_Node::NameToAttributeEnum(wsValue.AsStringView());
+  Optional<XFA_AttributeValue> item =
+      XFA_GetAttributeValueByName(wsValue.AsStringView());
   JSObject()->SetEnum(XFA_Attribute::NullTest,
-                      item ? *item : XFA_AttributeEnum::Disabled, false);
+                      item ? *item : XFA_AttributeValue::Disabled, false);
 }
 
-XFA_AttributeEnum CXFA_Validate::GetNullTest() {
+XFA_AttributeValue CXFA_Validate::GetNullTest() {
   return JSObject()->GetEnum(XFA_Attribute::NullTest);
 }
 
-XFA_AttributeEnum CXFA_Validate::GetScriptTest() {
+XFA_AttributeValue CXFA_Validate::GetScriptTest() {
   return JSObject()->GetEnum(XFA_Attribute::ScriptTest);
 }
 
@@ -78,7 +78,7 @@
   CXFA_Message* pNode =
       JSObject()->GetProperty<CXFA_Message>(0, XFA_Element::Message);
   if (!pNode)
-    return L"";
+    return WideString();
 
   for (CXFA_Node* pItemNode = pNode->GetFirstChild(); pItemNode;
        pItemNode = pItemNode->GetNextSibling()) {
@@ -89,7 +89,7 @@
     if (wsName.IsEmpty() || wsName == wsMessageType)
       return pItemNode->JSObject()->GetContent(false);
   }
-  return L"";
+  return WideString();
 }
 
 void CXFA_Validate::SetFormatMessageText(const WideString& wsMessage) {
@@ -137,7 +137,7 @@
   }
 
   CXFA_Node* pTextNode = pNode->CreateSamePacketNode(XFA_Element::Text);
-  pNode->InsertChild(pTextNode, nullptr);
+  pNode->InsertChildAndNotify(pTextNode, nullptr);
   pTextNode->JSObject()->SetCData(XFA_Attribute::Name, wsMessageType, false,
                                   false);
   pTextNode->JSObject()->SetContent(wsMessage, wsMessage, false, false, true);
@@ -145,7 +145,7 @@
 
 WideString CXFA_Validate::GetPicture() {
   CXFA_Picture* pNode = GetChild<CXFA_Picture>(0, XFA_Element::Picture, false);
-  return pNode ? pNode->JSObject()->GetContent(false) : L"";
+  return pNode ? pNode->JSObject()->GetContent(false) : WideString();
 }
 
 CXFA_Script* CXFA_Validate::GetScriptIfExists() {
diff --git a/xfa/fxfa/parser/cxfa_validate.h b/xfa/fxfa/parser/cxfa_validate.h
index a601308..0018cf9 100644
--- a/xfa/fxfa/parser/cxfa_validate.h
+++ b/xfa/fxfa/parser/cxfa_validate.h
@@ -11,22 +11,22 @@
 
 class CXFA_Script;
 
-class CXFA_Validate : public CXFA_Node {
+class CXFA_Validate final : public CXFA_Node {
  public:
   CXFA_Validate(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Validate() override;
 
-  XFA_AttributeEnum GetFormatTest();
+  XFA_AttributeValue GetFormatTest();
   WideString GetFormatMessageText();
   void SetFormatMessageText(const WideString& wsMessage);
 
-  XFA_AttributeEnum GetNullTest();
+  XFA_AttributeValue GetNullTest();
   void SetNullTest(const WideString& wsValue);
 
   WideString GetNullMessageText();
   void SetNullMessageText(const WideString& wsMessage);
 
-  XFA_AttributeEnum GetScriptTest();
+  XFA_AttributeValue GetScriptTest();
   WideString GetScriptMessageText();
   void SetScriptMessageText(const WideString& wsMessage);
 
diff --git a/xfa/fxfa/parser/cxfa_validateapprovalsignatures.cpp b/xfa/fxfa/parser/cxfa_validateapprovalsignatures.cpp
index f51131e..d0aa5fd 100644
--- a/xfa/fxfa/parser/cxfa_validateapprovalsignatures.cpp
+++ b/xfa/fxfa/parser/cxfa_validateapprovalsignatures.cpp
@@ -6,14 +6,15 @@
 
 #include "xfa/fxfa/parser/cxfa_validateapprovalsignatures.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kValidateApprovalSignaturesAttributeData[] = {
     {XFA_Attribute::Desc, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Lock, XFA_AttributeType::Integer, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"validateApprovalSignatures";
+};
 
 }  // namespace
 
@@ -25,8 +26,8 @@
                 XFA_XDPPACKET_Config,
                 XFA_ObjectType::NodeV,
                 XFA_Element::ValidateApprovalSignatures,
-                nullptr,
-                kAttributeData,
-                kName) {}
+                {},
+                kValidateApprovalSignaturesAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_ValidateApprovalSignatures::~CXFA_ValidateApprovalSignatures() {}
+CXFA_ValidateApprovalSignatures::~CXFA_ValidateApprovalSignatures() = default;
diff --git a/xfa/fxfa/parser/cxfa_validateapprovalsignatures.h b/xfa/fxfa/parser/cxfa_validateapprovalsignatures.h
index d7dac98..0504168 100644
--- a/xfa/fxfa/parser/cxfa_validateapprovalsignatures.h
+++ b/xfa/fxfa/parser/cxfa_validateapprovalsignatures.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_ValidateApprovalSignatures : public CXFA_Node {
+class CXFA_ValidateApprovalSignatures final : public CXFA_Node {
  public:
   CXFA_ValidateApprovalSignatures(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_ValidateApprovalSignatures() override;
diff --git a/xfa/fxfa/parser/cxfa_validationmessaging.cpp b/xfa/fxfa/parser/cxfa_validationmessaging.cpp
index 196c98c..687f37c 100644
--- a/xfa/fxfa/parser/cxfa_validationmessaging.cpp
+++ b/xfa/fxfa/parser/cxfa_validationmessaging.cpp
@@ -6,14 +6,15 @@
 
 #include "xfa/fxfa/parser/cxfa_validationmessaging.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kValidationMessagingAttributeData[] = {
     {XFA_Attribute::Desc, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Lock, XFA_AttributeType::Integer, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"validationMessaging";
+};
 
 }  // namespace
 
@@ -24,8 +25,8 @@
                 XFA_XDPPACKET_Config,
                 XFA_ObjectType::NodeV,
                 XFA_Element::ValidationMessaging,
-                nullptr,
-                kAttributeData,
-                kName) {}
+                {},
+                kValidationMessagingAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_ValidationMessaging::~CXFA_ValidationMessaging() {}
+CXFA_ValidationMessaging::~CXFA_ValidationMessaging() = default;
diff --git a/xfa/fxfa/parser/cxfa_validationmessaging.h b/xfa/fxfa/parser/cxfa_validationmessaging.h
index 081b24c..1131788 100644
--- a/xfa/fxfa/parser/cxfa_validationmessaging.h
+++ b/xfa/fxfa/parser/cxfa_validationmessaging.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_ValidationMessaging : public CXFA_Node {
+class CXFA_ValidationMessaging final : public CXFA_Node {
  public:
   CXFA_ValidationMessaging(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_ValidationMessaging() override;
diff --git a/xfa/fxfa/parser/cxfa_value.cpp b/xfa/fxfa/parser/cxfa_value.cpp
index 2cd0dd9..979eabc 100644
--- a/xfa/fxfa/parser/cxfa_value.cpp
+++ b/xfa/fxfa/parser/cxfa_value.cpp
@@ -6,8 +6,8 @@
 
 #include "xfa/fxfa/parser/cxfa_value.h"
 
+#include "fxjs/xfa/cjx_node.h"
 #include "fxjs/xfa/cjx_object.h"
-#include "fxjs/xfa/cjx_value.h"
 #include "third_party/base/ptr_util.h"
 #include "xfa/fxfa/parser/cxfa_arc.h"
 #include "xfa/fxfa/parser/cxfa_exdata.h"
@@ -17,7 +17,7 @@
 
 namespace {
 
-const CXFA_Node::PropertyData kPropertyData[] = {
+const CXFA_Node::PropertyData kValuePropertyData[] = {
     {XFA_Element::Arc, 1, XFA_PROPERTYFLAG_OneOf},
     {XFA_Element::Text, 1, XFA_PROPERTYFLAG_OneOf},
     {XFA_Element::Time, 1, XFA_PROPERTYFLAG_OneOf},
@@ -31,16 +31,15 @@
     {XFA_Element::Date, 1, XFA_PROPERTYFLAG_OneOf},
     {XFA_Element::Float, 1, XFA_PROPERTYFLAG_OneOf},
     {XFA_Element::Line, 1, XFA_PROPERTYFLAG_OneOf},
-    {XFA_Element::Unknown, 0, 0}};
-const CXFA_Node::AttributeData kAttributeData[] = {
+};
+
+const CXFA_Node::AttributeData kValueAttributeData[] = {
     {XFA_Attribute::Id, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Use, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Relevant, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Usehref, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Override, XFA_AttributeType::Boolean, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"value";
+};
 
 }  // namespace
 
@@ -50,12 +49,11 @@
                 (XFA_XDPPACKET_Template | XFA_XDPPACKET_Form),
                 XFA_ObjectType::Node,
                 XFA_Element::Value,
-                kPropertyData,
-                kAttributeData,
-                kName,
-                pdfium::MakeUnique<CJX_Value>(this)) {}
+                kValuePropertyData,
+                kValueAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_Value::~CXFA_Value() {}
+CXFA_Value::~CXFA_Value() = default;
 
 XFA_Element CXFA_Value::GetChildValueClassID() const {
   CXFA_Node* pNode = GetFirstChild();
@@ -64,41 +62,49 @@
 
 WideString CXFA_Value::GetChildValueContent() const {
   CXFA_Node* pNode = GetFirstChild();
-  return pNode ? pNode->JSObject()->TryContent(false, true).value_or(L"") : L"";
+  return pNode
+             ? pNode->JSObject()->TryContent(false, true).value_or(WideString())
+             : WideString();
 }
 
 CXFA_Arc* CXFA_Value::GetArcIfExists() const {
   CXFA_Node* node = GetFirstChild();
-  ASSERT(!node || node->GetElementType() == XFA_Element::Arc);
+  if (!node || node->GetElementType() != XFA_Element::Arc)
+    return nullptr;
   return static_cast<CXFA_Arc*>(node);
 }
 
 CXFA_Line* CXFA_Value::GetLineIfExists() const {
   CXFA_Node* node = GetFirstChild();
-  ASSERT(!node || node->GetElementType() == XFA_Element::Line);
+  if (!node || node->GetElementType() != XFA_Element::Line)
+    return nullptr;
   return static_cast<CXFA_Line*>(node);
 }
 
 CXFA_Rectangle* CXFA_Value::GetRectangleIfExists() const {
   CXFA_Node* node = GetFirstChild();
-  ASSERT(!node || node->GetElementType() == XFA_Element::Rectangle);
+  if (!node || node->GetElementType() != XFA_Element::Rectangle)
+    return nullptr;
   return static_cast<CXFA_Rectangle*>(node);
 }
 
 CXFA_Text* CXFA_Value::GetTextIfExists() const {
   CXFA_Node* node = GetFirstChild();
-  ASSERT(!node || node->GetElementType() == XFA_Element::Text);
+  if (!node || node->GetElementType() != XFA_Element::Text)
+    return nullptr;
   return static_cast<CXFA_Text*>(node);
 }
 
 CXFA_ExData* CXFA_Value::GetExDataIfExists() const {
   CXFA_Node* node = GetFirstChild();
-  ASSERT(!node || node->GetElementType() == XFA_Element::ExData);
+  if (!node || node->GetElementType() != XFA_Element::ExData)
+    return nullptr;
   return static_cast<CXFA_ExData*>(node);
 }
 
 CXFA_Image* CXFA_Value::GetImageIfExists() const {
   CXFA_Node* node = GetFirstChild();
-  ASSERT(!node || node->GetElementType() == XFA_Element::Image);
+  if (!node || node->GetElementType() != XFA_Element::Image)
+    return nullptr;
   return static_cast<CXFA_Image*>(node);
 }
diff --git a/xfa/fxfa/parser/cxfa_value.h b/xfa/fxfa/parser/cxfa_value.h
index 47aeefe..ccd4c2c 100644
--- a/xfa/fxfa/parser/cxfa_value.h
+++ b/xfa/fxfa/parser/cxfa_value.h
@@ -17,7 +17,7 @@
 class CXFA_Line;
 class CXFA_Rectangle;
 
-class CXFA_Value : public CXFA_Node {
+class CXFA_Value final : public CXFA_Node {
  public:
   CXFA_Value(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Value() override;
diff --git a/xfa/fxfa/parser/cxfa_variables.cpp b/xfa/fxfa/parser/cxfa_variables.cpp
index 1e3e751..5974b9e 100644
--- a/xfa/fxfa/parser/cxfa_variables.cpp
+++ b/xfa/fxfa/parser/cxfa_variables.cpp
@@ -6,18 +6,16 @@
 
 #include "xfa/fxfa/parser/cxfa_variables.h"
 
-#include "fxjs/xfa/cjx_variables.h"
+#include "fxjs/xfa/cjx_container.h"
 #include "third_party/base/ptr_util.h"
 
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kVariablesAttributeData[] = {
     {XFA_Attribute::Id, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Use, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Usehref, XFA_AttributeType::CData, nullptr},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"variables";
+};
 
 }  // namespace
 
@@ -27,9 +25,8 @@
                 (XFA_XDPPACKET_Template | XFA_XDPPACKET_Form),
                 XFA_ObjectType::ContainerNode,
                 XFA_Element::Variables,
-                nullptr,
-                kAttributeData,
-                kName,
-                pdfium::MakeUnique<CJX_Variables>(this)) {}
+                {},
+                kVariablesAttributeData,
+                pdfium::MakeUnique<CJX_Container>(this)) {}
 
-CXFA_Variables::~CXFA_Variables() {}
+CXFA_Variables::~CXFA_Variables() = default;
diff --git a/xfa/fxfa/parser/cxfa_variables.h b/xfa/fxfa/parser/cxfa_variables.h
index 4c4cb4e..b9f6d72 100644
--- a/xfa/fxfa/parser/cxfa_variables.h
+++ b/xfa/fxfa/parser/cxfa_variables.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Variables : public CXFA_Node {
+class CXFA_Variables final : public CXFA_Node {
  public:
   CXFA_Variables(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Variables() override;
diff --git a/xfa/fxfa/parser/cxfa_version.cpp b/xfa/fxfa/parser/cxfa_version.cpp
index 5266f44..651d498 100644
--- a/xfa/fxfa/parser/cxfa_version.cpp
+++ b/xfa/fxfa/parser/cxfa_version.cpp
@@ -6,14 +6,15 @@
 
 #include "xfa/fxfa/parser/cxfa_version.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kVersionAttributeData[] = {
     {XFA_Attribute::Desc, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Lock, XFA_AttributeType::Integer, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"version";
+};
 
 }  // namespace
 
@@ -23,8 +24,8 @@
                 XFA_XDPPACKET_Config,
                 XFA_ObjectType::ContentNode,
                 XFA_Element::Version,
-                nullptr,
-                kAttributeData,
-                kName) {}
+                {},
+                kVersionAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_Version::~CXFA_Version() {}
+CXFA_Version::~CXFA_Version() = default;
diff --git a/xfa/fxfa/parser/cxfa_version.h b/xfa/fxfa/parser/cxfa_version.h
index 34462fb..4b4f425 100644
--- a/xfa/fxfa/parser/cxfa_version.h
+++ b/xfa/fxfa/parser/cxfa_version.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Version : public CXFA_Node {
+class CXFA_Version final : public CXFA_Node {
  public:
   CXFA_Version(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Version() override;
diff --git a/xfa/fxfa/parser/cxfa_versioncontrol.cpp b/xfa/fxfa/parser/cxfa_versioncontrol.cpp
index 9cca84a..c72b877 100644
--- a/xfa/fxfa/parser/cxfa_versioncontrol.cpp
+++ b/xfa/fxfa/parser/cxfa_versioncontrol.cpp
@@ -6,19 +6,20 @@
 
 #include "xfa/fxfa/parser/cxfa_versioncontrol.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kVersionControlAttributeData[] = {
     {XFA_Attribute::SourceBelow, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::Update},
+     (void*)XFA_AttributeValue::Update},
     {XFA_Attribute::OutputBelow, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::Warn},
+     (void*)XFA_AttributeValue::Warn},
     {XFA_Attribute::SourceAbove, XFA_AttributeType::Enum,
-     (void*)XFA_AttributeEnum::Warn},
+     (void*)XFA_AttributeValue::Warn},
     {XFA_Attribute::Lock, XFA_AttributeType::Integer, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"versionControl";
+};
 
 }  // namespace
 
@@ -29,8 +30,8 @@
                 XFA_XDPPACKET_Config,
                 XFA_ObjectType::Node,
                 XFA_Element::VersionControl,
-                nullptr,
-                kAttributeData,
-                kName) {}
+                {},
+                kVersionControlAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_VersionControl::~CXFA_VersionControl() {}
+CXFA_VersionControl::~CXFA_VersionControl() = default;
diff --git a/xfa/fxfa/parser/cxfa_versioncontrol.h b/xfa/fxfa/parser/cxfa_versioncontrol.h
index 4688f55..733b817 100644
--- a/xfa/fxfa/parser/cxfa_versioncontrol.h
+++ b/xfa/fxfa/parser/cxfa_versioncontrol.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_VersionControl : public CXFA_Node {
+class CXFA_VersionControl final : public CXFA_Node {
  public:
   CXFA_VersionControl(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_VersionControl() override;
diff --git a/xfa/fxfa/parser/cxfa_viewerpreferences.cpp b/xfa/fxfa/parser/cxfa_viewerpreferences.cpp
index 1b80b47..4952c65 100644
--- a/xfa/fxfa/parser/cxfa_viewerpreferences.cpp
+++ b/xfa/fxfa/parser/cxfa_viewerpreferences.cpp
@@ -6,9 +6,12 @@
 
 #include "xfa/fxfa/parser/cxfa_viewerpreferences.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::PropertyData kPropertyData[] = {
+const CXFA_Node::PropertyData kViewerPreferencesPropertyData[] = {
     {XFA_Element::PrintScaling, 1, 0},
     {XFA_Element::Enforce, 1, 0},
     {XFA_Element::NumberOfCopies, 1, 0},
@@ -18,13 +21,12 @@
     {XFA_Element::DuplexOption, 1, 0},
     {XFA_Element::ADBE_JSDebugger, 1, 0},
     {XFA_Element::PickTrayByPDFSize, 1, 0},
-    {XFA_Element::Unknown, 0, 0}};
-const CXFA_Node::AttributeData kAttributeData[] = {
+};
+
+const CXFA_Node::AttributeData kViewerPreferencesAttributeData[] = {
     {XFA_Attribute::Desc, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Lock, XFA_AttributeType::Integer, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"viewerPreferences";
+};
 
 }  // namespace
 
@@ -35,8 +37,8 @@
                 XFA_XDPPACKET_Config,
                 XFA_ObjectType::Node,
                 XFA_Element::ViewerPreferences,
-                kPropertyData,
-                kAttributeData,
-                kName) {}
+                kViewerPreferencesPropertyData,
+                kViewerPreferencesAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_ViewerPreferences::~CXFA_ViewerPreferences() {}
+CXFA_ViewerPreferences::~CXFA_ViewerPreferences() = default;
diff --git a/xfa/fxfa/parser/cxfa_viewerpreferences.h b/xfa/fxfa/parser/cxfa_viewerpreferences.h
index bf831ee..229061f 100644
--- a/xfa/fxfa/parser/cxfa_viewerpreferences.h
+++ b/xfa/fxfa/parser/cxfa_viewerpreferences.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_ViewerPreferences : public CXFA_Node {
+class CXFA_ViewerPreferences final : public CXFA_Node {
  public:
   CXFA_ViewerPreferences(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_ViewerPreferences() override;
diff --git a/xfa/fxfa/parser/cxfa_webclient.cpp b/xfa/fxfa/parser/cxfa_webclient.cpp
index 0123560..66844fc 100644
--- a/xfa/fxfa/parser/cxfa_webclient.cpp
+++ b/xfa/fxfa/parser/cxfa_webclient.cpp
@@ -6,18 +6,21 @@
 
 #include "xfa/fxfa/parser/cxfa_webclient.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::PropertyData kPropertyData[] = {{XFA_Element::FontInfo, 1, 0},
-                                                 {XFA_Element::Xdc, 1, 0},
-                                                 {XFA_Element::Unknown, 0, 0}};
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::PropertyData kWebClientPropertyData[] = {
+    {XFA_Element::FontInfo, 1, 0},
+    {XFA_Element::Xdc, 1, 0},
+};
+
+const CXFA_Node::AttributeData kWebClientAttributeData[] = {
     {XFA_Attribute::Name, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Desc, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Lock, XFA_AttributeType::Integer, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"webClient";
+};
 
 }  // namespace
 
@@ -27,8 +30,8 @@
                 XFA_XDPPACKET_Config,
                 XFA_ObjectType::Node,
                 XFA_Element::WebClient,
-                kPropertyData,
-                kAttributeData,
-                kName) {}
+                kWebClientPropertyData,
+                kWebClientAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_WebClient::~CXFA_WebClient() {}
+CXFA_WebClient::~CXFA_WebClient() = default;
diff --git a/xfa/fxfa/parser/cxfa_webclient.h b/xfa/fxfa/parser/cxfa_webclient.h
index b778689..41da046 100644
--- a/xfa/fxfa/parser/cxfa_webclient.h
+++ b/xfa/fxfa/parser/cxfa_webclient.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_WebClient : public CXFA_Node {
+class CXFA_WebClient final : public CXFA_Node {
  public:
   CXFA_WebClient(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_WebClient() override;
diff --git a/xfa/fxfa/parser/cxfa_whitespace.cpp b/xfa/fxfa/parser/cxfa_whitespace.cpp
index 6359b86..d8bdc62 100644
--- a/xfa/fxfa/parser/cxfa_whitespace.cpp
+++ b/xfa/fxfa/parser/cxfa_whitespace.cpp
@@ -6,14 +6,15 @@
 
 #include "xfa/fxfa/parser/cxfa_whitespace.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kWhitespaceAttributeData[] = {
     {XFA_Attribute::Desc, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Lock, XFA_AttributeType::Integer, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"whitespace";
+};
 
 }  // namespace
 
@@ -23,8 +24,8 @@
                 XFA_XDPPACKET_Config,
                 XFA_ObjectType::NodeV,
                 XFA_Element::Whitespace,
-                nullptr,
-                kAttributeData,
-                kName) {}
+                {},
+                kWhitespaceAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_Whitespace::~CXFA_Whitespace() {}
+CXFA_Whitespace::~CXFA_Whitespace() = default;
diff --git a/xfa/fxfa/parser/cxfa_whitespace.h b/xfa/fxfa/parser/cxfa_whitespace.h
index 62dde48..096a2da 100644
--- a/xfa/fxfa/parser/cxfa_whitespace.h
+++ b/xfa/fxfa/parser/cxfa_whitespace.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Whitespace : public CXFA_Node {
+class CXFA_Whitespace final : public CXFA_Node {
  public:
   CXFA_Whitespace(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Whitespace() override;
diff --git a/xfa/fxfa/parser/cxfa_window.cpp b/xfa/fxfa/parser/cxfa_window.cpp
index b1485f6..c1dd78d 100644
--- a/xfa/fxfa/parser/cxfa_window.cpp
+++ b/xfa/fxfa/parser/cxfa_window.cpp
@@ -6,14 +6,15 @@
 
 #include "xfa/fxfa/parser/cxfa_window.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kWindowAttributeData[] = {
     {XFA_Attribute::Desc, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Lock, XFA_AttributeType::Integer, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"window";
+};
 
 }  // namespace
 
@@ -23,8 +24,8 @@
                 XFA_XDPPACKET_Config,
                 XFA_ObjectType::NodeV,
                 XFA_Element::Window,
-                nullptr,
-                kAttributeData,
-                kName) {}
+                {},
+                kWindowAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_Window::~CXFA_Window() {}
+CXFA_Window::~CXFA_Window() = default;
diff --git a/xfa/fxfa/parser/cxfa_window.h b/xfa/fxfa/parser/cxfa_window.h
index 852bc68..fc2fcb7 100644
--- a/xfa/fxfa/parser/cxfa_window.h
+++ b/xfa/fxfa/parser/cxfa_window.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Window : public CXFA_Node {
+class CXFA_Window final : public CXFA_Node {
  public:
   CXFA_Window(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Window() override;
diff --git a/xfa/fxfa/parser/cxfa_wsdladdress.cpp b/xfa/fxfa/parser/cxfa_wsdladdress.cpp
index 239bb66..9c35cac 100644
--- a/xfa/fxfa/parser/cxfa_wsdladdress.cpp
+++ b/xfa/fxfa/parser/cxfa_wsdladdress.cpp
@@ -6,19 +6,17 @@
 
 #include "xfa/fxfa/parser/cxfa_wsdladdress.h"
 
-#include "fxjs/xfa/cjx_wsdladdress.h"
+#include "fxjs/xfa/cjx_textnode.h"
 #include "third_party/base/ptr_util.h"
 
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kWsdlAddressAttributeData[] = {
     {XFA_Attribute::Id, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Name, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Use, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Usehref, XFA_AttributeType::CData, nullptr},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"wsdlAddress";
+};
 
 }  // namespace
 
@@ -28,9 +26,8 @@
                 XFA_XDPPACKET_ConnectionSet,
                 XFA_ObjectType::TextNode,
                 XFA_Element::WsdlAddress,
-                nullptr,
-                kAttributeData,
-                kName,
-                pdfium::MakeUnique<CJX_WsdlAddress>(this)) {}
+                {},
+                kWsdlAddressAttributeData,
+                pdfium::MakeUnique<CJX_TextNode>(this)) {}
 
-CXFA_WsdlAddress::~CXFA_WsdlAddress() {}
+CXFA_WsdlAddress::~CXFA_WsdlAddress() = default;
diff --git a/xfa/fxfa/parser/cxfa_wsdladdress.h b/xfa/fxfa/parser/cxfa_wsdladdress.h
index 83c965c..e65bd6f 100644
--- a/xfa/fxfa/parser/cxfa_wsdladdress.h
+++ b/xfa/fxfa/parser/cxfa_wsdladdress.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_WsdlAddress : public CXFA_Node {
+class CXFA_WsdlAddress final : public CXFA_Node {
  public:
   CXFA_WsdlAddress(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_WsdlAddress() override;
diff --git a/xfa/fxfa/parser/cxfa_wsdlconnection.cpp b/xfa/fxfa/parser/cxfa_wsdlconnection.cpp
index 6159f49..188255f 100644
--- a/xfa/fxfa/parser/cxfa_wsdlconnection.cpp
+++ b/xfa/fxfa/parser/cxfa_wsdlconnection.cpp
@@ -11,20 +11,19 @@
 
 namespace {
 
-const CXFA_Node::PropertyData kPropertyData[] = {
+const CXFA_Node::PropertyData kWsdlConnectionPropertyData[] = {
     {XFA_Element::Operation, 1, 0},
     {XFA_Element::WsdlAddress, 1, 0},
     {XFA_Element::SoapAddress, 1, 0},
     {XFA_Element::SoapAction, 1, 0},
     {XFA_Element::EffectiveOutputPolicy, 1, 0},
     {XFA_Element::EffectiveInputPolicy, 1, 0},
-    {XFA_Element::Unknown, 0, 0}};
-const CXFA_Node::AttributeData kAttributeData[] = {
+};
+
+const CXFA_Node::AttributeData kWsdlConnectionAttributeData[] = {
     {XFA_Attribute::Name, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::DataDescription, XFA_AttributeType::CData, nullptr},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"wsdlConnection";
+};
 
 }  // namespace
 
@@ -35,9 +34,8 @@
                 XFA_XDPPACKET_ConnectionSet,
                 XFA_ObjectType::Node,
                 XFA_Element::WsdlConnection,
-                kPropertyData,
-                kAttributeData,
-                kName,
+                kWsdlConnectionPropertyData,
+                kWsdlConnectionAttributeData,
                 pdfium::MakeUnique<CJX_WsdlConnection>(this)) {}
 
-CXFA_WsdlConnection::~CXFA_WsdlConnection() {}
+CXFA_WsdlConnection::~CXFA_WsdlConnection() = default;
diff --git a/xfa/fxfa/parser/cxfa_wsdlconnection.h b/xfa/fxfa/parser/cxfa_wsdlconnection.h
index 6c349cf..b2238fd 100644
--- a/xfa/fxfa/parser/cxfa_wsdlconnection.h
+++ b/xfa/fxfa/parser/cxfa_wsdlconnection.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_WsdlConnection : public CXFA_Node {
+class CXFA_WsdlConnection final : public CXFA_Node {
  public:
   CXFA_WsdlConnection(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_WsdlConnection() override;
diff --git a/xfa/fxfa/parser/cxfa_xdc.cpp b/xfa/fxfa/parser/cxfa_xdc.cpp
index daaebc8..84198da 100644
--- a/xfa/fxfa/parser/cxfa_xdc.cpp
+++ b/xfa/fxfa/parser/cxfa_xdc.cpp
@@ -6,17 +6,20 @@
 
 #include "xfa/fxfa/parser/cxfa_xdc.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::PropertyData kPropertyData[] = {{XFA_Element::Uri, 1, 0},
-                                                 {XFA_Element::Xsl, 1, 0},
-                                                 {XFA_Element::Unknown, 0, 0}};
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::PropertyData kXdcPropertyData[] = {
+    {XFA_Element::Uri, 1, 0},
+    {XFA_Element::Xsl, 1, 0},
+};
+
+const CXFA_Node::AttributeData kXdcAttributeData[] = {
     {XFA_Attribute::Desc, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Lock, XFA_AttributeType::Integer, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"xdc";
+};
 
 }  // namespace
 
@@ -26,8 +29,8 @@
                 (XFA_XDPPACKET_Config | XFA_XDPPACKET_Xdc),
                 XFA_ObjectType::ModelNode,
                 XFA_Element::Xdc,
-                kPropertyData,
-                kAttributeData,
-                kName) {}
+                kXdcPropertyData,
+                kXdcAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_Xdc::~CXFA_Xdc() {}
+CXFA_Xdc::~CXFA_Xdc() = default;
diff --git a/xfa/fxfa/parser/cxfa_xdc.h b/xfa/fxfa/parser/cxfa_xdc.h
index 0eb43d5..81cbb57 100644
--- a/xfa/fxfa/parser/cxfa_xdc.h
+++ b/xfa/fxfa/parser/cxfa_xdc.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Xdc : public CXFA_Node {
+class CXFA_Xdc final : public CXFA_Node {
  public:
   CXFA_Xdc(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Xdc() override;
diff --git a/xfa/fxfa/parser/cxfa_xdp.cpp b/xfa/fxfa/parser/cxfa_xdp.cpp
index f100ae8..f3dc76c 100644
--- a/xfa/fxfa/parser/cxfa_xdp.cpp
+++ b/xfa/fxfa/parser/cxfa_xdp.cpp
@@ -6,16 +6,19 @@
 
 #include "xfa/fxfa/parser/cxfa_xdp.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::PropertyData kPropertyData[] = {{XFA_Element::Packets, 1, 0},
-                                                 {XFA_Element::Unknown, 0, 0}};
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::PropertyData kXdpPropertyData[] = {
+    {XFA_Element::Packets, 1, 0},
+};
+
+const CXFA_Node::AttributeData kXdpAttributeData[] = {
     {XFA_Attribute::Desc, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Lock, XFA_AttributeType::Integer, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"xdp";
+};
 
 }  // namespace
 
@@ -25,8 +28,8 @@
                 XFA_XDPPACKET_Config,
                 XFA_ObjectType::Node,
                 XFA_Element::Xdp,
-                kPropertyData,
-                kAttributeData,
-                kName) {}
+                kXdpPropertyData,
+                kXdpAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_Xdp::~CXFA_Xdp() {}
+CXFA_Xdp::~CXFA_Xdp() = default;
diff --git a/xfa/fxfa/parser/cxfa_xdp.h b/xfa/fxfa/parser/cxfa_xdp.h
index 38b450e..16ad5d8 100644
--- a/xfa/fxfa/parser/cxfa_xdp.h
+++ b/xfa/fxfa/parser/cxfa_xdp.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Xdp : public CXFA_Node {
+class CXFA_Xdp final : public CXFA_Node {
  public:
   CXFA_Xdp(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Xdp() override;
diff --git a/xfa/fxfa/parser/cxfa_xfa.cpp b/xfa/fxfa/parser/cxfa_xfa.cpp
index 7eab898..22fdd35 100644
--- a/xfa/fxfa/parser/cxfa_xfa.cpp
+++ b/xfa/fxfa/parser/cxfa_xfa.cpp
@@ -11,12 +11,10 @@
 
 namespace {
 
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::AttributeData kXfaAttributeData[] = {
     {XFA_Attribute::TimeStamp, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Uuid, XFA_AttributeType::CData, nullptr},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"xfa";
+};
 
 }  // namespace
 
@@ -26,9 +24,8 @@
                 XFA_XDPPACKET_XDP,
                 XFA_ObjectType::ModelNode,
                 XFA_Element::Xfa,
-                nullptr,
-                kAttributeData,
-                kName,
+                {},
+                kXfaAttributeData,
                 pdfium::MakeUnique<CJX_Xfa>(this)) {}
 
-CXFA_Xfa::~CXFA_Xfa() {}
+CXFA_Xfa::~CXFA_Xfa() = default;
diff --git a/xfa/fxfa/parser/cxfa_xfa.h b/xfa/fxfa/parser/cxfa_xfa.h
index 137b601..d7d33df 100644
--- a/xfa/fxfa/parser/cxfa_xfa.h
+++ b/xfa/fxfa/parser/cxfa_xfa.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Xfa : public CXFA_Node {
+class CXFA_Xfa final : public CXFA_Node {
  public:
   CXFA_Xfa(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Xfa() override;
diff --git a/xfa/fxfa/parser/cxfa_xmlconnection.cpp b/xfa/fxfa/parser/cxfa_xmlconnection.cpp
index df05771..17be7bc 100644
--- a/xfa/fxfa/parser/cxfa_xmlconnection.cpp
+++ b/xfa/fxfa/parser/cxfa_xmlconnection.cpp
@@ -6,19 +6,19 @@
 
 #include "xfa/fxfa/parser/cxfa_xmlconnection.h"
 
-#include "fxjs/xfa/cjx_xmlconnection.h"
+#include "fxjs/xfa/cjx_node.h"
 #include "third_party/base/ptr_util.h"
 
 namespace {
 
-const CXFA_Node::PropertyData kPropertyData[] = {{XFA_Element::Uri, 1, 0},
-                                                 {XFA_Element::Unknown, 0, 0}};
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::PropertyData kXmlConnectionPropertyData[] = {
+    {XFA_Element::Uri, 1, 0},
+};
+
+const CXFA_Node::AttributeData kXmlConnectionAttributeData[] = {
     {XFA_Attribute::Name, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::DataDescription, XFA_AttributeType::CData, nullptr},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"xmlConnection";
+};
 
 }  // namespace
 
@@ -29,9 +29,8 @@
                 XFA_XDPPACKET_ConnectionSet,
                 XFA_ObjectType::Node,
                 XFA_Element::XmlConnection,
-                kPropertyData,
-                kAttributeData,
-                kName,
-                pdfium::MakeUnique<CJX_XmlConnection>(this)) {}
+                kXmlConnectionPropertyData,
+                kXmlConnectionAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_XmlConnection::~CXFA_XmlConnection() {}
+CXFA_XmlConnection::~CXFA_XmlConnection() = default;
diff --git a/xfa/fxfa/parser/cxfa_xmlconnection.h b/xfa/fxfa/parser/cxfa_xmlconnection.h
index f9158c6..33cc038 100644
--- a/xfa/fxfa/parser/cxfa_xmlconnection.h
+++ b/xfa/fxfa/parser/cxfa_xmlconnection.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_XmlConnection : public CXFA_Node {
+class CXFA_XmlConnection final : public CXFA_Node {
  public:
   CXFA_XmlConnection(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_XmlConnection() override;
diff --git a/xfa/fxfa/parser/cxfa_xmllocale.cpp b/xfa/fxfa/parser/cxfa_xmllocale.cpp
index 659c7bb..c7a6f47 100644
--- a/xfa/fxfa/parser/cxfa_xmllocale.cpp
+++ b/xfa/fxfa/parser/cxfa_xmllocale.cpp
@@ -8,94 +8,109 @@
 
 #include <utility>
 
-#include "core/fxcrt/xml/cxml_content.h"
-#include "core/fxcrt/xml/cxml_element.h"
+#include "core/fxcrt/cfx_readonlymemorystream.h"
+#include "core/fxcrt/fx_codepage.h"
+#include "core/fxcrt/xml/cfx_xmldocument.h"
+#include "core/fxcrt/xml/cfx_xmlelement.h"
+#include "core/fxcrt/xml/cfx_xmlparser.h"
+#include "third_party/base/ptr_util.h"
 #include "xfa/fxfa/parser/cxfa_document.h"
 #include "xfa/fxfa/parser/cxfa_localemgr.h"
 #include "xfa/fxfa/parser/cxfa_nodelocale.h"
 #include "xfa/fxfa/parser/cxfa_timezoneprovider.h"
 #include "xfa/fxfa/parser/xfa_utils.h"
 
-CXFA_XMLLocale::CXFA_XMLLocale(std::unique_ptr<CXML_Element> pLocaleData)
-    : m_pLocaleData(std::move(pLocaleData)) {}
+namespace {
+
+constexpr wchar_t kNumberSymbols[] = L"numberSymbols";
+constexpr wchar_t kNumberSymbol[] = L"numberSymbol";
+constexpr wchar_t kCurrencySymbols[] = L"currencySymbols";
+constexpr wchar_t kCurrencySymbol[] = L"currencySymbol";
+
+}  // namespace
+
+// static
+std::unique_ptr<CXFA_XMLLocale> CXFA_XMLLocale::Create(
+    pdfium::span<uint8_t> data) {
+  auto stream = pdfium::MakeRetain<CFX_ReadOnlyMemoryStream>(data);
+  CFX_XMLParser parser(stream);
+  auto doc = parser.Parse();
+  if (!doc)
+    return nullptr;
+
+  CFX_XMLElement* locale = nullptr;
+  for (auto* child = doc->GetRoot()->GetFirstChild(); child;
+       child = child->GetNextSibling()) {
+    CFX_XMLElement* elem = ToXMLElement(child);
+    if (elem && elem->GetName().EqualsASCII("locale")) {
+      locale = elem;
+      break;
+    }
+  }
+  if (!locale)
+    return nullptr;
+
+  return pdfium::MakeUnique<CXFA_XMLLocale>(std::move(doc), locale);
+}
+
+CXFA_XMLLocale::CXFA_XMLLocale(std::unique_ptr<CFX_XMLDocument> doc,
+                               CFX_XMLElement* locale)
+    : xml_doc_(std::move(doc)), locale_(locale) {
+  ASSERT(xml_doc_);
+  ASSERT(locale_);
+}
 
 CXFA_XMLLocale::~CXFA_XMLLocale() {}
 
 WideString CXFA_XMLLocale::GetName() const {
-  return m_pLocaleData ? m_pLocaleData->GetAttrValue("name") : WideString();
+  return locale_->GetAttribute(L"name");
 }
 
-WideString CXFA_XMLLocale::GetNumbericSymbol(FX_LOCALENUMSYMBOL eType) const {
-  ByteString bsSymbols;
-  WideString wsName;
-  switch (eType) {
-    case FX_LOCALENUMSYMBOL_Decimal:
-      bsSymbols = "numberSymbols";
-      wsName = L"decimal";
-      break;
-    case FX_LOCALENUMSYMBOL_Grouping:
-      bsSymbols = "numberSymbols";
-      wsName = L"grouping";
-      break;
-    case FX_LOCALENUMSYMBOL_Percent:
-      bsSymbols = "numberSymbols";
-      wsName = L"percent";
-      break;
-    case FX_LOCALENUMSYMBOL_Minus:
-      bsSymbols = "numberSymbols";
-      wsName = L"minus";
-      break;
-    case FX_LOCALENUMSYMBOL_Zero:
-      bsSymbols = "numberSymbols";
-      wsName = L"zero";
-      break;
-    case FX_LOCALENUMSYMBOL_CurrencySymbol:
-      bsSymbols = "currencySymbols";
-      wsName = L"symbol";
-      break;
-    case FX_LOCALENUMSYMBOL_CurrencyName:
-      bsSymbols = "currencySymbols";
-      wsName = L"isoname";
-      break;
-    default:
-      return WideString();
-  }
-  CXML_Element* pElement =
-      m_pLocaleData->GetElement("", bsSymbols.AsStringView(), 0);
-  if (!pElement)
-    return WideString();
+WideString CXFA_XMLLocale::GetDecimalSymbol() const {
+  CFX_XMLElement* patterns = locale_->GetFirstChildNamed(kNumberSymbols);
+  return patterns ? GetPattern(patterns, kNumberSymbol, L"decimal")
+                  : WideString();
+}
 
-  return GetPattern(
-      pElement, ByteStringView(bsSymbols.c_str(), bsSymbols.GetLength() - 1),
-      wsName.AsStringView());
+WideString CXFA_XMLLocale::GetGroupingSymbol() const {
+  CFX_XMLElement* patterns = locale_->GetFirstChildNamed(kNumberSymbols);
+  return patterns ? GetPattern(patterns, kNumberSymbol, L"grouping")
+                  : WideString();
+}
+
+WideString CXFA_XMLLocale::GetPercentSymbol() const {
+  CFX_XMLElement* patterns = locale_->GetFirstChildNamed(kNumberSymbols);
+  return patterns ? GetPattern(patterns, kNumberSymbol, L"percent")
+                  : WideString();
+}
+
+WideString CXFA_XMLLocale::GetMinusSymbol() const {
+  CFX_XMLElement* patterns = locale_->GetFirstChildNamed(kNumberSymbols);
+  return patterns ? GetPattern(patterns, kNumberSymbol, L"minus")
+                  : WideString();
+}
+
+WideString CXFA_XMLLocale::GetCurrencySymbol() const {
+  CFX_XMLElement* patterns = locale_->GetFirstChildNamed(kCurrencySymbols);
+  return patterns ? GetPattern(patterns, kCurrencySymbol, L"symbol")
+                  : WideString();
 }
 
 WideString CXFA_XMLLocale::GetDateTimeSymbols() const {
-  if (!m_pLocaleData)
-    return WideString();
-
-  CXML_Element* pNumberSymbols =
-      m_pLocaleData->GetElement("", "dateTimeSymbols", 0);
-  if (!pNumberSymbols)
-    return WideString();
-
-  CXML_Content* pContent = ToContent(pNumberSymbols->GetChild(0));
-  if (!pContent)
-    return WideString();
-
-  return pContent->m_Content;
+  CFX_XMLElement* symbols = locale_->GetFirstChildNamed(L"dateTimeSymbols");
+  return symbols ? symbols->GetTextData() : WideString();
 }
 
 WideString CXFA_XMLLocale::GetMonthName(int32_t nMonth, bool bAbbr) const {
-  return GetCalendarSymbol("month", nMonth, bAbbr);
+  return GetCalendarSymbol(L"month", nMonth, bAbbr);
 }
 
 WideString CXFA_XMLLocale::GetDayName(int32_t nWeek, bool bAbbr) const {
-  return GetCalendarSymbol("day", nWeek, bAbbr);
+  return GetCalendarSymbol(L"day", nWeek, bAbbr);
 }
 
 WideString CXFA_XMLLocale::GetMeridiemName(bool bAM) const {
-  return GetCalendarSymbol("meridiem", bAM ? 0 : 1, false);
+  return GetCalendarSymbol(L"meridiem", bAM ? 0 : 1, false);
 }
 
 FX_TIMEZONE CXFA_XMLLocale::GetTimeZone() const {
@@ -103,43 +118,45 @@
 }
 
 WideString CXFA_XMLLocale::GetEraName(bool bAD) const {
-  return GetCalendarSymbol("era", bAD ? 1 : 0, false);
+  return GetCalendarSymbol(L"era", bAD ? 1 : 0, false);
 }
 
-WideString CXFA_XMLLocale::GetCalendarSymbol(const ByteStringView& symbol,
-                                             int index,
+WideString CXFA_XMLLocale::GetCalendarSymbol(WideStringView symbol,
+                                             size_t index,
                                              bool bAbbr) const {
-  if (index < 0 || !m_pLocaleData)
+  CFX_XMLElement* child = locale_->GetFirstChildNamed(L"calendarSymbols");
+  if (!child)
     return WideString();
 
-  CXML_Element* pChild = m_pLocaleData->GetElement("", "calendarSymbols", 0);
-  if (!pChild)
+  WideString pstrSymbolNames = symbol + L"Names";
+  CFX_XMLElement* name_child = nullptr;
+  for (auto* name = child->GetFirstChild(); name;
+       name = name->GetNextSibling()) {
+    CFX_XMLElement* elem = ToXMLElement(name);
+    if (!elem || elem->GetName() != pstrSymbolNames)
+      continue;
+
+    WideString abbr = elem->GetAttribute(L"abbr");
+    bool abbr_value = false;
+    if (!abbr.IsEmpty())
+      abbr_value = abbr.EqualsASCII("1");
+    if (abbr_value != bAbbr)
+      continue;
+
+    name_child = elem;
+    break;
+  }
+  if (!name_child)
     return WideString();
 
-  ByteString pstrSymbolNames = symbol + "Names";
-  CXML_Element* pSymbolNames =
-      pChild->GetElement("", pstrSymbolNames.AsStringView(), 0);
-  if (!pSymbolNames)
-    return WideString();
-
-  if ((!!pSymbolNames->GetAttrInteger("abbr")) != bAbbr)
-    pSymbolNames = pChild->GetElement("", pstrSymbolNames.AsStringView(), 1);
-
-  if (!pSymbolNames || (!!pSymbolNames->GetAttrInteger("abbr")) != bAbbr)
-    return WideString();
-
-  CXML_Element* pSymbolName = pSymbolNames->GetElement("", symbol, index);
-  if (!pSymbolName)
-    return WideString();
-
-  CXML_Content* pContent = ToContent(pSymbolName->GetChild(0));
-  return pContent ? pContent->m_Content : WideString();
+  CFX_XMLElement* sym_element = name_child->GetNthChildNamed(symbol, index);
+  return sym_element ? sym_element->GetTextData() : WideString();
 }
 
 WideString CXFA_XMLLocale::GetDatePattern(
     FX_LOCALEDATETIMESUBCATEGORY eType) const {
-  CXML_Element* pElement = m_pLocaleData->GetElement("", "datePatterns", 0);
-  if (!pElement)
+  CFX_XMLElement* patterns = locale_->GetFirstChildNamed(L"datePatterns");
+  if (!patterns)
     return WideString();
 
   WideString wsName;
@@ -158,13 +175,13 @@
       wsName = L"long";
       break;
   }
-  return GetPattern(pElement, "datePattern", wsName.AsStringView());
+  return GetPattern(patterns, L"datePattern", wsName.AsStringView());
 }
 
 WideString CXFA_XMLLocale::GetTimePattern(
     FX_LOCALEDATETIMESUBCATEGORY eType) const {
-  CXML_Element* pElement = m_pLocaleData->GetElement("", "timePatterns", 0);
-  if (!pElement)
+  CFX_XMLElement* patterns = locale_->GetFirstChildNamed(L"timePatterns");
+  if (!patterns)
     return WideString();
 
   WideString wsName;
@@ -183,24 +200,23 @@
       wsName = L"long";
       break;
   }
-  return GetPattern(pElement, "timePattern", wsName.AsStringView());
+  return GetPattern(patterns, L"timePattern", wsName.AsStringView());
 }
 
 WideString CXFA_XMLLocale::GetNumPattern(FX_LOCALENUMSUBCATEGORY eType) const {
-  return m_pLocaleData->GetElement("", "numberPatterns", 0)
-             ? XFA_PatternToString(eType)
-             : WideString();
+  CFX_XMLElement* patterns = locale_->GetFirstChildNamed(L"numberPatterns");
+  return patterns ? XFA_PatternToString(eType) : WideString();
 }
 
-WideString CXFA_XMLLocale::GetPattern(CXML_Element* pElement,
-                                      const ByteStringView& bsTag,
-                                      const WideStringView& wsName) const {
-  size_t iCount = pElement->CountElements("", bsTag);
-  for (size_t i = 0; i < iCount; i++) {
-    CXML_Element* pChild = pElement->GetElement("", bsTag, i);
-    if (pChild->GetAttrValue("name") == wsName) {
-      CXML_Content* pContent = ToContent(pChild->GetChild(0));
-      return pContent ? pContent->m_Content : WideString();
+WideString CXFA_XMLLocale::GetPattern(CFX_XMLElement* patterns,
+                                      WideStringView bsTag,
+                                      WideStringView wsName) const {
+  for (auto* child = patterns->GetFirstChild(); child;
+       child = child->GetNextSibling()) {
+    CFX_XMLElement* pattern = ToXMLElement(child);
+    if (pattern && pattern->GetName() == bsTag &&
+        pattern->GetAttribute(L"name") == wsName) {
+      return pattern->GetTextData();
     }
   }
   return WideString();
diff --git a/xfa/fxfa/parser/cxfa_xmllocale.h b/xfa/fxfa/parser/cxfa_xmllocale.h
index 5050855..472f774 100644
--- a/xfa/fxfa/parser/cxfa_xmllocale.h
+++ b/xfa/fxfa/parser/cxfa_xmllocale.h
@@ -9,19 +9,27 @@
 
 #include <memory>
 
-#include "core/fxcrt/ifx_locale.h"
+#include "third_party/base/span.h"
+#include "xfa/fgas/crt/locale_iface.h"
 
-class CXML_Element;
+class CFX_XMLDocument;
+class CFX_XMLElement;
 
-class CXFA_XMLLocale : public IFX_Locale {
+class CXFA_XMLLocale final : public LocaleIface {
  public:
-  explicit CXFA_XMLLocale(std::unique_ptr<CXML_Element> pLocaleData);
+  static std::unique_ptr<CXFA_XMLLocale> Create(pdfium::span<uint8_t> data);
+
+  explicit CXFA_XMLLocale(std::unique_ptr<CFX_XMLDocument> root,
+                          CFX_XMLElement* locale);
   ~CXFA_XMLLocale() override;
 
-  // IFX_Locale
+  // LocaleIface
   WideString GetName() const override;
-  WideString GetNumbericSymbol(FX_LOCALENUMSYMBOL eType) const override;
-
+  WideString GetDecimalSymbol() const override;
+  WideString GetGroupingSymbol() const override;
+  WideString GetPercentSymbol() const override;
+  WideString GetMinusSymbol() const override;
+  WideString GetCurrencySymbol() const override;
   WideString GetDateTimeSymbols() const override;
   WideString GetMonthName(int32_t nMonth, bool bAbbr) const override;
   WideString GetDayName(int32_t nWeek, bool bAbbr) const override;
@@ -34,14 +42,15 @@
   WideString GetNumPattern(FX_LOCALENUMSUBCATEGORY eType) const override;
 
  private:
-  WideString GetPattern(CXML_Element* pElement,
-                        const ByteStringView& bsTag,
-                        const WideStringView& wsName) const;
-  WideString GetCalendarSymbol(const ByteStringView& symbol,
-                               int index,
+  WideString GetPattern(CFX_XMLElement* pElement,
+                        WideStringView bsTag,
+                        WideStringView wsName) const;
+  WideString GetCalendarSymbol(WideStringView symbol,
+                               size_t index,
                                bool bAbbr) const;
 
-  std::unique_ptr<CXML_Element> m_pLocaleData;
+  std::unique_ptr<CFX_XMLDocument> xml_doc_;
+  UnownedPtr<CFX_XMLElement> locale_;
 };
 
 #endif  // XFA_FXFA_PARSER_CXFA_XMLLOCALE_H_
diff --git a/xfa/fxfa/parser/cxfa_xmllocale_unittest.cpp b/xfa/fxfa/parser/cxfa_xmllocale_unittest.cpp
new file mode 100644
index 0000000..395a360
--- /dev/null
+++ b/xfa/fxfa/parser/cxfa_xmllocale_unittest.cpp
@@ -0,0 +1,213 @@
+// Copyright 2018 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_xmllocale.h"
+
+#include <memory>
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+const char kXMLData[] =
+    "<locale name=\"en_US\" desc=\"English(America)\">"
+    "<calendarSymbols name=\"gregorian\"><monthNames><month>January</month>"
+    "<month>February</month>"
+    "<month>March</month>"
+    "<month>April</month>"
+    "<month>May</month>"
+    "<month>June</month>"
+    "<month>July</month>"
+    "<month>August</month>"
+    "<month>September</month>"
+    "<month>October</month>"
+    "<month>November</month>"
+    "<month>December</month>"
+    "</monthNames>"
+    "<monthNames abbr=\"1\"><month>Jan</month>"
+    "<month>Feb</month>"
+    "<month>Mar</month>"
+    "<month>Apr</month>"
+    "<month>May</month>"
+    "<month>Jun</month>"
+    "<month>Jul</month>"
+    "<month>Aug</month>"
+    "<month>Sep</month>"
+    "<month>Oct</month>"
+    "<month>Nov</month>"
+    "<month>Dec</month>"
+    "</monthNames>"
+    "<dayNames><day>Sunday</day>"
+    "<day>Monday</day>"
+    "<day>Tuesday</day>"
+    "<day>Wednesday</day>"
+    "<day>Thursday</day>"
+    "<day>Friday</day>"
+    "<day>Saturday</day>"
+    "</dayNames>"
+    "<dayNames abbr=\"1\"><day>Sun</day>"
+    "<day>Mon</day>"
+    "<day>Tue</day>"
+    "<day>Wed</day>"
+    "<day>Thu</day>"
+    "<day>Fri</day>"
+    "<day>Sat</day>"
+    "</dayNames>"
+    "<meridiemNames><meridiem>AM</meridiem>"
+    "<meridiem>PM</meridiem>"
+    "</meridiemNames>"
+    "<eraNames><era>BC</era>"
+    "<era>AD</era>"
+    "</eraNames>"
+    "</calendarSymbols>"
+    "<datePatterns><datePattern name=\"full\">EEEE, MMMM D, YYYY</datePattern>"
+    "<datePattern name=\"long\">MMMM D, YYYY</datePattern>"
+    "<datePattern name=\"med\">MMM D, YYYY</datePattern>"
+    "<datePattern name=\"short\">M/D/YY</datePattern>"
+    "</datePatterns>"
+    "<timePatterns><timePattern name=\"full\">h:MM:SS A Z</timePattern>"
+    "<timePattern name=\"long\">h:MM:SS A Z</timePattern>"
+    "<timePattern name=\"med\">h:MM:SS A</timePattern>"
+    "<timePattern name=\"short\">h:MM A</timePattern>"
+    "</timePatterns>"
+    "<dateTimeSymbols>GyMdkHmsSEDFwWahKzZ</dateTimeSymbols>"
+    "<numberPatterns><numberPattern name=\"numeric\">z,zz9.zzz</numberPattern>"
+    "<numberPattern name=\"currency\">$z,zz9.99|($z,zz9.99)</numberPattern>"
+    "<numberPattern name=\"percent\">z,zz9%</numberPattern>"
+    "</numberPatterns>"
+    "<numberSymbols><numberSymbol name=\"decimal\">.</numberSymbol>"
+    "<numberSymbol name=\"grouping\">,</numberSymbol>"
+    "<numberSymbol name=\"percent\">%</numberSymbol>"
+    "<numberSymbol name=\"minus\">-</numberSymbol>"
+    "<numberSymbol name=\"zero\">0</numberSymbol>"
+    "</numberSymbols>"
+    "<currencySymbols><currencySymbol name=\"symbol\">$</currencySymbol>"
+    "<currencySymbol name=\"isoname\">USD</currencySymbol>"
+    "<currencySymbol name=\"decimal\">.</currencySymbol>"
+    "</currencySymbols>"
+    "</locale>";
+
+std::unique_ptr<CXFA_XMLLocale> CreateLocaleHelper() {
+  return CXFA_XMLLocale::Create(pdfium::as_writable_bytes(
+      pdfium::make_span(const_cast<char*>(kXMLData), strlen(kXMLData))));
+}
+
+}  // namespace
+
+TEST(CXFA_XMLLocaleTest, Create) {
+  auto locale = CreateLocaleHelper();
+  EXPECT_TRUE(locale != nullptr);
+}
+
+TEST(CXFA_XMLLocaleTest, CreateBadXML) {
+  auto locale = CXFA_XMLLocale::Create(pdfium::span<uint8_t>());
+  EXPECT_TRUE(locale == nullptr);
+}
+
+TEST(CXFA_XMLLocaleTest, GetName) {
+  auto locale = CreateLocaleHelper();
+  ASSERT_TRUE(locale != nullptr);
+
+  EXPECT_EQ(L"en_US", locale->GetName());
+}
+
+TEST(CXFA_XMLLocaleTest, GetNumericSymbols) {
+  auto locale = CreateLocaleHelper();
+  ASSERT_TRUE(locale != nullptr);
+
+  EXPECT_EQ(L".", locale->GetDecimalSymbol());
+  EXPECT_EQ(L",", locale->GetGroupingSymbol());
+  EXPECT_EQ(L"%", locale->GetPercentSymbol());
+  EXPECT_EQ(L"-", locale->GetMinusSymbol());
+  EXPECT_EQ(L"$", locale->GetCurrencySymbol());
+}
+
+TEST(CXFA_XMLLocaleTest, GetDateTimeSymbols) {
+  auto locale = CreateLocaleHelper();
+  ASSERT_TRUE(locale != nullptr);
+
+  EXPECT_EQ(L"GyMdkHmsSEDFwWahKzZ", locale->GetDateTimeSymbols());
+}
+
+TEST(CXFA_XMLLocaleTest, GetMonthName) {
+  auto locale = CreateLocaleHelper();
+  ASSERT_TRUE(locale != nullptr);
+
+  EXPECT_EQ(L"", locale->GetMonthName(24, false));
+  EXPECT_EQ(L"", locale->GetMonthName(-5, false));
+  EXPECT_EQ(L"Feb", locale->GetMonthName(1, true));
+  EXPECT_EQ(L"February", locale->GetMonthName(1, false));
+}
+
+TEST(CXFA_XMLLocaleTest, GetDayName) {
+  auto locale = CreateLocaleHelper();
+  ASSERT_TRUE(locale != nullptr);
+
+  EXPECT_EQ(L"", locale->GetDayName(24, false));
+  EXPECT_EQ(L"", locale->GetDayName(-5, false));
+  EXPECT_EQ(L"Mon", locale->GetDayName(1, true));
+  EXPECT_EQ(L"Monday", locale->GetDayName(1, false));
+}
+
+TEST(CXFA_XMLLocaleTest, GetMeridiemName) {
+  auto locale = CreateLocaleHelper();
+  ASSERT_TRUE(locale != nullptr);
+
+  EXPECT_EQ(L"AM", locale->GetMeridiemName(true));
+  EXPECT_EQ(L"PM", locale->GetMeridiemName(false));
+}
+
+TEST(CXFA_XMLLocaleTest, GetEraName) {
+  auto locale = CreateLocaleHelper();
+  ASSERT_TRUE(locale != nullptr);
+
+  EXPECT_EQ(L"AD", locale->GetEraName(true));
+  EXPECT_EQ(L"BC", locale->GetEraName(false));
+}
+
+TEST(CXFA_XMLLocaleTest, GetDatePattern) {
+  auto locale = CreateLocaleHelper();
+  ASSERT_TRUE(locale != nullptr);
+
+  EXPECT_EQ(L"M/D/YY",
+            locale->GetDatePattern(FX_LOCALEDATETIMESUBCATEGORY_Short));
+  EXPECT_EQ(L"MMM D, YYYY",
+            locale->GetDatePattern(FX_LOCALEDATETIMESUBCATEGORY_Default));
+  EXPECT_EQ(L"MMM D, YYYY",
+            locale->GetDatePattern(FX_LOCALEDATETIMESUBCATEGORY_Medium));
+  EXPECT_EQ(L"EEEE, MMMM D, YYYY",
+            locale->GetDatePattern(FX_LOCALEDATETIMESUBCATEGORY_Full));
+  EXPECT_EQ(L"MMMM D, YYYY",
+            locale->GetDatePattern(FX_LOCALEDATETIMESUBCATEGORY_Long));
+}
+
+TEST(CXFA_XMLLocaleTest, GetTimePattern) {
+  auto locale = CreateLocaleHelper();
+  ASSERT_TRUE(locale != nullptr);
+
+  EXPECT_EQ(L"h:MM A",
+            locale->GetTimePattern(FX_LOCALEDATETIMESUBCATEGORY_Short));
+  EXPECT_EQ(L"h:MM:SS A",
+            locale->GetTimePattern(FX_LOCALEDATETIMESUBCATEGORY_Default));
+  EXPECT_EQ(L"h:MM:SS A",
+            locale->GetTimePattern(FX_LOCALEDATETIMESUBCATEGORY_Medium));
+  EXPECT_EQ(L"h:MM:SS A Z",
+            locale->GetTimePattern(FX_LOCALEDATETIMESUBCATEGORY_Full));
+  EXPECT_EQ(L"h:MM:SS A Z",
+            locale->GetTimePattern(FX_LOCALEDATETIMESUBCATEGORY_Long));
+}
+
+TEST(CXFA_XMLLocaleTest, GetNumPattern) {
+  auto locale = CreateLocaleHelper();
+  ASSERT_TRUE(locale != nullptr);
+
+  EXPECT_EQ(L"z,zzz,zzz,zzz,zzz,zzz%",
+            locale->GetNumPattern(FX_LOCALENUMPATTERN_Percent));
+  EXPECT_EQ(L"$z,zzz,zzz,zzz,zzz,zz9.99",
+            locale->GetNumPattern(FX_LOCALENUMPATTERN_Currency));
+  EXPECT_EQ(L"z,zzz,zzz,zzz,zzz,zz9.zzz",
+            locale->GetNumPattern(FX_LOCALENUMPATTERN_Decimal));
+  EXPECT_EQ(L"z,zzz,zzz,zzz,zzz,zzz",
+            locale->GetNumPattern(FX_LOCALENUMPATTERN_Integer));
+}
diff --git a/xfa/fxfa/parser/cxfa_xsdconnection.cpp b/xfa/fxfa/parser/cxfa_xsdconnection.cpp
index 7b0de0d..1973870 100644
--- a/xfa/fxfa/parser/cxfa_xsdconnection.cpp
+++ b/xfa/fxfa/parser/cxfa_xsdconnection.cpp
@@ -6,21 +6,20 @@
 
 #include "xfa/fxfa/parser/cxfa_xsdconnection.h"
 
-#include "fxjs/xfa/cjx_xsdconnection.h"
+#include "fxjs/xfa/cjx_node.h"
 #include "third_party/base/ptr_util.h"
 
 namespace {
 
-const CXFA_Node::PropertyData kPropertyData[] = {
+const CXFA_Node::PropertyData kXsdConnectionPropertyData[] = {
     {XFA_Element::Uri, 1, 0},
     {XFA_Element::RootElement, 1, 0},
-    {XFA_Element::Unknown, 0, 0}};
-const CXFA_Node::AttributeData kAttributeData[] = {
+};
+
+const CXFA_Node::AttributeData kXsdConnectionAttributeData[] = {
     {XFA_Attribute::Name, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::DataDescription, XFA_AttributeType::CData, nullptr},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"xsdConnection";
+};
 
 }  // namespace
 
@@ -31,9 +30,8 @@
                 XFA_XDPPACKET_ConnectionSet,
                 XFA_ObjectType::Node,
                 XFA_Element::XsdConnection,
-                kPropertyData,
-                kAttributeData,
-                kName,
-                pdfium::MakeUnique<CJX_XsdConnection>(this)) {}
+                kXsdConnectionPropertyData,
+                kXsdConnectionAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_XsdConnection::~CXFA_XsdConnection() {}
+CXFA_XsdConnection::~CXFA_XsdConnection() = default;
diff --git a/xfa/fxfa/parser/cxfa_xsdconnection.h b/xfa/fxfa/parser/cxfa_xsdconnection.h
index 652d45e..8cdef80 100644
--- a/xfa/fxfa/parser/cxfa_xsdconnection.h
+++ b/xfa/fxfa/parser/cxfa_xsdconnection.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_XsdConnection : public CXFA_Node {
+class CXFA_XsdConnection final : public CXFA_Node {
  public:
   CXFA_XsdConnection(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_XsdConnection() override;
diff --git a/xfa/fxfa/parser/cxfa_xsl.cpp b/xfa/fxfa/parser/cxfa_xsl.cpp
index 4d5e71e..2db4bdc 100644
--- a/xfa/fxfa/parser/cxfa_xsl.cpp
+++ b/xfa/fxfa/parser/cxfa_xsl.cpp
@@ -6,17 +6,20 @@
 
 #include "xfa/fxfa/parser/cxfa_xsl.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::PropertyData kPropertyData[] = {{XFA_Element::Uri, 1, 0},
-                                                 {XFA_Element::Debug, 1, 0},
-                                                 {XFA_Element::Unknown, 0, 0}};
-const CXFA_Node::AttributeData kAttributeData[] = {
+const CXFA_Node::PropertyData kXslPropertyData[] = {
+    {XFA_Element::Uri, 1, 0},
+    {XFA_Element::Debug, 1, 0},
+};
+
+const CXFA_Node::AttributeData kXslAttributeData[] = {
     {XFA_Attribute::Desc, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Lock, XFA_AttributeType::Integer, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"xsl";
+};
 
 }  // namespace
 
@@ -26,8 +29,8 @@
                 XFA_XDPPACKET_Config,
                 XFA_ObjectType::Node,
                 XFA_Element::Xsl,
-                kPropertyData,
-                kAttributeData,
-                kName) {}
+                kXslPropertyData,
+                kXslAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_Xsl::~CXFA_Xsl() {}
+CXFA_Xsl::~CXFA_Xsl() = default;
diff --git a/xfa/fxfa/parser/cxfa_xsl.h b/xfa/fxfa/parser/cxfa_xsl.h
index d921125..1be8d4b 100644
--- a/xfa/fxfa/parser/cxfa_xsl.h
+++ b/xfa/fxfa/parser/cxfa_xsl.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Xsl : public CXFA_Node {
+class CXFA_Xsl final : public CXFA_Node {
  public:
   CXFA_Xsl(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Xsl() override;
diff --git a/xfa/fxfa/parser/cxfa_zpl.cpp b/xfa/fxfa/parser/cxfa_zpl.cpp
index aa078b5..aa9db61 100644
--- a/xfa/fxfa/parser/cxfa_zpl.cpp
+++ b/xfa/fxfa/parser/cxfa_zpl.cpp
@@ -6,21 +6,23 @@
 
 #include "xfa/fxfa/parser/cxfa_zpl.h"
 
+#include "fxjs/xfa/cjx_node.h"
+#include "third_party/base/ptr_util.h"
+
 namespace {
 
-const CXFA_Node::PropertyData kPropertyData[] = {
+const CXFA_Node::PropertyData kZplPropertyData[] = {
     {XFA_Element::FontInfo, 1, 0},
     {XFA_Element::Xdc, 1, 0},
     {XFA_Element::BatchOutput, 1, 0},
     {XFA_Element::FlipLabel, 1, 0},
-    {XFA_Element::Unknown, 0, 0}};
-const CXFA_Node::AttributeData kAttributeData[] = {
+};
+
+const CXFA_Node::AttributeData kZplAttributeData[] = {
     {XFA_Attribute::Name, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Desc, XFA_AttributeType::CData, nullptr},
     {XFA_Attribute::Lock, XFA_AttributeType::Integer, (void*)0},
-    {XFA_Attribute::Unknown, XFA_AttributeType::Integer, nullptr}};
-
-constexpr wchar_t kName[] = L"zpl";
+};
 
 }  // namespace
 
@@ -30,8 +32,8 @@
                 XFA_XDPPACKET_Config,
                 XFA_ObjectType::Node,
                 XFA_Element::Zpl,
-                kPropertyData,
-                kAttributeData,
-                kName) {}
+                kZplPropertyData,
+                kZplAttributeData,
+                pdfium::MakeUnique<CJX_Node>(this)) {}
 
-CXFA_Zpl::~CXFA_Zpl() {}
+CXFA_Zpl::~CXFA_Zpl() = default;
diff --git a/xfa/fxfa/parser/cxfa_zpl.h b/xfa/fxfa/parser/cxfa_zpl.h
index ee8f925..6433015 100644
--- a/xfa/fxfa/parser/cxfa_zpl.h
+++ b/xfa/fxfa/parser/cxfa_zpl.h
@@ -9,7 +9,7 @@
 
 #include "xfa/fxfa/parser/cxfa_node.h"
 
-class CXFA_Zpl : public CXFA_Node {
+class CXFA_Zpl final : public CXFA_Node {
  public:
   CXFA_Zpl(CXFA_Document* doc, XFA_PacketType packet);
   ~CXFA_Zpl() override;
diff --git a/xfa/fxfa/parser/element_attributes.inc b/xfa/fxfa/parser/element_attributes.inc
new file mode 100644
index 0000000..c8bfc60
--- /dev/null
+++ b/xfa/fxfa/parser/element_attributes.inc
@@ -0,0 +1,552 @@
+// Copyright 2018 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
+
+ELEM_ATTR____(RecordSet, Max, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(RecordSet, EofAction, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(RecordSet, CursorType, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(RecordSet, LockType, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(RecordSet, BofAction, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(RecordSet, CursorLocation, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(SubformSet, InstanceIndex, CJX_Object::ScriptSomInstanceIndex)
+ELEM_ATTR____(SubformSet, Relation, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(SubformSet, Relevant, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Typeface, Name, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Break, BeforeTarget, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Break, OverflowTarget, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Break, OverflowLeader, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Break, OverflowTrailer, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Break, StartNew, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Break, BookendTrailer, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Break, After, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Break, BookendLeader, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Break, AfterTarget, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Break, Before, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(NumberPattern, Name, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(DynamicRender, Value, CJX_Object::ScriptSomDefaultValue_Read)
+ELEM_ATTR____(CheckButton, AllowNeutral, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(CheckButton, Mark, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(CheckButton, Shape, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(CheckButton, Size, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(SourceSet, Use, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(SourceSet, Usehref, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Arc, StartAngle, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Arc, SweepAngle, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Arc, Circular, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Arc, Hand, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Map, Bind, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Map, Desc, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Map, From, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Map, Lock, CJX_Object::ScriptAttributeBool)
+ELEM_ATTR____(Mdp, SignatureType, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Mdp, Permissions, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(BreakBefore, StartNew, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(BreakBefore, Trailer, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(BreakBefore, TargetType, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(BreakBefore, Target, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(BreakBefore, Leader, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Pcl, Name, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Pdf, Name, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Uri, Desc, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Uri, Lock, CJX_Object::ScriptAttributeBool)
+ELEM_ATTR____(Xfa, ThisValue, CJX_Xfa::thisValue)
+ELEM_ATTR____(Xfa, TimeStamp, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Xfa, Uuid, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Zpl, Name, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Margin, LeftInset, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Margin, BottomInset, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Margin, TopInset, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Margin, RightInset, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(KeyUsage, NonRepudiation, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(KeyUsage, EncipherOnly, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(KeyUsage, Type, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(KeyUsage, DigitalSignature, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(KeyUsage, CrlSign, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(KeyUsage, KeyAgreement, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(KeyUsage, KeyEncipherment, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(KeyUsage, DataEncipherment, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(KeyUsage, KeyCertSign, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(KeyUsage, DecipherOnly, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(ChoiceList, Open, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(ChoiceList, CommitOn, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(ChoiceList, TextEntry, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(LabelPrinter, Name, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(CalendarSymbols, Name, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Para, HAlign, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Para, TextIndent, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Para, MarginRight, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Para, MarginLeft, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Para, RadixOffset, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Para, Preserve, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Para, SpaceBelow, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Para, VAlign, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Para, TabDefault, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Para, TabStops, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Para, LineHeight, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Para, SpaceAbove, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Part, Desc, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Part, Lock, CJX_Object::ScriptAttributeBool)
+ELEM_ATTR____(Filter, AddRevocationInfo, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Event, Ref, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Event, Activity, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Barcode, DataRowCount, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Barcode, DataPrep, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Barcode, Type, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Barcode, TextLocation, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Barcode, ModuleWidth, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Barcode, PrintCheckDigit, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Barcode, ModuleHeight, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Barcode, StartChar, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Barcode, Truncate, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Barcode, WideNarrowRatio, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Barcode, ErrorCorrectionLevel, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Barcode, UpsMode, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Barcode, Checksum, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Barcode, CharEncoding, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Barcode, DataColumnCount, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Barcode, RowColumnRatio, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Barcode, DataLength, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Barcode, EndChar, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(TimePattern, Name, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(BatchOutput, Format, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Operation, Output, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Operation, Input, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(SubjectDNs, Type, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Issuers, Type, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(WsdlConnection, DataDescription, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Delta, CurrentValue, CJX_Delta::currentValue)
+ELEM_ATTR____(Delta, SavedValue, CJX_Delta::savedValue)
+ELEM_ATTR____(Delta, Target, CJX_Delta::target)
+ELEM_ATTR____(Button, Highlight, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Border, Break, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Border, Presence, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Border, Relevant, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Border, Hand, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Area, X, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Area, Y, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Area, Id, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Area, Name, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Area, Level, CJX_Object::ScriptAttributeInteger)
+ELEM_ATTR____(Area, Relevant, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Area, ColSpan, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Area, Lock, CJX_Object::ScriptAttributeBool)
+ELEM_ATTR____(Hyphenation, Id, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Hyphenation, WordCharacterCount, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Hyphenation, Hyphenate, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Hyphenation, ExcludeInitialCap, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Hyphenation, PushCharacterCount, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Hyphenation, RemainCharacterCount, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Hyphenation, ExcludeAllCaps, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Text, MaxChars, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Text, DefaultValue, CJX_Object::ScriptSomDefaultValue)
+ELEM_ATTR____(Text, Value, CJX_Object::ScriptSomDefaultValue)
+ELEM_ATTR____(Time, DefaultValue, CJX_Object::ScriptSomDefaultValue)
+ELEM_ATTR____(Time, Value, CJX_Object::ScriptSomDefaultValue)
+ELEM_ATTR____(Certificates, Url, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Certificates, CredentialServerPolicy, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Certificates, UrlPolicy, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(EncryptionMethods, Type, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(SetProperty, Connection, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(SetProperty, Target, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(DateTime, DefaultValue, CJX_Object::ScriptSomDefaultValue)
+ELEM_ATTR____(DateTime, Value, CJX_Object::ScriptSomDefaultValue)
+ELEM_ATTR____(Comb, NumberOfCells, CJX_Object::ScriptAttributeInteger)
+ELEM_ATTR____(Pattern, Type, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Field, H, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Field, W, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Field, X, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Field, Y, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Field, HAlign, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Field, DataNode, CJX_Object::ScriptSomDataNode)
+ELEM_ATTR____(Field, Access, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Field, Rotate, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Field, FillColor, CJX_Object::ScriptSomFillColor)
+ELEM_ATTR____(Field, FormattedValue, CJX_Field::formattedValue)
+ELEM_ATTR____(Field, Presence, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Field, BorderColor, CJX_Object::ScriptSomBorderColor)
+ELEM_ATTR____(Field, FontColor, CJX_Object::ScriptSomFontColor)
+ELEM_ATTR____(Field, ParentSubform, CJX_Field::parentSubform)
+ELEM_ATTR____(Field, MandatoryMessage, CJX_Object::ScriptSomMandatoryMessage)
+ELEM_ATTR____(Field, VAlign, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Field, MaxH, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Field, MaxW, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Field, MinH, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Field, MinW, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Field, Mandatory, CJX_Object::ScriptSomMandatory)
+ELEM_ATTR____(Field, Relevant, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Field, FormatMessage, CJX_Field::formatMessage)
+ELEM_ATTR____(Field, RawValue, CJX_Field::rawValue)
+ELEM_ATTR____(Field, DefaultValue, CJX_Field::defaultValue)
+ELEM_ATTR____(Field, Length, CJX_Field::length)
+ELEM_ATTR____(Field, ColSpan, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Field, Locale, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Field, AnchorType, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Field, AccessKey, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Field, ValidationMessage, CJX_Object::ScriptSomValidationMessage)
+ELEM_ATTR____(Field, EditValue, CJX_Field::editValue)
+ELEM_ATTR____(Field, SelectedIndex, CJX_Field::selectedIndex)
+ELEM_ATTR____(Field, BorderWidth, CJX_Object::ScriptSomBorderWidth)
+ELEM_ATTR____(Agent, Name, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(ContentArea, H, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(ContentArea, W, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(ContentArea, X, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(ContentArea, Y, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(ContentArea, Relevant, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Edge, Cap, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Edge, Stroke, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Edge, Presence, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Edge, Thickness, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Stipple, Rate, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(VersionControl, SourceBelow, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(VersionControl, OutputBelow, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(VersionControl, SourceAbove, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(VersionControl, Lock, CJX_Object::ScriptAttributeBool)
+ELEM_ATTR____(ExclGroup, H, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(ExclGroup, W, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(ExclGroup, X, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(ExclGroup, Y, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(ExclGroup, HAlign, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(ExclGroup, ErrorText, CJX_ExclGroup::errorText)
+ELEM_ATTR____(ExclGroup, DataNode, CJX_Object::ScriptSomDataNode)
+ELEM_ATTR____(ExclGroup, Access, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(ExclGroup, FillColor, CJX_Object::ScriptSomFillColor)
+ELEM_ATTR____(ExclGroup, Presence, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(ExclGroup, BorderColor, CJX_Object::ScriptSomBorderColor)
+ELEM_ATTR____(ExclGroup, MandatoryMessage, CJX_Object::ScriptSomMandatoryMessage)
+ELEM_ATTR____(ExclGroup, VAlign, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(ExclGroup, MaxH, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(ExclGroup, MaxW, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(ExclGroup, MinH, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(ExclGroup, MinW, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(ExclGroup, Layout, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(ExclGroup, Transient, CJX_ExclGroup::transient)
+ELEM_ATTR____(ExclGroup, Mandatory, CJX_Object::ScriptSomMandatory)
+ELEM_ATTR____(ExclGroup, Relevant, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(ExclGroup, RawValue, CJX_ExclGroup::rawValue)
+ELEM_ATTR____(ExclGroup, DefaultValue, CJX_ExclGroup::defaultValue)
+ELEM_ATTR____(ExclGroup, ColSpan, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(ExclGroup, AnchorType, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(ExclGroup, AccessKey, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(ExclGroup, ValidationMessage, CJX_Object::ScriptSomValidationMessage)
+ELEM_ATTR____(ExclGroup, BorderWidth, CJX_Object::ScriptSomBorderWidth)
+ELEM_ATTR____(Compress, Scope, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Execute, Connection, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Execute, RunAt, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Execute, ExecuteType, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(DateTimeEdit, HScrollPolicy, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Image, ContentType, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Image, TransferEncoding, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Image, DefaultValue, CJX_Object::ScriptSomDefaultValue_Read)
+ELEM_ATTR____(Image, Aspect, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Image, Value, CJX_Object::ScriptSomDefaultValue_Read)
+ELEM_ATTR____(Image, Href, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(SharpxHTML, Value, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(TimeStamp, Type, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(TimeStamp, Server, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Decimal, FracDigits, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Decimal, DefaultValue, CJX_Object::ScriptSomDefaultValue)
+ELEM_ATTR____(Decimal, Value, CJX_Object::ScriptSomDefaultValue)
+ELEM_ATTR____(Decimal, LeadDigits, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Subform, H, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Subform, W, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Subform, X, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Subform, Y, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Subform, HAlign, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Subform, AllowMacro, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Subform, ColumnWidths, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Subform, DataNode, CJX_Object::ScriptSomDataNode)
+ELEM_ATTR____(Subform, InstanceIndex, CJX_Object::ScriptSomInstanceIndex)
+ELEM_ATTR____(Subform, Access, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Subform, FillColor, CJX_Object::ScriptSomFillColor)
+ELEM_ATTR____(Subform, Presence, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Subform, BorderColor, CJX_Object::ScriptSomBorderColor)
+ELEM_ATTR____(Subform, VAlign, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Subform, MaxH, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Subform, MaxW, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Subform, MinH, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Subform, MinW, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Subform, Layout, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Subform, Relevant, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Subform, MergeMode, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Subform, InstanceManager, CJX_Subform::instanceManager)
+ELEM_ATTR____(Subform, ColSpan, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Subform, Locale, CJX_Subform::locale)
+ELEM_ATTR____(Subform, AnchorType, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Subform, ValidationMessage, CJX_Object::ScriptSomValidationMessage)
+ELEM_ATTR____(Subform, RestoreState, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Subform, Scope, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Subform, BorderWidth, CJX_Object::ScriptSomBorderWidth)
+ELEM_ATTR____(Handler, Type, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Handler, Version, CJX_Handler::version)
+ELEM_ATTR____(Command, Timeout, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Staple, Mode, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(SubmitFormat, Mode, CJX_Object::ScriptSubmitFormatMode)
+ELEM_ATTR____(Boolean, DefaultValue, CJX_Boolean::defaultValue)
+ELEM_ATTR____(Boolean, Value, CJX_Boolean::value)
+ELEM_ATTR____(Message, Desc, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Message, Lock, CJX_Object::ScriptAttributeBool)
+ELEM_ATTR____(Assist, Role, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Picture, DefaultValue, CJX_Object::ScriptSomDefaultValue)
+ELEM_ATTR____(Picture, Desc, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Picture, Value, CJX_Object::ScriptSomDefaultValue)
+ELEM_ATTR____(Picture, Lock, CJX_Object::ScriptAttributeBool)
+ELEM_ATTR____(WebClient, Name, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Corner, Stroke, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Corner, Presence, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Corner, Inverted, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Corner, Thickness, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Corner, Join, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Corner, Radius, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Color, CSpace, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Color, Value, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Keep, Next, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Keep, Previous, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Keep, Intact, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Query, CommandType, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(ImageEdit, Data, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Validate, ScriptTest, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Validate, NullTest, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Validate, Desc, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Validate, FormatTest, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Validate, Lock, CJX_Object::ScriptAttributeBool)
+ELEM_ATTR____(DigestMethods, Type, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(PageSet, Relation, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(PageSet, Relevant, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Integer, DefaultValue, CJX_Object::ScriptSomDefaultValue)
+ELEM_ATTR____(Integer, Value, CJX_Object::ScriptSomDefaultValue)
+ELEM_ATTR____(Equate, To, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Equate, Force, CJX_Object::ScriptAttributeBool)
+ELEM_ATTR____(Equate, From, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Sharpxml, Value, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(XsdConnection, DataDescription, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Traverse, Ref, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Traverse, Operation, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Encodings, Type, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Template, Desc, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Template, Lock, CJX_Object::ScriptAttributeBool)
+ELEM_ATTR____(Signing, Type, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Script, ContentType, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Script, RunAt, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Script, Stateless, CJX_Script::stateless)
+ELEM_ATTR____(Script, DefaultValue, CJX_Object::ScriptSomDefaultValue)
+ELEM_ATTR____(Script, Binding, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Script, Desc, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Script, Value, CJX_Object::ScriptSomDefaultValue)
+ELEM_ATTR____(Script, Lock, CJX_Object::ScriptAttributeBool)
+ELEM_ATTR____(PasswordEdit, PasswordChar, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(PasswordEdit, HScrollPolicy, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(NumericEdit, HScrollPolicy, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(PageArea, PagePosition, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(PageArea, OddOrEven, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(PageArea, Relevant, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(PageArea, InitialNumber, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(PageArea, Numbered, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(PageArea, BlankOrNotBlank, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(SubmitUrl, Value, CJX_Object::ScriptSomDefaultValue)
+ELEM_ATTR____(Oids, Type, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Caption, Reserve, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Caption, Presence, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Caption, Placement, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(ExData, ContentType, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(ExData, TransferEncoding, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(ExData, DefaultValue, CJX_Object::ScriptSomDefaultValue)
+ELEM_ATTR____(ExData, MaxLength, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(ExData, Value, CJX_Object::ScriptSomDefaultValue)
+ELEM_ATTR____(ExData, Href, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(DayNames, Abbr, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(DefaultTypeface, WritingScript, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Manifest, Action, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Manifest, DefaultValue, CJX_Object::ScriptSomDefaultValue)
+ELEM_ATTR____(Overflow, Trailer, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Overflow, Target, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Overflow, Leader, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Linear, Type, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(CurrencySymbol, Name, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(InstanceManager, Max, CJX_InstanceManager::max)
+ELEM_ATTR____(InstanceManager, Min, CJX_InstanceManager::min)
+ELEM_ATTR____(InstanceManager, Count, CJX_InstanceManager::count)
+ELEM_ATTR____(EquateRange, To, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(EquateRange, UnicodeRange, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(EquateRange, From, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Medium, Orientation, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Medium, ImagingBBox, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Medium, Short, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Medium, Stock, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Medium, Long, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(TextEdit, VScrollPolicy, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(TextEdit, AllowRichText, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(TextEdit, MultiLine, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(TextEdit, HScrollPolicy, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(TemplateCache, MaxEntries, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(DataValue, ContentType, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(DataValue, Contains, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(DataValue, DefaultValue, CJX_Object::ScriptSomDefaultValue)
+ELEM_ATTR____(DataValue, Value, CJX_Object::ScriptSomDefaultValue)
+ELEM_ATTR____(DataValue, IsNull, CJX_Object::ScriptAttributeBool)
+ELEM_ATTR____(XmlConnection, DataDescription, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(SignData, Ref, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(SignData, Operation, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(SignData, Target, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(DatePattern, Name, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Bind, Ref, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Bind, ContentType, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Bind, TransferEncoding, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Bind, Match, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Rectangle, Hand, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(EffectiveOutputPolicy, Id, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(EffectiveOutputPolicy, Name, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Date, DefaultValue, CJX_Object::ScriptSomDefaultValue)
+ELEM_ATTR____(Date, Value, CJX_Object::ScriptSomDefaultValue)
+ELEM_ATTR____(Encrypt, Format, CJX_Encrypt::format)
+ELEM_ATTR____(Encrypt, Desc, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Encrypt, Lock, CJX_Object::ScriptAttributeBool)
+ELEM_ATTR____(Draw, H, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Draw, W, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Draw, X, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Draw, Y, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Draw, HAlign, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Draw, Rotate, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Draw, Presence, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Draw, VAlign, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Draw, MaxH, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Draw, MaxW, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Draw, MinH, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Draw, MinW, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Draw, Relevant, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Draw, RawValue, CJX_Draw::rawValue)
+ELEM_ATTR____(Draw, DefaultValue, CJX_Draw::defaultValue)
+ELEM_ATTR____(Draw, ColSpan, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Draw, Locale, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Draw, AnchorType, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Speak, Priority, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Speak, Disable, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Sharptext, Value, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Reasons, Type, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(AppearanceFilter, Id, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(AppearanceFilter, Type, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Fill, Presence, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Font, LineThrough, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Font, Typeface, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Font, FontHorizontalScale, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Font, KerningMode, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Font, Underline, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Font, BaselineShift, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Font, OverlinePeriod, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Font, LetterSpacing, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Font, LineThroughPeriod, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Font, FontVerticalScale, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Font, Size, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Font, Posture, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Font, Weight, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Font, UnderlinePeriod, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Font, Overline, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Form, Checksum, CJX_Form::checksumS)
+ELEM_ATTR____(Float, DefaultValue, CJX_Object::ScriptSomDefaultValue)
+ELEM_ATTR____(Float, Value, CJX_Object::ScriptSomDefaultValue)
+ELEM_ATTR____(Value, Relevant, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Value, Override, CJX_Object::ScriptAttributeBool)
+ELEM_ATTR____(Bookend, Trailer, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Bookend, Leader, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(ExObject, CodeType, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(ExObject, Archive, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(ExObject, CodeBase, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(ExObject, ClassId, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(BindItems, Connection, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(BindItems, LabelRef, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(BindItems, ValueRef, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Calculate, Override, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Extras, Type, CJX_Extras::type)
+ELEM_ATTR____(Connect, Ref, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Connect, Timeout, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Connect, Connection, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Connect, Usage, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Connect, DelayedOpen, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Submit, Format, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Submit, EmbedPDF, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Submit, Target, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Submit, TextEncoding, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Submit, XdpContent, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Packet, Content, CJX_Packet::content)
+ELEM_ATTR____(SubjectDN, Delimiter, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Radial, Type, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(EffectiveInputPolicy, Id, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(EffectiveInputPolicy, Name, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Transform, Ref, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(LockDocument, Id, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(LockDocument, Type, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(BreakAfter, StartNew, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(BreakAfter, Trailer, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(BreakAfter, TargetType, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(BreakAfter, Target, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(BreakAfter, Leader, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Line, Slope, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Line, Hand, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Source, Db, CJX_Source::db)
+ELEM_ATTR____(Occur, Max, CJX_Occur::max)
+ELEM_ATTR____(Occur, Min, CJX_Occur::min)
+ELEM_ATTR____(Occur, Initial, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(MonthNames, Abbr, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(NumberSymbol, Name, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Items, Ref, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Items, Presence, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Items, Save, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(EventPseudoModel, FullText, CJX_EventPseudoModel::fullText)
+ELEM_ATTR____(EventPseudoModel, Reenter, CJX_EventPseudoModel::reenter)
+ELEM_ATTR____(EventPseudoModel, PrevContentType, CJX_EventPseudoModel::prevContentType)
+ELEM_ATTR____(EventPseudoModel, SoapFaultString, CJX_EventPseudoModel::soapFaultString)
+ELEM_ATTR____(EventPseudoModel, NewContentType, CJX_EventPseudoModel::newContentType)
+ELEM_ATTR____(EventPseudoModel, Modifier, CJX_EventPseudoModel::modifier)
+ELEM_ATTR____(EventPseudoModel, SelEnd, CJX_EventPseudoModel::selEnd)
+ELEM_ATTR____(EventPseudoModel, PrevText, CJX_EventPseudoModel::prevText)
+ELEM_ATTR____(EventPseudoModel, SoapFaultCode, CJX_EventPseudoModel::soapFaultCode)
+ELEM_ATTR____(EventPseudoModel, NewText, CJX_EventPseudoModel::newText)
+ELEM_ATTR____(EventPseudoModel, Change, CJX_EventPseudoModel::change)
+ELEM_ATTR____(EventPseudoModel, Shift, CJX_EventPseudoModel::shift)
+ELEM_ATTR____(EventPseudoModel, keyDown, CJX_EventPseudoModel::keyDown)
+ELEM_ATTR____(EventPseudoModel, selStart, CJX_EventPseudoModel::selStart)
+ELEM_ATTR____(EventPseudoModel, CommitKey, CJX_EventPseudoModel::commitKey)
+ELEM_ATTR____(EventPseudoModel, Target, CJX_EventPseudoModel::target)
+ELEM_ATTR____(EventPseudoModel, cancelAction, CJX_EventPseudoModel::cancelAction)
+ELEM_ATTR____(HostPseudoModel, Name, CJX_HostPseudoModel::name)
+ELEM_ATTR____(HostPseudoModel, ValidationsEnabled, CJX_HostPseudoModel::validationsEnabled)
+ELEM_ATTR____(HostPseudoModel, Title, CJX_HostPseudoModel::title)
+ELEM_ATTR____(HostPseudoModel, Platform, CJX_HostPseudoModel::platform)
+ELEM_ATTR____(HostPseudoModel, Version, CJX_HostPseudoModel::version)
+ELEM_ATTR____(HostPseudoModel, Variation, CJX_HostPseudoModel::variation)
+ELEM_ATTR____(HostPseudoModel, Language, CJX_HostPseudoModel::language)
+ELEM_ATTR____(HostPseudoModel, AppType, CJX_HostPseudoModel::appType)
+ELEM_ATTR____(HostPseudoModel, CalculationsEnabled, CJX_HostPseudoModel::calculationsEnabled)
+ELEM_ATTR____(HostPseudoModel, CurrentPage, CJX_HostPseudoModel::currentPage)
+ELEM_ATTR____(HostPseudoModel, NumPages, CJX_HostPseudoModel::numPages)
+ELEM_ATTR____(LayoutPseudoModel, Ready, CJX_LayoutPseudoModel::ready)
+ELEM_ATTR____(DataWindow, RecordsBefore, CJX_DataWindow::recordsBefore)
+ELEM_ATTR____(DataWindow, CurrentRecordNumber, CJX_DataWindow::currentRecordNumber)
+ELEM_ATTR____(DataWindow, RecordsAfter, CJX_DataWindow::recordsAfter)
+ELEM_ATTR____(DataWindow, IsDefined, CJX_DataWindow::isDefined)
+ELEM_ATTR____(List, Length, CJX_List::length)
+ELEM_ATTR____(Object, ClassName, CJX_Object::className)
+ELEM_ATTR____(ListDuplicate, Length, CJX_List::length)
+ELEM_ATTR____(Tree, Name, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Tree, All, CJX_Tree::all)
+ELEM_ATTR____(Tree, Nodes, CJX_Tree::nodes)
+ELEM_ATTR____(Tree, ClassAll, CJX_Tree::classAll)
+ELEM_ATTR____(Tree, Parent, CJX_Tree::parent)
+ELEM_ATTR____(Tree, Index, CJX_Tree::index)
+ELEM_ATTR____(Tree, ClassIndex, CJX_Tree::classIndex)
+ELEM_ATTR____(Tree, SomExpression, CJX_Tree::somExpression)
+ELEM_ATTR____(Node, Id, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(Node, Ns, CJX_Node::ns)
+ELEM_ATTR____(Node, Model, CJX_Node::model)
+ELEM_ATTR____(Node, IsContainer, CJX_Node::isContainer)
+ELEM_ATTR____(Node, IsNull, CJX_Node::isNull)
+ELEM_ATTR____(Node, OneOfChild, CJX_Node::oneOfChild)
+ELEM_ATTR____(Model, Context, CJX_Model::context)
+ELEM_ATTR____(Model, AliasNode, CJX_Model::aliasNode)
+ELEM_ATTR____(NodeWithUse, Use, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(NodeWithUse, Usehref, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(NodeWithValue, DefaultValue, CJX_Object::ScriptSomDefaultValue)
+ELEM_ATTR____(NodeWithValue, Value, CJX_Object::ScriptSomDefaultValue)
+ELEM_ATTR____(NodeWithDesc, Desc, CJX_Object::ScriptAttributeString)
+ELEM_ATTR____(NodeWithDesc, Lock, CJX_Object::ScriptAttributeBool)
diff --git a/xfa/fxfa/parser/elements.inc b/xfa/fxfa/parser/elements.inc
new file mode 100644
index 0000000..b0246ec
--- /dev/null
+++ b/xfa/fxfa/parser/elements.inc
@@ -0,0 +1,329 @@
+// Copyright 2018 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
+
+// NOTE: A hash of 0xFFFFFFFF is reserved for an item that can not be looked up
+// by name, and the corresponding name placeholder must not hash to it.
+
+ELEM____(0x0023ee3u, "ps", Ps, NodeWithDesc)
+ELEM____(0x0025363u, "to", To, NodeWithDesc)
+ELEM____(0x002587eu, "ui", Ui, NodeWithUse)
+ELEM____(0x01c648bu, "recordSet", RecordSet, NodeWithUse)
+ELEM____(0x0171428fu, "subsetBelow", SubsetBelow, NodeWithDesc)
+ELEM____(0x01a0776au, "subformSet", SubformSet, NodeWithUse)
+ELEM____(0x02340d70u, "adobeExtensionLevel", AdobeExtensionLevel, NodeWithDesc)
+ELEM____(0x02c1c7f1u, "typeface", Typeface, Node)
+ELEM____(0x05518c25u, "break", Break, NodeWithUse)
+ELEM____(0x05fff523u, "fontInfo", FontInfo, NodeWithDesc)
+ELEM____(0x0653a227u, "numberPattern", NumberPattern, Node)
+ELEM____(0x065b4a05u, "dynamicRender", DynamicRender, NodeWithDesc)
+ELEM____(0x07e4362eu, "printScaling", PrintScaling, NodeWithDesc)
+ELEM____(0x07fe6d3au, "checkButton", CheckButton, NodeWithUse)
+ELEM____(0x080cf58fu, "datePatterns", DatePatterns, Node)
+ELEM____(0x0811929du, "sourceSet", SourceSet, Model)
+ELEM____(0x09f9d612u, "amd", Amd, NodeWithDesc)
+ELEM____(0x09f9efb6u, "arc", Arc, NodeWithUse)
+ELEM____(0x0a48835eu, "day", Day, Node)
+ELEM____(0x0a6328b8u, "era", Era, Node)
+ELEM____(0x0ae6a0a0u, "jog", Jog, NodeWithDesc)
+ELEM____(0x0b1b3d22u, "log", Log, NodeWithDesc)
+ELEM____(0x0b35439eu, "map", Map, NodeWithUse)
+ELEM____(0x0b355301u, "mdp", Mdp, NodeWithUse)
+ELEM____(0x0b420438u, "breakBefore", BreakBefore, NodeWithUse)
+ELEM____(0x0b6a091cu, "oid", Oid, NodeWithValue)
+ELEM____(0x0b84389fu, "pcl", Pcl, NodeWithDesc)
+ELEM____(0x0b843dbau, "pdf", Pdf, NodeWithDesc)
+ELEM____(0x0bb8df5du, "ref", Ref, NodeWithValue)
+ELEM____(0x0c080cd0u, "uri", Uri, NodeWithValue)
+ELEM____(0x0c56afbfu, "xdc", Xdc, NodeWithDesc)
+ELEM____(0x0c56afccu, "xdp", Xdp, NodeWithDesc)
+ELEM____(0x0c56b9ffu, "xfa", Xfa, Model)
+ELEM____(0x0c56fcb7u, "xsl", Xsl, NodeWithDesc)
+ELEM____(0x0c8b89d6u, "zpl", Zpl, NodeWithDesc)
+ELEM____(0x0c9bae94u, "cache", Cache, NodeWithDesc)
+ELEM____(0x0cb016beu, "margin", Margin, NodeWithUse)
+ELEM____(0x0e1378feu, "keyUsage", KeyUsage, NodeWithUse)
+ELEM____(0x0fe3596au, "exclude", Exclude, NodeWithDesc)
+ELEM____(0x10395ac7u, "choiceList", ChoiceList, NodeWithUse)
+ELEM____(0x1059ec18u, "level", Level, NodeWithDesc)
+ELEM____(0x10874804u, "labelPrinter", LabelPrinter, NodeWithDesc)
+ELEM____(0x10c40e03u, "calendarSymbols", CalendarSymbols, Node)
+ELEM____(0x10f1ea24u, "para", Para, NodeWithUse)
+ELEM____(0x10f1ea37u, "part", Part, NodeWithUse)
+ELEM____(0x1140975bu, "pdfa", Pdfa, Node)
+ELEM____(0x1154efe6u, "filter", Filter, NodeWithUse)
+ELEM____(0x13f41de1u, "present", Present, NodeWithDesc)
+ELEM____(0x1827e6eau, "pagination", Pagination, NodeWithDesc)
+ELEM____(0x18463707u, "encoding", Encoding, NodeWithUse)
+ELEM____(0x185e41e2u, "event", Event, NodeWithUse)
+ELEM____(0x1adb142du, "whitespace", Whitespace, NodeWithDesc)
+ELEM____(0x1f3f64c3u, "defaultUi", DefaultUi, NodeWithUse)
+ELEM____(0x204e87cbu, "dataModel", DataModel, Model)
+ELEM____(0x2057b350u, "barcode", Barcode, NodeWithUse)
+ELEM____(0x20596badu, "timePattern", TimePattern, Node)
+ELEM____(0x210b74d3u, "batchOutput", BatchOutput, NodeWithDesc)
+ELEM____(0x212ff0e2u, "enforce", Enforce, NodeWithDesc)
+ELEM____(0x21d351b4u, "currencySymbols", CurrencySymbols, Node)
+ELEM____(0x21db83c5u, "addSilentPrint", AddSilentPrint, NodeWithDesc)
+ELEM____(0x22266258u, "rename", Rename, NodeWithDesc)
+ELEM____(0x226ca8f1u, "operation", Operation, NodeWithValue)
+ELEM____(0x23e27b84u, "typefaces", Typefaces, Node)
+ELEM____(0x23f4aa75u, "subjectDNs", SubjectDNs, Node)
+ELEM____(0x240d5e8eu, "issuers", Issuers, NodeWithUse)
+ELEM____(0x24a52f8au, "wsdlConnection", WsdlConnection, Node)
+ELEM____(0x254ebd07u, "debug", Debug, NodeWithDesc)
+ELEM____(0x2655c66au, "delta", Delta, Unknown)
+ELEM____(0x26c0daecu, "eraNames", EraNames, Node)
+ELEM____(0x273ab03bu, "modifyAnnots", ModifyAnnots, NodeWithDesc)
+ELEM____(0x27875bb4u, "startNode", StartNode, NodeWithDesc)
+ELEM____(0x285d0dbcu, "button", Button, NodeWithUse)
+ELEM____(0x28dee6e9u, "format", Format, NodeWithUse)
+ELEM____(0x2a23349eu, "border", Border, NodeWithUse)
+ELEM____(0x2ae67f19u, "area", Area, NodeWithUse)
+ELEM____(0x2c3c4c67u, "hyphenation", Hyphenation, NodeWithUse)
+ELEM____(0x2d08af85u, "text", Text, NodeWithUse)
+ELEM____(0x2d71b00fu, "time", Time, NodeWithUse)
+ELEM____(0x2f16a382u, "type", Type, NodeWithDesc)
+ELEM____(0x2fe057e9u, "overprint", Overprint, NodeWithDesc)
+ELEM____(0x302aee16u, "certificates", Certificates, NodeWithUse)
+ELEM____(0x30b227dfu, "encryptionMethods", EncryptionMethods, NodeWithUse)
+ELEM____(0x32b900d1u, "setProperty", SetProperty, Node)
+ELEM____(0x337d9e45u, "printerName", PrinterName, NodeWithDesc)
+ELEM____(0x33edda4bu, "startPage", StartPage, NodeWithDesc)
+ELEM____(0x381943e4u, "pageOffset", PageOffset, NodeWithDesc)
+ELEM____(0x382106cdu, "dateTime", DateTime, NodeWithUse)
+ELEM____(0x386e7421u, "comb", Comb, NodeWithUse)
+ELEM____(0x390acd9eu, "pattern", Pattern, NodeWithUse)
+ELEM____(0x3942163eu, "ifEmpty", IfEmpty, NodeWithDesc)
+ELEM____(0x39944a7bu, "suppressBanner", SuppressBanner, NodeWithDesc)
+ELEM____(0x3b3c3dcau, "outputBin", OutputBin, NodeWithDesc)
+ELEM____(0x3b8a4024u, "field", Field, NodeWithUse)
+ELEM____(0x3c15352fu, "agent", Agent, NodeWithDesc)
+ELEM____(0x3d7e8668u, "outputXSL", OutputXSL, NodeWithDesc)
+ELEM____(0x3e1c91c5u, "adjustData", AdjustData, NodeWithDesc)
+ELEM____(0x3e7a9408u, "autoSave", AutoSave, NodeWithDesc)
+ELEM____(0x3ecead94u, "contentArea", ContentArea, NodeWithUse)
+ELEM____(0x3fadaec0u, "wsdlAddress", WsdlAddress, NodeWithValue)
+ELEM____(0x40623b5bu, "solid", Solid, NodeWithUse)
+ELEM____(0x41f0bd76u, "dateTimeSymbols", DateTimeSymbols, Node)
+ELEM____(0x444e7523u, "encryptionLevel", EncryptionLevel, NodeWithDesc)
+ELEM____(0x4523af55u, "edge", Edge, NodeWithUse)
+ELEM____(0x45d5e3c1u, "stipple", Stipple, NodeWithUse)
+ELEM____(0x475e4e87u, "attributes", Attributes, NodeWithDesc)
+ELEM____(0x487a8c87u, "versionControl", VersionControl, Node)
+ELEM____(0x48e5248cu, "meridiem", Meridiem, Node)
+ELEM____(0x48f36719u, "exclGroup", ExclGroup, NodeWithUse)
+ELEM____(0x4977356bu, "toolTip", ToolTip, NodeWithValue)
+ELEM____(0x499afeccu, "compress", Compress, NodeWithDesc)
+ELEM____(0x4a0c4948u, "reason", Reason, NodeWithValue)
+ELEM____(0x4bdcce13u, "execute", Execute, NodeWithUse)
+ELEM____(0x4c56b216u, "contentCopy", ContentCopy, NodeWithDesc)
+ELEM____(0x4cc176d3u, "dateTimeEdit", DateTimeEdit, NodeWithUse)
+ELEM____(0x4e1e39b6u, "config", Config, NodeWithDesc)
+ELEM____(0x4e2d6083u, "image", Image, NodeWithUse)
+ELEM____(0x4e814150u, "#xHTML", SharpxHTML, Node)
+ELEM____(0x4f2388c1u, "numberOfCopies", NumberOfCopies, NodeWithDesc)
+ELEM____(0x4f512e30u, "behaviorOverride", BehaviorOverride, NodeWithDesc)
+ELEM____(0x4fdc3454u, "timeStamp", TimeStamp, NodeWithUse)
+ELEM____(0x51d90546u, "month", Month, Node)
+ELEM____(0x523437e4u, "viewerPreferences", ViewerPreferences, NodeWithDesc)
+ELEM____(0x53abc1c6u, "scriptModel", ScriptModel, NodeWithDesc)
+ELEM____(0x54034c2fu, "decimal", Decimal, NodeWithUse)
+ELEM____(0x54202c9eu, "subform", Subform, NodeWithUse)
+ELEM____(0x542c7300u, "select", Select, NodeWithValue)
+ELEM____(0x5436d198u, "window", Window, NodeWithDesc)
+ELEM____(0x5473b6dcu, "localeSet", LocaleSet, NodeWithDesc)
+ELEM____(0x56ae179eu, "handler", Handler, NodeWithValue)
+ELEM____(0x570ce835u, "presence", Presence, NodeWithDesc)
+ELEM____(0x5779d65fu, "record", Record, NodeWithDesc)
+ELEM____(0x59c8f27du, "embed", Embed, NodeWithDesc)
+ELEM____(0x5a50e9e6u, "version", Version, NodeWithDesc)
+ELEM____(0x5b8383dfu, "command", Command, NodeWithUse)
+ELEM____(0x5c43c6c3u, "copies", Copies, NodeWithDesc)
+ELEM____(0x5e0c2c49u, "staple", Staple, NodeWithDesc)
+ELEM____(0x5e5083ddu, "submitFormat", SubmitFormat, NodeWithDesc)
+ELEM____(0x5e8c5d20u, "boolean", Boolean, NodeWithUse)
+ELEM____(0x60490a85u, "message", Message, NodeWithUse)
+ELEM____(0x60d4c8b1u, "output", Output, NodeWithDesc)
+ELEM____(0x61810081u, "psMap", PsMap, Node)
+ELEM____(0x62bd904bu, "excludeNS", ExcludeNS, NodeWithDesc)
+ELEM____(0x669d4f77u, "assist", Assist, NodeWithUse)
+ELEM____(0x67334a1cu, "picture", Picture, NodeWithUse)
+ELEM____(0x67fe7334u, "traversal", Traversal, NodeWithUse)
+ELEM____(0x6894589cu, "silentPrint", SilentPrint, NodeWithDesc)
+ELEM____(0x68a16bbdu, "webClient", WebClient, NodeWithDesc)
+ELEM____(0x6a4bc084u, "producer", Producer, NodeWithDesc)
+ELEM____(0x6a9e04c9u, "corner", Corner, NodeWithUse)
+ELEM____(0x6ccd7274u, "msgId", MsgId, NodeWithDesc)
+ELEM____(0x6e67921fu, "color", Color, NodeWithUse)
+ELEM____(0x6ec217a5u, "keep", Keep, NodeWithUse)
+ELEM____(0x6eef1116u, "query", Query, NodeWithUse)
+ELEM____(0x7033bfd5u, "insert", Insert, NodeWithValue)
+ELEM____(0x704af389u, "imageEdit", ImageEdit, NodeWithUse)
+ELEM____(0x7233018au, "validate", Validate, NodeWithUse)
+ELEM____(0x72ba47b4u, "digestMethods", DigestMethods, NodeWithUse)
+ELEM____(0x72f2aa7au, "numberPatterns", NumberPatterns, Node)
+ELEM____(0x74caed29u, "pageSet", PageSet, NodeWithUse)
+ELEM____(0x7568e6aeu, "integer", Integer, NodeWithUse)
+ELEM____(0x76182db9u, "soapAddress", SoapAddress, NodeWithValue)
+ELEM____(0x773146c5u, "equate", Equate, NodeWithDesc)
+ELEM____(0x77d449ddu, "formFieldFilling", FormFieldFilling, NodeWithDesc)
+ELEM____(0x7889d68au, "pageRange", PageRange, NodeWithDesc)
+ELEM____(0x7baca2e3u, "update", Update, NodeWithValue)
+ELEM____(0x7ce89001u, "connectString", ConnectString, NodeWithValue)
+ELEM____(0x7d9fd7c5u, "mode", Mode, NodeWithDesc)
+ELEM____(0x7e7e845eu, "layout", Layout, NodeWithDesc)
+ELEM____(0x7e845c34u, "#xml", Sharpxml, Node)
+ELEM____(0x7fb341dfu, "xsdConnection", XsdConnection, Node)
+ELEM____(0x7ffb51ccu, "traverse", Traverse, NodeWithUse)
+ELEM____(0x80203b5au, "encodings", Encodings, NodeWithUse)
+ELEM____(0x803550fcu, "template", Template, Model)
+ELEM____(0x803d5bbcu, "acrobat", Acrobat, NodeWithDesc)
+ELEM____(0x821d6569u, "validationMessaging", ValidationMessaging, NodeWithDesc)
+ELEM____(0x830e688fu, "signing", Signing, NodeWithUse)
+ELEM____(0x83dab9f5u, "script", Script, NodeWithUse)
+ELEM____(0x8411ebcdu, "addViewerPreferences", AddViewerPreferences, NodeWithDesc)
+ELEM____(0x8777642eu, "alwaysEmbed", AlwaysEmbed, NodeWithDesc)
+ELEM____(0x877a6b39u, "passwordEdit", PasswordEdit, NodeWithUse)
+ELEM____(0x87e84c99u, "numericEdit", NumericEdit, NodeWithUse)
+ELEM____(0x8852cdecu, "encryptionMethod", EncryptionMethod, NodeWithUse)
+ELEM____(0x891f4606u, "change", Change, NodeWithDesc)
+ELEM____(0x89939f36u, "pageArea", PageArea, NodeWithUse)
+ELEM____(0x8a9d6247u, "submitUrl", SubmitUrl, NodeWithDesc)
+ELEM____(0x8ad8b90fu, "oids", Oids, NodeWithUse)
+ELEM____(0x8b036f32u, "signature", Signature, NodeWithUse)
+ELEM____(0x8b128efbu, "ADBE_JSConsole", ADBE_JSConsole, NodeWithDesc)
+ELEM____(0x8bcfe96eu, "caption", Caption, NodeWithUse)
+ELEM____(0x8e1c2921u, "relevant", Relevant, NodeWithDesc)
+ELEM____(0x8e3f0a4bu, "flipLabel", FlipLabel, NodeWithDesc)
+ELEM____(0x900280b7u, "exData", ExData, NodeWithUse)
+ELEM____(0x91e80352u, "dayNames", DayNames, Node)
+ELEM____(0x93113b11u, "soapAction", SoapAction, NodeWithValue)
+ELEM____(0x938b09f6u, "defaultTypeface", DefaultTypeface, NodeWithDesc)
+ELEM____(0x95b37897u, "manifest", Manifest, NodeWithUse)
+ELEM____(0x97b76b54u, "overflow", Overflow, NodeWithUse)
+ELEM____(0x9a57861bu, "linear", Linear, NodeWithUse)
+ELEM____(0x9ad5a821u, "currencySymbol", CurrencySymbol, Node)
+ELEM____(0x9c6471b3u, "delete", Delete, NodeWithValue)
+ELEM____(0x9deea61du, "deltas", Deltas, ListDuplicate)
+ELEM____(0x9e67de21u, "digestMethod", DigestMethod, NodeWithUse)
+ELEM____(0x9f3e9510u, "instanceManager", InstanceManager, Node)
+ELEM____(0xa0799892u, "equateRange", EquateRange, NodeWithDesc)
+ELEM____(0xa084a381u, "medium", Medium, NodeWithUse)
+ELEM____(0xa1211b8bu, "textEdit", TextEdit, NodeWithUse)
+ELEM____(0xa17008f0u, "templateCache", TemplateCache, NodeWithDesc)
+ELEM____(0xa4f7b88fu, "compressObjectStream", CompressObjectStream, NodeWithDesc)
+ELEM____(0xa65f5d17u, "dataValue", DataValue, Node)
+ELEM____(0xa6caaa89u, "accessibleContent", AccessibleContent, NodeWithDesc)
+ELEM____(0xa94cc00bu, "includeXDPContent", IncludeXDPContent, NodeWithDesc)
+ELEM____(0xa9b081a1u, "xmlConnection", XmlConnection, Node)
+ELEM____(0xab2a3b74u, "validateApprovalSignatures", ValidateApprovalSignatures, NodeWithDesc)
+ELEM____(0xab8c5a2bu, "signData", SignData, NodeWithUse)
+ELEM____(0xabaa2cebu, "packets", Packets, NodeWithDesc)
+ELEM____(0xadba359cu, "datePattern", DatePattern, Node)
+ELEM____(0xae222b2bu, "duplexOption", DuplexOption, NodeWithDesc)
+ELEM____(0xb012effbu, "base", Base, NodeWithDesc)
+ELEM____(0xb0e5485du, "bind", Bind, NodeWithUse)
+ELEM____(0xb45d61b2u, "compression", Compression, NodeWithDesc)
+ELEM____(0xb563f0ffu, "user", User, NodeWithValue)
+ELEM____(0xb5848ad5u, "rectangle", Rectangle, NodeWithUse)
+ELEM____(0xb6dacb72u, "effectiveOutputPolicy", EffectiveOutputPolicy, NodeWithUse)
+ELEM____(0xb7d7654du, "ADBE_JSDebugger", ADBE_JSDebugger, NodeWithDesc)
+ELEM____(0xbab37f73u, "acrobat7", Acrobat7, NodeWithDesc)
+ELEM____(0xbc70081eu, "interactive", Interactive, NodeWithDesc)
+ELEM____(0xbc8fa350u, "locale", Locale, NodeWithDesc)
+ELEM____(0xbcd44940u, "currentPage", CurrentPage, NodeWithDesc)
+ELEM____(0xbde9abdau, "data", Data, NodeWithDesc)
+ELEM____(0xbde9abdeu, "date", Date, NodeWithUse)
+ELEM____(0xbe52dfbfu, "desc", Desc, NodeWithUse)
+ELEM____(0xbf4b6405u, "encrypt", Encrypt, NodeWithUse)
+ELEM____(0xbfa87cceu, "draw", Draw, NodeWithUse)
+ELEM____(0xc181ff4bu, "encryption", Encryption, NodeWithDesc)
+ELEM____(0xc1970f40u, "meridiemNames", MeridiemNames, Node)
+ELEM____(0xc5ad9f5eu, "messaging", Messaging, NodeWithDesc)
+ELEM____(0xc69549f4u, "speak", Speak, NodeWithValue)
+ELEM____(0xc7743dc7u, "dataGroup", DataGroup, Node)
+ELEM____(0xc7eb20e9u, "common", Common, NodeWithDesc)
+ELEM____(0xc85d4528u, "#text", Sharptext, Node)
+ELEM____(0xc861556au, "paginationOverride", PaginationOverride, NodeWithDesc)
+ELEM____(0xc903dabbu, "reasons", Reasons, NodeWithUse)
+ELEM____(0xc9a8127fu, "signatureProperties", SignatureProperties, NodeWithUse)
+ELEM____(0xca010c2du, "threshold", Threshold, NodeWithDesc)
+ELEM____(0xcb4c5e96u, "appearanceFilter", AppearanceFilter, NodeWithUse)
+ELEM____(0xcc92aba7u, "fill", Fill, NodeWithUse)
+ELEM____(0xcd308b77u, "font", Font, NodeWithUse)
+ELEM____(0xcd309ff4u, "form", Form, Model)
+ELEM____(0xcebcca2du, "mediumInfo", MediumInfo, NodeWithDesc)
+ELEM____(0xcfe0d643u, "certificate", Certificate, NodeWithValue)
+ELEM____(0xd012c033u, "password", Password, NodeWithValue)
+ELEM____(0xd01604bdu, "runScripts", RunScripts, NodeWithDesc)
+ELEM____(0xd1227e6fu, "trace", Trace, NodeWithDesc)
+ELEM____(0xd1532876u, "float", Float, NodeWithUse)
+ELEM____(0xd17a6c30u, "renderPolicy", RenderPolicy, NodeWithDesc)
+ELEM____(0xd58aa962u, "destination", Destination, NodeWithDesc)
+ELEM____(0xd6e27f1du, "value", Value, NodeWithUse)
+ELEM____(0xd7a14462u, "bookend", Bookend, NodeWithUse)
+ELEM____(0xd8c31254u, "exObject", ExObject, NodeWithUse)
+ELEM____(0xda6a8590u, "openAction", OpenAction, NodeWithDesc)
+ELEM____(0xdab4fb7du, "neverEmbed", NeverEmbed, NodeWithDesc)
+ELEM____(0xdb98475fu, "bindItems", BindItems, Node)
+ELEM____(0xdbfbe02eu, "calculate", Calculate, NodeWithUse)
+ELEM____(0xdd7676edu, "print", Print, NodeWithDesc)
+ELEM____(0xdde273d7u, "extras", Extras, NodeWithUse)
+ELEM____(0xde146b34u, "proto", Proto, Node)
+ELEM____(0xdf059321u, "dSigData", DSigData, Node)
+ELEM____(0xdfccf030u, "creator", Creator, NodeWithDesc)
+ELEM____(0xdff78c6au, "connect", Connect, NodeWithUse)
+ELEM____(0xe11a2cbcu, "permissions", Permissions, NodeWithDesc)
+ELEM____(0xe14c801cu, "connectionSet", ConnectionSet, Model)
+ELEM____(0xe1c83a14u, "submit", Submit, NodeWithUse)
+ELEM____(0xe29821cdu, "range", Range, NodeWithDesc)
+ELEM____(0xe38d83c7u, "linearized", Linearized, NodeWithDesc)
+ELEM____(0xe3aa2578u, "packet", Packet, Node)
+ELEM____(0xe3aa860eu, "rootElement", RootElement, NodeWithValue)
+ELEM____(0xe3e553fau, "plaintextMetadata", PlaintextMetadata, NodeWithDesc)
+ELEM____(0xe3e6e4f2u, "numberSymbols", NumberSymbols, Node)
+ELEM____(0xe3f067f6u, "printHighQuality", PrintHighQuality, NodeWithDesc)
+ELEM____(0xe3fd078cu, "driver", Driver, NodeWithDesc)
+ELEM____(0xe48b34f2u, "incrementalLoad", IncrementalLoad, NodeWithDesc)
+ELEM____(0xe550e7c2u, "subjectDN", SubjectDN, Node)
+ELEM____(0xe6669a78u, "compressLogicalStructure", CompressLogicalStructure, NodeWithDesc)
+ELEM____(0xe7a7ea02u, "incrementalMerge", IncrementalMerge, NodeWithDesc)
+ELEM____(0xe948530du, "radial", Radial, NodeWithUse)
+ELEM____(0xea8d6999u, "variables", Variables, NodeWithUse)
+ELEM____(0xeaa142c0u, "timePatterns", TimePatterns, Node)
+ELEM____(0xeb943a71u, "effectiveInputPolicy", EffectiveInputPolicy, NodeWithUse)
+ELEM____(0xef04a2bcu, "nameAttr", NameAttr, NodeWithDesc)
+ELEM____(0xf07222abu, "conformance", Conformance, NodeWithDesc)
+ELEM____(0xf0aaaadcu, "transform", Transform, NodeWithDesc)
+ELEM____(0xf1433e88u, "lockDocument", LockDocument, NodeWithUse)
+ELEM____(0xf54eb997u, "breakAfter", BreakAfter, NodeWithUse)
+ELEM____(0xf616da28u, "line", Line, NodeWithUse)
+ELEM____(0xf7055fb1u, "source", Source, NodeWithUse)
+ELEM____(0xf7eebe1cu, "occur", Occur, NodeWithUse)
+ELEM____(0xf8d10d97u, "pickTrayByPDFSize", PickTrayByPDFSize, NodeWithDesc)
+ELEM____(0xf8f19e3au, "monthNames", MonthNames, Node)
+ELEM____(0xf984149bu, "severity", Severity, NodeWithDesc)
+ELEM____(0xf9bcb037u, "groupParent", GroupParent, NodeWithDesc)
+ELEM____(0xfbc42fffu, "documentAssembly", DocumentAssembly, NodeWithDesc)
+ELEM____(0xfc78159fu, "numberSymbol", NumberSymbol, Node)
+ELEM____(0xfcbd606cu, "tagged", Tagged, NodeWithDesc)
+ELEM____(0xff063802u, "items", Items, NodeWithUse)
+ELEM____(0xffffffffu, "signaturePseudoModel", SignaturePseudoModel, Object)
+ELEM____(0xffffffffu, "eventPseudoModel", EventPseudoModel, Object)
+ELEM____(0xffffffffu, "hostPseudoModel", HostPseudoModel, Object)
+ELEM____(0xffffffffu, "layoutPseudoModel", LayoutPseudoModel, Object)
+ELEM____(0xffffffffu, "dataWindow", DataWindow, Object)
+ELEM____(0xffffffffu, "treeList,", TreeList, ListDuplicate)
+ELEM____(0xffffffffu, "logPseudoModel", LogPseudoModel, Object)
+ELEM____(0xffffffffu, "list", List, ListDuplicate)
+ELEM____(0xffffffffu, "object", Object, Unknown)
+ELEM____(0xffffffffu, "******", ListDuplicate, Object)
+ELEM____(0xffffffffu, "tree", Tree, Object)
+ELEM____(0xffffffffu, "node", Node, Tree)
+ELEM____(0xffffffffu, "model", Model, Node)
+ELEM____(0xffffffffu, "******", NodeWithUse, Node)
+ELEM____(0xffffffffu, "******", NodeWithValue, NodeWithUse)
+ELEM____(0xffffffffu, "******", NodeWithDesc, Node)
diff --git a/xfa/fxfa/parser/packets.inc b/xfa/fxfa/parser/packets.inc
new file mode 100644
index 0000000..58e49a4
--- /dev/null
+++ b/xfa/fxfa/parser/packets.inc
@@ -0,0 +1,21 @@
+// Copyright 2018 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
+
+PCKT____(0x0811929du, "sourceSet", SourceSet, L"http://www.xfa.org/schema/xfa-source-set/", NOMATCH, SUPPORTONE)
+PCKT____(0x0b843dbau, "pdf", Pdf, L"http://ns.adobe.com/xdp/pdf/", COMPLETEMATCH, SUPPORTONE)
+PCKT____(0x0c56afbfu, "xdc", Xdc, L"http://www.xfa.org/schema/xdc/", NOMATCH, SUPPORTONE)
+PCKT____(0x0c56afccu, "xdp", Xdp, L"http://ns.adobe.com/xdp/", COMPLETEMATCH, SUPPORTONE)
+PCKT____(0x132a8fbcu, "xmpmeta", Xmpmeta, L"http://ns.adobe.com/xmpmeta/", NOMATCH, SUPPORTMANY)
+PCKT____(0x48d004a8u, "xfdf", Xfdf, L"http://ns.adobe.com/xfdf/", NOMATCH, SUPPORTONE)
+PCKT____(0x4e1e39b6u, "config", Config, L"http://www.xfa.org/schema/xci/", NOMATCH, SUPPORTONE)
+PCKT____(0x5473b6dcu, "localeSet", LocaleSet, L"http://www.xfa.org/schema/xfa-locale-set/", NOMATCH, SUPPORTONE)
+PCKT____(0x6038580au, "stylesheet", Stylesheet, L"http://www.w3.org/1999/XSL/Transform", NOMATCH, SUPPORTMANY)
+PCKT____(0x803550fcu, "template", Template,  L"http://www.xfa.org/schema/xfa-template/", NOMATCH, SUPPORTONE)
+PCKT____(0x8b036f32u, "signature", Signature, L"http://www.w3.org/2000/09/xmldsig#", NOMATCH, SUPPORTONE)
+PCKT____(0x99b95079u, "datasets", Datasets,  L"http://www.xfa.org/schema/xfa-data/", PREFIXMATCH, SUPPORTONE)
+PCKT____(0xcd309ff4u, "form", Form, L"http://www.xfa.org/schema/xfa-form/", NOMATCH, SUPPORTONE)
+PCKT____(0xe14c801cu, "connectionSet", ConnectionSet, L"http://www.xfa.org/schema/xfa-connection-set/", NOMATCH, SUPPORTONE)
+PCKT____(0xffffffffu, "user", User, nullptr, NOMATCH, SUPPORTMANY)
diff --git a/xfa/fxfa/parser/xfa_basic_data.cpp b/xfa/fxfa/parser/xfa_basic_data.cpp
new file mode 100644
index 0000000..e7b01c9
--- /dev/null
+++ b/xfa/fxfa/parser/xfa_basic_data.cpp
@@ -0,0 +1,209 @@
+// Copyright 2016 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
+
+#include "xfa/fxfa/parser/xfa_basic_data.h"
+
+#include <utility>
+
+#include "fxjs/xfa/cjx_boolean.h"
+#include "fxjs/xfa/cjx_container.h"
+#include "fxjs/xfa/cjx_datawindow.h"
+#include "fxjs/xfa/cjx_delta.h"
+#include "fxjs/xfa/cjx_desc.h"
+#include "fxjs/xfa/cjx_draw.h"
+#include "fxjs/xfa/cjx_encrypt.h"
+#include "fxjs/xfa/cjx_eventpseudomodel.h"
+#include "fxjs/xfa/cjx_exclgroup.h"
+#include "fxjs/xfa/cjx_extras.h"
+#include "fxjs/xfa/cjx_field.h"
+#include "fxjs/xfa/cjx_form.h"
+#include "fxjs/xfa/cjx_handler.h"
+#include "fxjs/xfa/cjx_hostpseudomodel.h"
+#include "fxjs/xfa/cjx_instancemanager.h"
+#include "fxjs/xfa/cjx_layoutpseudomodel.h"
+#include "fxjs/xfa/cjx_logpseudomodel.h"
+#include "fxjs/xfa/cjx_manifest.h"
+#include "fxjs/xfa/cjx_model.h"
+#include "fxjs/xfa/cjx_node.h"
+#include "fxjs/xfa/cjx_occur.h"
+#include "fxjs/xfa/cjx_packet.h"
+#include "fxjs/xfa/cjx_script.h"
+#include "fxjs/xfa/cjx_signaturepseudomodel.h"
+#include "fxjs/xfa/cjx_source.h"
+#include "fxjs/xfa/cjx_subform.h"
+#include "fxjs/xfa/cjx_textnode.h"
+#include "fxjs/xfa/cjx_tree.h"
+#include "fxjs/xfa/cjx_treelist.h"
+#include "fxjs/xfa/cjx_wsdlconnection.h"
+#include "fxjs/xfa/cjx_xfa.h"
+#include "xfa/fxfa/fxfa_basic.h"
+
+namespace {
+
+struct PacketRecord {
+  XFA_PacketType packet_type;
+  uint32_t hash;
+  uint32_t flags;
+  const wchar_t* name;
+  const wchar_t* uri;
+};
+
+const PacketRecord g_PacketTable[] = {
+#undef PCKT____
+#define PCKT____(a, b, c, d, e, f)                                          \
+  {XFA_PacketType::c, a, XFA_XDPPACKET_FLAGS_##e | XFA_XDPPACKET_FLAGS_##f, \
+   L##b, d},
+#include "xfa/fxfa/parser/packets.inc"
+#undef PCKT____
+};
+
+struct ElementRecord {
+  uint32_t hash;  // Hashed as wide string.
+  XFA_Element element;
+  XFA_Element parent;
+  const char* name;
+};
+
+const ElementRecord g_ElementTable[] = {
+#undef ELEM____
+#define ELEM____(a, b, c, d) {a, XFA_Element::c, XFA_Element::d, b},
+#include "xfa/fxfa/parser/elements.inc"
+#undef ELEM____
+};
+
+struct AttributeRecord {
+  uint32_t hash;  // Hashed as wide string.
+  XFA_Attribute attribute;
+  XFA_ScriptType script_type;
+  const char* name;
+};
+
+const AttributeRecord g_AttributeTable[] = {
+#undef ATTR____
+#define ATTR____(a, b, c, d) {a, XFA_Attribute::c, XFA_ScriptType::d, b},
+#include "xfa/fxfa/parser/attributes.inc"
+#undef ATTR____
+};
+
+struct AttributeValueRecord {
+  uint32_t uHash;  // |pName| hashed as WideString.
+  XFA_AttributeValue eName;
+  const char* pName;
+};
+
+const AttributeValueRecord g_AttributeValueTable[] = {
+#undef VALUE____
+#define VALUE____(a, b, c) {a, XFA_AttributeValue::c, b},
+#include "xfa/fxfa/parser/attribute_values.inc"
+#undef VALUE____
+};
+
+struct ElementAttributeRecord {
+  XFA_Element element;
+  XFA_Attribute attribute;
+  XFA_ATTRIBUTE_CALLBACK callback;
+};
+
+const ElementAttributeRecord g_ElementAttributeTable[] = {
+#undef ELEM_ATTR____
+#define ELEM_ATTR____(a, b, c) {XFA_Element::a, XFA_Attribute::b, c##_static},
+#include "xfa/fxfa/parser/element_attributes.inc"
+#undef ELEM_ATTR____
+};
+
+}  // namespace
+
+XFA_PACKETINFO XFA_GetPacketByIndex(XFA_PacketType ePacket) {
+  const PacketRecord* pRecord = &g_PacketTable[static_cast<uint8_t>(ePacket)];
+  return {pRecord->name, pRecord->packet_type, pRecord->uri, pRecord->flags};
+}
+
+Optional<XFA_PACKETINFO> XFA_GetPacketByName(WideStringView wsName) {
+  uint32_t hash = FX_HashCode_GetW(wsName, false);
+  auto* elem = std::lower_bound(
+      std::begin(g_PacketTable), std::end(g_PacketTable), hash,
+      [](const PacketRecord& a, uint32_t hash) { return a.hash < hash; });
+  if (elem != std::end(g_PacketTable) && elem->name == wsName)
+    return XFA_GetPacketByIndex(elem->packet_type);
+  return {};
+}
+
+ByteStringView XFA_ElementToName(XFA_Element elem) {
+  return g_ElementTable[static_cast<size_t>(elem)].name;
+}
+
+XFA_Element XFA_GetElementByName(WideStringView name) {
+  uint32_t hash = FX_HashCode_GetW(name, false);
+  auto* elem = std::lower_bound(
+      std::begin(g_ElementTable), std::end(g_ElementTable), hash,
+      [](const ElementRecord& a, uint32_t hash) { return a.hash < hash; });
+  if (elem != std::end(g_ElementTable) && name.EqualsASCII(elem->name))
+    return elem->element;
+  return XFA_Element::Unknown;
+}
+
+ByteStringView XFA_AttributeToName(XFA_Attribute attr) {
+  return g_AttributeTable[static_cast<size_t>(attr)].name;
+}
+
+Optional<XFA_ATTRIBUTEINFO> XFA_GetAttributeByName(WideStringView name) {
+  uint32_t hash = FX_HashCode_GetW(name, false);
+  auto* elem = std::lower_bound(
+      std::begin(g_AttributeTable), std::end(g_AttributeTable), hash,
+      [](const AttributeRecord& a, uint32_t hash) { return a.hash < hash; });
+  if (elem != std::end(g_AttributeTable) && name.EqualsASCII(elem->name)) {
+    XFA_ATTRIBUTEINFO result;
+    result.attribute = elem->attribute;
+    result.eValueType = elem->script_type;
+    return result;
+  }
+  return {};
+}
+
+ByteStringView XFA_AttributeValueToName(XFA_AttributeValue item) {
+  return g_AttributeValueTable[static_cast<int32_t>(item)].pName;
+}
+
+Optional<XFA_AttributeValue> XFA_GetAttributeValueByName(WideStringView name) {
+  auto* it = std::lower_bound(std::begin(g_AttributeValueTable),
+                              std::end(g_AttributeValueTable),
+                              FX_HashCode_GetW(name, false),
+                              [](const AttributeValueRecord& arg,
+                                 uint32_t hash) { return arg.uHash < hash; });
+  if (it != std::end(g_AttributeValueTable) && name.EqualsASCII(it->pName))
+    return it->eName;
+
+  return {};
+}
+
+Optional<XFA_SCRIPTATTRIBUTEINFO> XFA_GetScriptAttributeByName(
+    XFA_Element element,
+    WideStringView attribute_name) {
+  Optional<XFA_ATTRIBUTEINFO> attr = XFA_GetAttributeByName(attribute_name);
+  if (!attr.has_value())
+    return {};
+
+  while (element != XFA_Element::Unknown) {
+    auto compound_key = std::make_pair(element, attr.value().attribute);
+    auto* it = std::lower_bound(
+        std::begin(g_ElementAttributeTable), std::end(g_ElementAttributeTable),
+        compound_key,
+        [](const ElementAttributeRecord& arg,
+           const std::pair<XFA_Element, XFA_Attribute>& key) {
+          return std::make_pair(arg.element, arg.attribute) < key;
+        });
+    if (it != std::end(g_ElementAttributeTable) &&
+        compound_key == std::make_pair(it->element, it->attribute)) {
+      XFA_SCRIPTATTRIBUTEINFO result;
+      result.attribute = attr.value().attribute;
+      result.eValueType = attr.value().eValueType;
+      result.callback = it->callback;
+      return result;
+    }
+    element = g_ElementTable[static_cast<size_t>(element)].parent;
+  }
+  return {};
+}
diff --git a/xfa/fxfa/parser/xfa_basic_data.h b/xfa/fxfa/parser/xfa_basic_data.h
index b394d35..4c3e0c7 100644
--- a/xfa/fxfa/parser/xfa_basic_data.h
+++ b/xfa/fxfa/parser/xfa_basic_data.h
@@ -7,17 +7,45 @@
 #ifndef XFA_FXFA_PARSER_XFA_BASIC_DATA_H_
 #define XFA_FXFA_PARSER_XFA_BASIC_DATA_H_
 
-#include <map>
+#include <stddef.h>
 
+#include "core/fxcrt/widestring.h"
+#include "fxjs/xfa/cjx_object.h"
+#include "third_party/base/optional.h"
 #include "xfa/fxfa/fxfa_basic.h"
 
-extern const XFA_AttributeEnumInfo g_XFAEnumData[];
-extern const int32_t g_iXFAEnumCount;
+struct XFA_PACKETINFO {
+  const wchar_t* name;
+  XFA_PacketType packet_type;
+  const wchar_t* uri;
+  uint32_t flags;
+};
 
-extern const XFA_SCRIPTHIERARCHY g_XFAScriptIndex[];
-extern const int32_t g_iScriptIndexCount;
+struct XFA_ATTRIBUTEINFO {
+  XFA_Attribute attribute;
+  XFA_ScriptType eValueType;
+};
 
-extern const XFA_SCRIPTATTRIBUTEINFO g_SomAttributeData[];
-extern const int32_t g_iSomAttributeCount;
+struct XFA_SCRIPTATTRIBUTEINFO {
+  XFA_Attribute attribute;
+  XFA_ScriptType eValueType;
+  XFA_ATTRIBUTE_CALLBACK callback = nullptr;
+};
+
+XFA_PACKETINFO XFA_GetPacketByIndex(XFA_PacketType ePacket);
+Optional<XFA_PACKETINFO> XFA_GetPacketByName(WideStringView wsName);
+
+ByteStringView XFA_ElementToName(XFA_Element elem);
+XFA_Element XFA_GetElementByName(WideStringView name);
+
+ByteStringView XFA_AttributeToName(XFA_Attribute attr);
+Optional<XFA_ATTRIBUTEINFO> XFA_GetAttributeByName(WideStringView name);
+
+ByteStringView XFA_AttributeValueToName(XFA_AttributeValue item);
+Optional<XFA_AttributeValue> XFA_GetAttributeValueByName(WideStringView name);
+
+Optional<XFA_SCRIPTATTRIBUTEINFO> XFA_GetScriptAttributeByName(
+    XFA_Element eElement,
+    WideStringView wsAttributeName);
 
 #endif  // XFA_FXFA_PARSER_XFA_BASIC_DATA_H_
diff --git a/xfa/fxfa/parser/xfa_basic_data_element_script.cpp b/xfa/fxfa/parser/xfa_basic_data_element_script.cpp
deleted file mode 100644
index 80a2bf3..0000000
--- a/xfa/fxfa/parser/xfa_basic_data_element_script.cpp
+++ /dev/null
@@ -1,3808 +0,0 @@
-// Copyright 2016 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
-
-#include "xfa/fxfa/parser/xfa_basic_data.h"
-
-#include "fxjs/xfa/cjx_arc.h"
-#include "fxjs/xfa/cjx_area.h"
-#include "fxjs/xfa/cjx_assist.h"
-#include "fxjs/xfa/cjx_barcode.h"
-#include "fxjs/xfa/cjx_bind.h"
-#include "fxjs/xfa/cjx_binditems.h"
-#include "fxjs/xfa/cjx_bookend.h"
-#include "fxjs/xfa/cjx_boolean.h"
-#include "fxjs/xfa/cjx_border.h"
-#include "fxjs/xfa/cjx_break.h"
-#include "fxjs/xfa/cjx_breakafter.h"
-#include "fxjs/xfa/cjx_breakbefore.h"
-#include "fxjs/xfa/cjx_button.h"
-#include "fxjs/xfa/cjx_calculate.h"
-#include "fxjs/xfa/cjx_caption.h"
-#include "fxjs/xfa/cjx_certificate.h"
-#include "fxjs/xfa/cjx_certificates.h"
-#include "fxjs/xfa/cjx_checkbutton.h"
-#include "fxjs/xfa/cjx_choicelist.h"
-#include "fxjs/xfa/cjx_color.h"
-#include "fxjs/xfa/cjx_comb.h"
-#include "fxjs/xfa/cjx_command.h"
-#include "fxjs/xfa/cjx_connect.h"
-#include "fxjs/xfa/cjx_connectstring.h"
-#include "fxjs/xfa/cjx_contentarea.h"
-#include "fxjs/xfa/cjx_corner.h"
-#include "fxjs/xfa/cjx_datavalue.h"
-#include "fxjs/xfa/cjx_datawindow.h"
-#include "fxjs/xfa/cjx_date.h"
-#include "fxjs/xfa/cjx_datetime.h"
-#include "fxjs/xfa/cjx_datetimeedit.h"
-#include "fxjs/xfa/cjx_decimal.h"
-#include "fxjs/xfa/cjx_defaultui.h"
-#include "fxjs/xfa/cjx_delete.h"
-#include "fxjs/xfa/cjx_delta.h"
-#include "fxjs/xfa/cjx_desc.h"
-#include "fxjs/xfa/cjx_digestmethod.h"
-#include "fxjs/xfa/cjx_digestmethods.h"
-#include "fxjs/xfa/cjx_draw.h"
-#include "fxjs/xfa/cjx_edge.h"
-#include "fxjs/xfa/cjx_encoding.h"
-#include "fxjs/xfa/cjx_encodings.h"
-#include "fxjs/xfa/cjx_encrypt.h"
-#include "fxjs/xfa/cjx_event.h"
-#include "fxjs/xfa/cjx_eventpseudomodel.h"
-#include "fxjs/xfa/cjx_exclgroup.h"
-#include "fxjs/xfa/cjx_exdata.h"
-#include "fxjs/xfa/cjx_execute.h"
-#include "fxjs/xfa/cjx_exobject.h"
-#include "fxjs/xfa/cjx_extras.h"
-#include "fxjs/xfa/cjx_field.h"
-#include "fxjs/xfa/cjx_fill.h"
-#include "fxjs/xfa/cjx_filter.h"
-#include "fxjs/xfa/cjx_float.h"
-#include "fxjs/xfa/cjx_font.h"
-#include "fxjs/xfa/cjx_format.h"
-#include "fxjs/xfa/cjx_handler.h"
-#include "fxjs/xfa/cjx_hostpseudomodel.h"
-#include "fxjs/xfa/cjx_image.h"
-#include "fxjs/xfa/cjx_imageedit.h"
-#include "fxjs/xfa/cjx_insert.h"
-#include "fxjs/xfa/cjx_instancemanager.h"
-#include "fxjs/xfa/cjx_integer.h"
-#include "fxjs/xfa/cjx_issuers.h"
-#include "fxjs/xfa/cjx_items.h"
-#include "fxjs/xfa/cjx_keep.h"
-#include "fxjs/xfa/cjx_keyusage.h"
-#include "fxjs/xfa/cjx_layoutpseudomodel.h"
-#include "fxjs/xfa/cjx_line.h"
-#include "fxjs/xfa/cjx_linear.h"
-#include "fxjs/xfa/cjx_logpseudomodel.h"
-#include "fxjs/xfa/cjx_manifest.h"
-#include "fxjs/xfa/cjx_map.h"
-#include "fxjs/xfa/cjx_margin.h"
-#include "fxjs/xfa/cjx_mdp.h"
-#include "fxjs/xfa/cjx_medium.h"
-#include "fxjs/xfa/cjx_message.h"
-#include "fxjs/xfa/cjx_node.h"
-#include "fxjs/xfa/cjx_numericedit.h"
-#include "fxjs/xfa/cjx_occur.h"
-#include "fxjs/xfa/cjx_oid.h"
-#include "fxjs/xfa/cjx_oids.h"
-#include "fxjs/xfa/cjx_operation.h"
-#include "fxjs/xfa/cjx_overflow.h"
-#include "fxjs/xfa/cjx_packet.h"
-#include "fxjs/xfa/cjx_pagearea.h"
-#include "fxjs/xfa/cjx_pageset.h"
-#include "fxjs/xfa/cjx_para.h"
-#include "fxjs/xfa/cjx_password.h"
-#include "fxjs/xfa/cjx_passwordedit.h"
-#include "fxjs/xfa/cjx_pattern.h"
-#include "fxjs/xfa/cjx_picture.h"
-#include "fxjs/xfa/cjx_query.h"
-#include "fxjs/xfa/cjx_radial.h"
-#include "fxjs/xfa/cjx_reason.h"
-#include "fxjs/xfa/cjx_reasons.h"
-#include "fxjs/xfa/cjx_recordset.h"
-#include "fxjs/xfa/cjx_rectangle.h"
-#include "fxjs/xfa/cjx_ref.h"
-#include "fxjs/xfa/cjx_rootelement.h"
-#include "fxjs/xfa/cjx_script.h"
-#include "fxjs/xfa/cjx_select.h"
-#include "fxjs/xfa/cjx_setproperty.h"
-#include "fxjs/xfa/cjx_signature.h"
-#include "fxjs/xfa/cjx_signatureproperties.h"
-#include "fxjs/xfa/cjx_signaturepseudomodel.h"
-#include "fxjs/xfa/cjx_signdata.h"
-#include "fxjs/xfa/cjx_signing.h"
-#include "fxjs/xfa/cjx_soapaction.h"
-#include "fxjs/xfa/cjx_soapaddress.h"
-#include "fxjs/xfa/cjx_solid.h"
-#include "fxjs/xfa/cjx_source.h"
-#include "fxjs/xfa/cjx_sourceset.h"
-#include "fxjs/xfa/cjx_speak.h"
-#include "fxjs/xfa/cjx_stipple.h"
-#include "fxjs/xfa/cjx_subform.h"
-#include "fxjs/xfa/cjx_subformset.h"
-#include "fxjs/xfa/cjx_subjectdn.h"
-#include "fxjs/xfa/cjx_subjectdns.h"
-#include "fxjs/xfa/cjx_submit.h"
-#include "fxjs/xfa/cjx_text.h"
-#include "fxjs/xfa/cjx_textedit.h"
-#include "fxjs/xfa/cjx_time.h"
-#include "fxjs/xfa/cjx_timestamp.h"
-#include "fxjs/xfa/cjx_tooltip.h"
-#include "fxjs/xfa/cjx_traversal.h"
-#include "fxjs/xfa/cjx_traverse.h"
-#include "fxjs/xfa/cjx_tree.h"
-#include "fxjs/xfa/cjx_treelist.h"
-#include "fxjs/xfa/cjx_ui.h"
-#include "fxjs/xfa/cjx_update.h"
-#include "fxjs/xfa/cjx_uri.h"
-#include "fxjs/xfa/cjx_user.h"
-#include "fxjs/xfa/cjx_validate.h"
-#include "fxjs/xfa/cjx_value.h"
-#include "fxjs/xfa/cjx_variables.h"
-#include "fxjs/xfa/cjx_wsdladdress.h"
-#include "fxjs/xfa/cjx_wsdlconnection.h"
-#include "fxjs/xfa/cjx_xfa.h"
-#include "fxjs/xfa/cjx_xmlconnection.h"
-#include "fxjs/xfa/cjx_xsdconnection.h"
-#include "xfa/fxfa/fxfa_basic.h"
-
-const XFA_SCRIPTHIERARCHY g_XFAScriptIndex[] = {
-    {/* ps */ 0, 2, 316},
-    {/* to */ 2, 2, 316},
-    {/* ui */ 4, 2, 316},
-    {/* recordSet */ 6, 8, 316},
-    {/* subsetBelow */ 14, 4, 316},
-    {/* subformSet */ 18, 5, 317},
-    {/* adobeExtensionLevel */ 23, 2, 316},
-    {/* typeface */ 25, 1, 316},
-    {/* break */ 26, 12, 316},
-    {/* fontInfo */ 38, 2, 316},
-    {/* numberPattern */ 40, 1, 316},
-    {/* dynamicRender */ 41, 3, 316},
-    {/* printScaling */ 44, 2, 316},
-    {/* checkButton */ 46, 6, 316},
-    {/* datePatterns */ 52, 0, 316},
-    {/* sourceSet */ 52, 2, 319},
-    {/* amd */ 54, 2, 316},
-    {/* arc */ 56, 6, 316},
-    {/* day */ 62, 0, 316},
-    {/* era */ 62, 0, 316},
-    {/* jog */ 62, 2, 316},
-    {/* log */ 64, 2, 316},
-    {/* map */ 66, 6, 316},
-    {/* mdp */ 72, 4, 316},
-    {/* breakBefore */ 76, 7, 316},
-    {/* oid */ 83, 2, 320},
-    {/* pcl */ 85, 3, 316},
-    {/* pdf */ 88, 3, 316},
-    {/* ref */ 91, 2, 320},
-    {/* uri */ 93, 6, 320},
-    {/* xdc */ 99, 4, 316},
-    {/* xdp */ 103, 2, 316},
-    {/* xfa */ 105, 3, 319},
-    {/* xsl */ 108, 4, 316},
-    {/* zpl */ 112, 3, 316},
-    {/* cache */ 115, 2, 316},
-    {/* margin */ 117, 6, 316},
-    {/* keyUsage */ 123, 12, 316},
-    {/* exclude */ 135, 2, 316},
-    {/* choiceList */ 137, 5, 316},
-    {/* level */ 142, 2, 316},
-    {/* labelPrinter */ 144, 3, 316},
-    {/* calendarSymbols */ 147, 1, 316},
-    {/* para */ 148, 14, 316},
-    {/* part */ 162, 2, 316},
-    {/* pdfa */ 164, 2, 316},
-    {/* filter */ 166, 3, 316},
-    {/* present */ 169, 2, 316},
-    {/* pagination */ 171, 2, 316},
-    {/* encoding */ 173, 2, 316},
-    {/* event */ 175, 4, 316},
-    {/* whitespace */ 179, 2, 316},
-    {/* defaultUi */ 181, 2, 316},
-    {/* dataModel */ 183, 0, 319},
-    {/* barcode */ 183, 20, 316},
-    {/* timePattern */ 203, 1, 316},
-    {/* batchOutput */ 204, 3, 316},
-    {/* enforce */ 207, 2, 316},
-    {/* currencySymbols */ 209, 0, 316},
-    {/* addSilentPrint */ 209, 2, 316},
-    {/* rename */ 211, 2, 316},
-    {/* operation */ 213, 4, 320},
-    {/* typefaces */ 217, 0, 316},
-    {/* subjectDNs */ 217, 1, 316},
-    {/* issuers */ 218, 3, 316},
-    {/* signaturePseudoModel */ 221, 0, 312},
-    {/* wsdlConnection */ 221, 1, 316},
-    {/* debug */ 222, 2, 316},
-    {/* delta */ 224, 3, -1},
-    {/* eraNames */ 227, 0, 316},
-    {/* modifyAnnots */ 227, 2, 316},
-    {/* startNode */ 229, 2, 316},
-    {/* button */ 231, 3, 316},
-    {/* format */ 234, 2, 316},
-    {/* border */ 236, 6, 316},
-    {/* area */ 242, 10, 317},
-    {/* hyphenation */ 252, 9, 316},
-    {/* text */ 261, 5, 318},
-    {/* time */ 266, 4, 318},
-    {/* type */ 270, 2, 316},
-    {/* overprint */ 272, 2, 316},
-    {/* certificates */ 274, 5, 316},
-    {/* encryptionMethods */ 279, 3, 316},
-    {/* setProperty */ 282, 2, 316},
-    {/* printerName */ 284, 2, 316},
-    {/* startPage */ 286, 2, 316},
-    {/* pageOffset */ 288, 2, 316},
-    {/* dateTime */ 290, 4, 316},
-    {/* comb */ 294, 3, 316},
-    {/* pattern */ 297, 3, 316},
-    {/* ifEmpty */ 300, 2, 316},
-    {/* suppressBanner */ 302, 2, 316},
-    {/* outputBin */ 304, 2, 316},
-    {/* field */ 306, 36, 317},
-    {/* agent */ 342, 3, 316},
-    {/* outputXSL */ 345, 2, 316},
-    {/* adjustData */ 347, 2, 316},
-    {/* autoSave */ 349, 2, 316},
-    {/* contentArea */ 351, 7, 317},
-    {/* eventPseudoModel */ 358, 16, 312},
-    {/* wsdlAddress */ 374, 2, 320},
-    {/* solid */ 376, 2, 316},
-    {/* dateTimeSymbols */ 378, 0, 316},
-    {/* encryptionLevel */ 378, 2, 316},
-    {/* edge */ 380, 6, 316},
-    {/* stipple */ 386, 3, 316},
-    {/* attributes */ 389, 2, 316},
-    {/* versionControl */ 391, 4, 316},
-    {/* meridiem */ 395, 0, 316},
-    {/* exclGroup */ 395, 30, 316},
-    {/* toolTip */ 425, 2, 320},
-    {/* compress */ 427, 3, 316},
-    {/* reason */ 430, 2, 320},
-    {/* execute */ 432, 5, 316},
-    {/* contentCopy */ 437, 2, 316},
-    {/* dateTimeEdit */ 439, 3, 316},
-    {/* config */ 442, 2, 316},
-    {/* image */ 444, 8, 316},
-    {/* #xHTML */ 452, 1, 316},
-    {/* numberOfCopies */ 453, 2, 316},
-    {/* behaviorOverride */ 455, 2, 316},
-    {/* timeStamp */ 457, 4, 316},
-    {/* month */ 461, 0, 316},
-    {/* viewerPreferences */ 461, 2, 316},
-    {/* scriptModel */ 463, 2, 316},
-    {/* decimal */ 465, 6, 318},
-    {/* subform */ 471, 31, 317},
-    {/* select */ 502, 2, 320},
-    {/* window */ 504, 2, 316},
-    {/* localeSet */ 506, 2, 316},
-    {/* handler */ 508, 4, 320},
-    {/* hostPseudoModel */ 512, 11, 312},
-    {/* presence */ 523, 2, 316},
-    {/* record */ 525, 2, 316},
-    {/* embed */ 527, 2, 316},
-    {/* version */ 529, 2, 316},
-    {/* command */ 531, 3, 316},
-    {/* copies */ 534, 2, 316},
-    {/* staple */ 536, 3, 316},
-    {/* submitFormat */ 539, 3, 316},
-    {/* boolean */ 542, 4, 318},
-    {/* message */ 546, 4, 316},
-    {/* output */ 550, 2, 316},
-    {/* psMap */ 552, 0, 316},
-    {/* excludeNS */ 552, 2, 316},
-    {/* assist */ 554, 3, 316},
-    {/* picture */ 557, 6, 316},
-    {/* traversal */ 563, 2, 316},
-    {/* silentPrint */ 565, 2, 316},
-    {/* webClient */ 567, 3, 316},
-    {/* layoutPseudoModel */ 570, 1, 312},
-    {/* producer */ 571, 2, 316},
-    {/* corner */ 573, 8, 316},
-    {/* msgId */ 581, 2, 316},
-    {/* color */ 583, 4, 316},
-    {/* keep */ 587, 5, 316},
-    {/* query */ 592, 3, 316},
-    {/* insert */ 595, 2, 320},
-    {/* imageEdit */ 597, 3, 316},
-    {/* validate */ 600, 7, 316},
-    {/* digestMethods */ 607, 3, 316},
-    {/* numberPatterns */ 610, 0, 316},
-    {/* pageSet */ 610, 4, 317},
-    {/* integer */ 614, 4, 318},
-    {/* soapAddress */ 618, 2, 320},
-    {/* equate */ 620, 5, 316},
-    {/* formFieldFilling */ 625, 2, 316},
-    {/* pageRange */ 627, 2, 316},
-    {/* update */ 629, 2, 320},
-    {/* connectString */ 631, 2, 320},
-    {/* mode */ 633, 4, 316},
-    {/* layout */ 637, 2, 316},
-    {/* #xml */ 639, 1, 316},
-    {/* xsdConnection */ 640, 1, 316},
-    {/* traverse */ 641, 4, 316},
-    {/* encodings */ 645, 3, 316},
-    {/* template */ 648, 2, 319},
-    {/* acrobat */ 650, 2, 316},
-    {/* validationMessaging */ 652, 2, 316},
-    {/* signing */ 654, 3, 316},
-    {/* dataWindow */ 657, 4, 312},
-    {/* script */ 661, 10, 316},
-    {/* addViewerPreferences */ 671, 2, 316},
-    {/* alwaysEmbed */ 673, 4, 316},
-    {/* passwordEdit */ 677, 4, 316},
-    {/* numericEdit */ 681, 3, 316},
-    {/* encryptionMethod */ 684, 2, 316},
-    {/* change */ 686, 2, 316},
-    {/* pageArea */ 688, 8, 317},
-    {/* submitUrl */ 696, 3, 316},
-    {/* oids */ 699, 3, 316},
-    {/* signature */ 702, 2, 316},
-    {/* ADBE_JSConsole */ 704, 2, 316},
-    {/* caption */ 706, 5, 316},
-    {/* relevant */ 711, 4, 316},
-    {/* flipLabel */ 715, 2, 316},
-    {/* exData */ 717, 8, 318},
-    {/* dayNames */ 725, 1, 316},
-    {/* soapAction */ 726, 2, 320},
-    {/* defaultTypeface */ 728, 3, 316},
-    {/* manifest */ 731, 4, 316},
-    {/* overflow */ 735, 5, 316},
-    {/* linear */ 740, 3, 316},
-    {/* currencySymbol */ 743, 1, 316},
-    {/* delete */ 744, 2, 320},
-    {/* deltas */ 746, 0, 313},
-    {/* digestMethod */ 746, 2, 316},
-    {/* instanceManager */ 748, 3, 316},
-    {/* equateRange */ 751, 5, 316},
-    {/* medium */ 756, 7, 316},
-    {/* textEdit */ 763, 6, 316},
-    {/* templateCache */ 769, 3, 316},
-    {/* compressObjectStream */ 772, 2, 316},
-    {/* dataValue */ 774, 5, 316},
-    {/* accessibleContent */ 779, 2, 316},
-    {/* nodeList */ 781, 0, 314},
-    {/* includeXDPContent */ 781, 2, 316},
-    {/* xmlConnection */ 783, 1, 316},
-    {/* validateApprovalSignatures */ 784, 2, 316},
-    {/* signData */ 786, 5, 316},
-    {/* packets */ 791, 2, 316},
-    {/* datePattern */ 793, 1, 316},
-    {/* duplexOption */ 794, 2, 316},
-    {/* base */ 796, 2, 316},
-    {/* bind */ 798, 6, 316},
-    {/* compression */ 804, 2, 316},
-    {/* user */ 806, 2, 320},
-    {/* rectangle */ 808, 3, 316},
-    {/* effectiveOutputPolicy */ 811, 4, 316},
-    {/* ADBE_JSDebugger */ 815, 2, 316},
-    {/* acrobat7 */ 817, 2, 316},
-    {/* interactive */ 819, 2, 316},
-    {/* locale */ 821, 2, 316},
-    {/* currentPage */ 823, 2, 316},
-    {/* data */ 825, 2, 316},
-    {/* date */ 827, 4, 318},
-    {/* desc */ 831, 2, 316},
-    {/* encrypt */ 833, 5, 316},
-    {/* draw */ 838, 20, 317},
-    {/* encryption */ 858, 2, 316},
-    {/* meridiemNames */ 860, 0, 316},
-    {/* messaging */ 860, 2, 316},
-    {/* speak */ 862, 4, 320},
-    {/* dataGroup */ 866, 0, 316},
-    {/* common */ 866, 2, 316},
-    {/* #text */ 868, 1, 316},
-    {/* paginationOverride */ 869, 2, 316},
-    {/* reasons */ 871, 3, 316},
-    {/* signatureProperties */ 874, 2, 316},
-    {/* threshold */ 876, 2, 316},
-    {/* appearanceFilter */ 878, 4, 316},
-    {/* fill */ 882, 3, 316},
-    {/* font */ 885, 17, 316},
-    {/* form */ 902, 1, 319},
-    {/* mediumInfo */ 903, 2, 316},
-    {/* certificate */ 905, 2, 320},
-    {/* password */ 907, 2, 320},
-    {/* runScripts */ 909, 2, 316},
-    {/* trace */ 911, 2, 316},
-    {/* float */ 913, 4, 318},
-    {/* renderPolicy */ 917, 2, 316},
-    {/* logPseudoModel */ 919, 0, 312},
-    {/* destination */ 919, 2, 316},
-    {/* value */ 921, 4, 316},
-    {/* bookend */ 925, 4, 316},
-    {/* exObject */ 929, 6, 316},
-    {/* openAction */ 935, 2, 316},
-    {/* neverEmbed */ 937, 4, 316},
-    {/* bindItems */ 941, 3, 316},
-    {/* calculate */ 944, 3, 316},
-    {/* print */ 947, 2, 316},
-    {/* extras */ 949, 3, 316},
-    {/* proto */ 952, 0, 316},
-    {/* dSigData */ 952, 0, 316},
-    {/* creator */ 952, 2, 316},
-    {/* connect */ 954, 7, 316},
-    {/* permissions */ 961, 2, 316},
-    {/* connectionSet */ 963, 0, 319},
-    {/* submit */ 963, 7, 316},
-    {/* range */ 970, 2, 316},
-    {/* linearized */ 972, 2, 316},
-    {/* packet */ 974, 1, 316},
-    {/* rootElement */ 975, 2, 320},
-    {/* plaintextMetadata */ 977, 4, 316},
-    {/* numberSymbols */ 981, 0, 316},
-    {/* printHighQuality */ 981, 2, 316},
-    {/* driver */ 983, 2, 316},
-    {/* incrementalLoad */ 985, 4, 316},
-    {/* subjectDN */ 989, 1, 316},
-    {/* compressLogicalStructure */ 990, 2, 316},
-    {/* incrementalMerge */ 992, 2, 316},
-    {/* radial */ 994, 3, 316},
-    {/* variables */ 997, 2, 317},
-    {/* timePatterns */ 999, 0, 316},
-    {/* effectiveInputPolicy */ 999, 4, 316},
-    {/* nameAttr */ 1003, 4, 316},
-    {/* conformance */ 1007, 2, 316},
-    {/* transform */ 1009, 3, 316},
-    {/* lockDocument */ 1012, 4, 316},
-    {/* breakAfter */ 1016, 7, 316},
-    {/* line */ 1023, 4, 316},
-    {/* list */ 1027, 1, 313},
-    {/* source */ 1028, 3, 316},
-    {/* occur */ 1031, 5, 316},
-    {/* pickTrayByPDFSize */ 1036, 2, 316},
-    {/* monthNames */ 1038, 1, 316},
-    {/* severity */ 1039, 4, 316},
-    {/* groupParent */ 1043, 2, 316},
-    {/* documentAssembly */ 1045, 2, 316},
-    {/* numberSymbol */ 1047, 1, 316},
-    {/* tagged */ 1048, 2, 316},
-    {/*  */ 1050, 5, 316},
-    {/*  */ 1055, 1, -1},
-    {/*  */ 1056, 1, 312},
-    {/*  */ 1057, 0, 313},
-    {/*  */ 1057, 8, 312},
-    {/*  */ 1065, 6, 315},
-    {/*  */ 1071, 0, 316},
-    {/*  */ 1071, 0, 316},
-    {/*  */ 1071, 2, 316},
-    {/*  */ 1073, 2, 316},
-};
-const int32_t g_iScriptIndexCount =
-    sizeof(g_XFAScriptIndex) / sizeof(XFA_SCRIPTHIERARCHY);
-const XFA_SCRIPTATTRIBUTEINFO g_SomAttributeData[] = {
-    /* ps */
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-
-    /* to */
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-
-    /* ui */
-    {0xc0811ed, L"use", (XFA_ATTRIBUTE_CALLBACK)&CJX_Ui::use,
-     XFA_Attribute::Use, XFA_ScriptType::Basic},
-    {0xbc254332, L"usehref", (XFA_ATTRIBUTE_CALLBACK)&CJX_Ui::usehref,
-     XFA_Attribute::Usehref, XFA_ScriptType::Basic},
-
-    /* recordSet */
-    {0xb3543a6, L"max", (XFA_ATTRIBUTE_CALLBACK)&CJX_RecordSet::max,
-     XFA_Attribute::Max, XFA_ScriptType::Basic},
-    {0xc0811ed, L"use", (XFA_ATTRIBUTE_CALLBACK)&CJX_RecordSet::use,
-     XFA_Attribute::Use, XFA_ScriptType::Basic},
-    {0x45a6daf8, L"eofAction",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_RecordSet::eofAction,
-     XFA_Attribute::EofAction, XFA_ScriptType::Basic},
-    {0x5ec958c0, L"cursorType",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_RecordSet::cursorType,
-     XFA_Attribute::CursorType, XFA_ScriptType::Basic},
-    {0x79975f2b, L"lockType", (XFA_ATTRIBUTE_CALLBACK)&CJX_RecordSet::lockType,
-     XFA_Attribute::LockType, XFA_ScriptType::Basic},
-    {0xa5340ff5, L"bofAction",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_RecordSet::bofAction,
-     XFA_Attribute::BofAction, XFA_ScriptType::Basic},
-    {0xbc254332, L"usehref", (XFA_ATTRIBUTE_CALLBACK)&CJX_RecordSet::usehref,
-     XFA_Attribute::Usehref, XFA_ScriptType::Basic},
-    {0xc5762157, L"cursorLocation",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_RecordSet::cursorLocation,
-     XFA_Attribute::CursorLocation, XFA_ScriptType::Basic},
-
-    /* subsetBelow */
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-
-    /* subformSet */
-    {0xc0811ed, L"use", (XFA_ATTRIBUTE_CALLBACK)&CJX_SubformSet::use,
-     XFA_Attribute::Use, XFA_ScriptType::Basic},
-    {0x1ee2d24d, L"instanceIndex",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_SubformSet::instanceIndex,
-     XFA_Attribute::Unknown, XFA_ScriptType::Basic},
-    {0x8c99377e, L"relation", (XFA_ATTRIBUTE_CALLBACK)&CJX_SubformSet::relation,
-     XFA_Attribute::Relation, XFA_ScriptType::Basic},
-    {0x8e1c2921, L"relevant", (XFA_ATTRIBUTE_CALLBACK)&CJX_SubformSet::relevant,
-     XFA_Attribute::Relevant, XFA_ScriptType::Basic},
-    {0xbc254332, L"usehref", (XFA_ATTRIBUTE_CALLBACK)&CJX_SubformSet::usehref,
-     XFA_Attribute::Usehref, XFA_ScriptType::Basic},
-
-    /* adobeExtensionLevel */
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-
-    /* typeface */
-    {0x31b19c1, L"name",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Name, XFA_ScriptType::Basic},
-
-    /* break */
-    {0x3106c3a, L"beforeTarget",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Break::beforeTarget,
-     XFA_Attribute::BeforeTarget, XFA_ScriptType::Basic},
-    {0xc0811ed, L"use", (XFA_ATTRIBUTE_CALLBACK)&CJX_Break::use,
-     XFA_Attribute::Use, XFA_ScriptType::Basic},
-    {0x13a08bdb, L"overflowTarget",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Break::overflowTarget,
-     XFA_Attribute::OverflowTarget, XFA_ScriptType::Basic},
-    {0x169134a1, L"overflowLeader",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Break::overflowLeader,
-     XFA_Attribute::OverflowLeader, XFA_ScriptType::Basic},
-    {0x20914367, L"overflowTrailer",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Break::overflowTrailer,
-     XFA_Attribute::OverflowTrailer, XFA_ScriptType::Basic},
-    {0x453eaf38, L"startNew", (XFA_ATTRIBUTE_CALLBACK)&CJX_Break::startNew,
-     XFA_Attribute::StartNew, XFA_ScriptType::Basic},
-    {0x64110ab5, L"bookendTrailer",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Break::bookendTrailer,
-     XFA_Attribute::BookendTrailer, XFA_ScriptType::Basic},
-    {0xb6b44172, L"after", (XFA_ATTRIBUTE_CALLBACK)&CJX_Break::after,
-     XFA_Attribute::After, XFA_ScriptType::Basic},
-    {0xbc254332, L"usehref", (XFA_ATTRIBUTE_CALLBACK)&CJX_Break::usehref,
-     XFA_Attribute::Usehref, XFA_ScriptType::Basic},
-    {0xc3c1442f, L"bookendLeader",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Break::bookendLeader,
-     XFA_Attribute::BookendLeader, XFA_ScriptType::Basic},
-    {0xcb150479, L"afterTarget",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Break::afterTarget,
-     XFA_Attribute::AfterTarget, XFA_ScriptType::Basic},
-    {0xf4ffce73, L"before", (XFA_ATTRIBUTE_CALLBACK)&CJX_Break::before,
-     XFA_Attribute::Before, XFA_ScriptType::Basic},
-
-    /* fontInfo */
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-
-    /* numberPattern */
-    {0x31b19c1, L"name",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Name, XFA_ScriptType::Basic},
-
-    /* dynamicRender */
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xd6e27f1d, L"value",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Som_DefaultValue_Read,
-     XFA_Attribute::Unknown, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-
-    /* printScaling */
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-
-    /* checkButton */
-    {0xc0811ed, L"use", (XFA_ATTRIBUTE_CALLBACK)&CJX_CheckButton::use,
-     XFA_Attribute::Use, XFA_ScriptType::Basic},
-    {0x47cfa43a, L"allowNeutral",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_CheckButton::allowNeutral,
-     XFA_Attribute::AllowNeutral, XFA_ScriptType::Basic},
-    {0x7c2fd80b, L"mark", (XFA_ATTRIBUTE_CALLBACK)&CJX_CheckButton::mark,
-     XFA_Attribute::Mark, XFA_ScriptType::Basic},
-    {0x8ed182d1, L"shape", (XFA_ATTRIBUTE_CALLBACK)&CJX_CheckButton::shape,
-     XFA_Attribute::Shape, XFA_ScriptType::Basic},
-    {0xa686975b, L"size", (XFA_ATTRIBUTE_CALLBACK)&CJX_CheckButton::size,
-     XFA_Attribute::Size, XFA_ScriptType::Basic},
-    {0xbc254332, L"usehref", (XFA_ATTRIBUTE_CALLBACK)&CJX_CheckButton::usehref,
-     XFA_Attribute::Usehref, XFA_ScriptType::Basic},
-
-    /* datePatterns */
-
-    /* sourceSet */
-    {0xc0811ed, L"use", (XFA_ATTRIBUTE_CALLBACK)&CJX_SourceSet::use,
-     XFA_Attribute::Use, XFA_ScriptType::Basic},
-    {0xbc254332, L"usehref", (XFA_ATTRIBUTE_CALLBACK)&CJX_SourceSet::usehref,
-     XFA_Attribute::Usehref, XFA_ScriptType::Basic},
-
-    /* amd */
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-
-    /* arc */
-    {0xc0811ed, L"use", (XFA_ATTRIBUTE_CALLBACK)&CJX_Arc::use,
-     XFA_Attribute::Use, XFA_ScriptType::Basic},
-    {0x5c054755, L"startAngle", (XFA_ATTRIBUTE_CALLBACK)&CJX_Arc::startAngle,
-     XFA_Attribute::StartAngle, XFA_ScriptType::Basic},
-    {0x74788f8b, L"sweepAngle", (XFA_ATTRIBUTE_CALLBACK)&CJX_Arc::sweepAngle,
-     XFA_Attribute::SweepAngle, XFA_ScriptType::Basic},
-    {0x9d833d75, L"circular", (XFA_ATTRIBUTE_CALLBACK)&CJX_Arc::circular,
-     XFA_Attribute::Circular, XFA_ScriptType::Basic},
-    {0xbc254332, L"usehref", (XFA_ATTRIBUTE_CALLBACK)&CJX_Arc::usehref,
-     XFA_Attribute::Usehref, XFA_ScriptType::Basic},
-    {0xd996fa9b, L"hand", (XFA_ATTRIBUTE_CALLBACK)&CJX_Arc::hand,
-     XFA_Attribute::Hand, XFA_ScriptType::Basic},
-
-    /* day */
-
-    /* era */
-
-    /* jog */
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-
-    /* log */
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-
-    /* map */
-    {0xc0811ed, L"use", (XFA_ATTRIBUTE_CALLBACK)&CJX_Map::use,
-     XFA_Attribute::Use, XFA_ScriptType::Basic},
-    {0xb0e5485d, L"bind", (XFA_ATTRIBUTE_CALLBACK)&CJX_Map::bind,
-     XFA_Attribute::Bind, XFA_ScriptType::Basic},
-    {0xbc254332, L"usehref", (XFA_ATTRIBUTE_CALLBACK)&CJX_Map::usehref,
-     XFA_Attribute::Usehref, XFA_ScriptType::Basic},
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xcd7f7b54, L"from", (XFA_ATTRIBUTE_CALLBACK)&CJX_Map::from,
-     XFA_Attribute::From, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-
-    /* mdp */
-    {0xc0811ed, L"use", (XFA_ATTRIBUTE_CALLBACK)&CJX_Mdp::use,
-     XFA_Attribute::Use, XFA_ScriptType::Basic},
-    {0x8e29d794, L"signatureType",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Mdp::signatureType,
-     XFA_Attribute::SignatureType, XFA_ScriptType::Basic},
-    {0xbc254332, L"usehref", (XFA_ATTRIBUTE_CALLBACK)&CJX_Mdp::usehref,
-     XFA_Attribute::Usehref, XFA_ScriptType::Basic},
-    {0xe11a2cbc, L"permissions", (XFA_ATTRIBUTE_CALLBACK)&CJX_Mdp::permissions,
-     XFA_Attribute::Permissions, XFA_ScriptType::Basic},
-
-    /* breakBefore */
-    {0xc0811ed, L"use", (XFA_ATTRIBUTE_CALLBACK)&CJX_BreakBefore::use,
-     XFA_Attribute::Use, XFA_ScriptType::Basic},
-    {0x453eaf38, L"startNew",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_BreakBefore::startNew,
-     XFA_Attribute::StartNew, XFA_ScriptType::Basic},
-    {0x9dcc3ab3, L"trailer", (XFA_ATTRIBUTE_CALLBACK)&CJX_BreakBefore::trailer,
-     XFA_Attribute::Trailer, XFA_ScriptType::Basic},
-    {0xa6118c89, L"targetType",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_BreakBefore::targetType,
-     XFA_Attribute::TargetType, XFA_ScriptType::Basic},
-    {0xbc254332, L"usehref", (XFA_ATTRIBUTE_CALLBACK)&CJX_BreakBefore::usehref,
-     XFA_Attribute::Usehref, XFA_ScriptType::Basic},
-    {0xc8da4da7, L"target", (XFA_ATTRIBUTE_CALLBACK)&CJX_BreakBefore::target,
-     XFA_Attribute::Target, XFA_ScriptType::Basic},
-    {0xcbcaf66d, L"leader", (XFA_ATTRIBUTE_CALLBACK)&CJX_BreakBefore::leader,
-     XFA_Attribute::Leader, XFA_ScriptType::Basic},
-
-    /* oid */
-    {0xc0811ed, L"use", (XFA_ATTRIBUTE_CALLBACK)&CJX_Oid::use,
-     XFA_Attribute::Use, XFA_ScriptType::Basic},
-    {0xbc254332, L"usehref", (XFA_ATTRIBUTE_CALLBACK)&CJX_Oid::usehref,
-     XFA_Attribute::Usehref, XFA_ScriptType::Basic},
-
-    /* pcl */
-    {0x31b19c1, L"name",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Name, XFA_ScriptType::Basic},
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-
-    /* pdf */
-    {0x31b19c1, L"name",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Name, XFA_ScriptType::Basic},
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-
-    /* ref */
-    {0xc0811ed, L"use", (XFA_ATTRIBUTE_CALLBACK)&CJX_Ref::use,
-     XFA_Attribute::Use, XFA_ScriptType::Basic},
-    {0xbc254332, L"usehref", (XFA_ATTRIBUTE_CALLBACK)&CJX_Ref::usehref,
-     XFA_Attribute::Usehref, XFA_ScriptType::Basic},
-
-    /* uri */
-    {0xc0811ed, L"use", (XFA_ATTRIBUTE_CALLBACK)&CJX_Uri::use,
-     XFA_Attribute::Use, XFA_ScriptType::Basic},
-    {0xbc254332, L"usehref", (XFA_ATTRIBUTE_CALLBACK)&CJX_Uri::usehref,
-     XFA_Attribute::Usehref, XFA_ScriptType::Basic},
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-
-    /* xdc */
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-
-    /* xdp */
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-
-    /* xfa */
-    {0x2d574d58, L"this", (XFA_ATTRIBUTE_CALLBACK)&CJX_Xfa::thisValue,
-     XFA_Attribute::Unknown, XFA_ScriptType::Object},
-    {0x4fdc3454, L"timeStamp", (XFA_ATTRIBUTE_CALLBACK)&CJX_Xfa::timeStamp,
-     XFA_Attribute::TimeStamp, XFA_ScriptType::Basic},
-    {0xb598a1f7, L"uuid", (XFA_ATTRIBUTE_CALLBACK)&CJX_Xfa::uuid,
-     XFA_Attribute::Uuid, XFA_ScriptType::Basic},
-
-    /* xsl */
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-
-    /* zpl */
-    {0x31b19c1, L"name",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Name, XFA_ScriptType::Basic},
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-
-    /* cache */
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-
-    /* margin */
-    {0xc0811ed, L"use", (XFA_ATTRIBUTE_CALLBACK)&CJX_Margin::use,
-     XFA_Attribute::Use, XFA_ScriptType::Basic},
-    {0xcfea02e, L"leftInset", (XFA_ATTRIBUTE_CALLBACK)&CJX_Margin::leftInset,
-     XFA_Attribute::LeftInset, XFA_ScriptType::Basic},
-    {0x1356caf8, L"bottomInset",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Margin::bottomInset,
-     XFA_Attribute::BottomInset, XFA_ScriptType::Basic},
-    {0x25764436, L"topInset", (XFA_ATTRIBUTE_CALLBACK)&CJX_Margin::topInset,
-     XFA_Attribute::TopInset, XFA_ScriptType::Basic},
-    {0x8a692521, L"rightInset", (XFA_ATTRIBUTE_CALLBACK)&CJX_Margin::rightInset,
-     XFA_Attribute::RightInset, XFA_ScriptType::Basic},
-    {0xbc254332, L"usehref", (XFA_ATTRIBUTE_CALLBACK)&CJX_Margin::usehref,
-     XFA_Attribute::Usehref, XFA_ScriptType::Basic},
-
-    /* keyUsage */
-    {0xc0811ed, L"use", (XFA_ATTRIBUTE_CALLBACK)&CJX_KeyUsage::use,
-     XFA_Attribute::Use, XFA_ScriptType::Basic},
-    {0x1e459b8f, L"nonRepudiation",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_KeyUsage::nonRepudiation,
-     XFA_Attribute::NonRepudiation, XFA_ScriptType::Basic},
-    {0x2bb3f470, L"encipherOnly",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_KeyUsage::encipherOnly,
-     XFA_Attribute::EncipherOnly, XFA_ScriptType::Basic},
-    {0x2f16a382, L"type", (XFA_ATTRIBUTE_CALLBACK)&CJX_KeyUsage::type,
-     XFA_Attribute::Type, XFA_ScriptType::Basic},
-    {0x5f760b50, L"digitalSignature",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_KeyUsage::digitalSignature,
-     XFA_Attribute::DigitalSignature, XFA_ScriptType::Basic},
-    {0x69aa2292, L"crlSign", (XFA_ATTRIBUTE_CALLBACK)&CJX_KeyUsage::crlSign,
-     XFA_Attribute::CrlSign, XFA_ScriptType::Basic},
-    {0x98fd4d81, L"keyAgreement",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_KeyUsage::keyAgreement,
-     XFA_Attribute::KeyAgreement, XFA_ScriptType::Basic},
-    {0xa66404cb, L"keyEncipherment",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_KeyUsage::keyEncipherment,
-     XFA_Attribute::KeyEncipherment, XFA_ScriptType::Basic},
-    {0xbc254332, L"usehref", (XFA_ATTRIBUTE_CALLBACK)&CJX_KeyUsage::usehref,
-     XFA_Attribute::Usehref, XFA_ScriptType::Basic},
-    {0xca5dc27c, L"dataEncipherment",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_KeyUsage::dataEncipherment,
-     XFA_Attribute::DataEncipherment, XFA_ScriptType::Basic},
-    {0xe8f118a8, L"keyCertSign",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_KeyUsage::keyCertSign,
-     XFA_Attribute::KeyCertSign, XFA_ScriptType::Basic},
-    {0xfea53ec6, L"decipherOnly",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_KeyUsage::decipherOnly,
-     XFA_Attribute::DecipherOnly, XFA_ScriptType::Basic},
-
-    /* exclude */
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-
-    /* choiceList */
-    {0xc0811ed, L"use", (XFA_ATTRIBUTE_CALLBACK)&CJX_ChoiceList::use,
-     XFA_Attribute::Use, XFA_ScriptType::Basic},
-    {0x8b90e1f2, L"open", (XFA_ATTRIBUTE_CALLBACK)&CJX_ChoiceList::open,
-     XFA_Attribute::Open, XFA_ScriptType::Basic},
-    {0x957fa006, L"commitOn", (XFA_ATTRIBUTE_CALLBACK)&CJX_ChoiceList::commitOn,
-     XFA_Attribute::CommitOn, XFA_ScriptType::Basic},
-    {0xb12128b7, L"textEntry",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_ChoiceList::textEntry,
-     XFA_Attribute::TextEntry, XFA_ScriptType::Basic},
-    {0xbc254332, L"usehref", (XFA_ATTRIBUTE_CALLBACK)&CJX_ChoiceList::usehref,
-     XFA_Attribute::Usehref, XFA_ScriptType::Basic},
-
-    /* level */
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-
-    /* labelPrinter */
-    {0x31b19c1, L"name",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Name, XFA_ScriptType::Basic},
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-
-    /* calendarSymbols */
-    {0x31b19c1, L"name",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Name, XFA_ScriptType::Basic},
-
-    /* para */
-    {0x2282c73, L"hAlign", (XFA_ATTRIBUTE_CALLBACK)&CJX_Para::hAlign,
-     XFA_Attribute::HAlign, XFA_ScriptType::Basic},
-    {0x8d4f1c7, L"textIndent", (XFA_ATTRIBUTE_CALLBACK)&CJX_Para::textIndent,
-     XFA_Attribute::TextIndent, XFA_ScriptType::Basic},
-    {0xc0811ed, L"use", (XFA_ATTRIBUTE_CALLBACK)&CJX_Para::use,
-     XFA_Attribute::Use, XFA_ScriptType::Basic},
-    {0x2a82d99c, L"marginRight", (XFA_ATTRIBUTE_CALLBACK)&CJX_Para::marginRight,
-     XFA_Attribute::MarginRight, XFA_ScriptType::Basic},
-    {0x534729c9, L"marginLeft", (XFA_ATTRIBUTE_CALLBACK)&CJX_Para::marginLeft,
-     XFA_Attribute::MarginLeft, XFA_ScriptType::Basic},
-    {0x5739d1ff, L"radixOffset", (XFA_ATTRIBUTE_CALLBACK)&CJX_Para::radixOffset,
-     XFA_Attribute::RadixOffset, XFA_ScriptType::Basic},
-    {0x577682ac, L"preserve", (XFA_ATTRIBUTE_CALLBACK)&CJX_Para::preserve,
-     XFA_Attribute::Preserve, XFA_ScriptType::Basic},
-    {0x731e0665, L"spaceBelow", (XFA_ATTRIBUTE_CALLBACK)&CJX_Para::spaceBelow,
-     XFA_Attribute::SpaceBelow, XFA_ScriptType::Basic},
-    {0x7a7cc341, L"vAlign", (XFA_ATTRIBUTE_CALLBACK)&CJX_Para::vAlign,
-     XFA_Attribute::VAlign, XFA_ScriptType::Basic},
-    {0x836d4d7c, L"tabDefault", (XFA_ATTRIBUTE_CALLBACK)&CJX_Para::tabDefault,
-     XFA_Attribute::TabDefault, XFA_ScriptType::Basic},
-    {0x8fa01790, L"tabStops", (XFA_ATTRIBUTE_CALLBACK)&CJX_Para::tabStops,
-     XFA_Attribute::TabStops, XFA_ScriptType::Basic},
-    {0xbc254332, L"usehref", (XFA_ATTRIBUTE_CALLBACK)&CJX_Para::usehref,
-     XFA_Attribute::Usehref, XFA_ScriptType::Basic},
-    {0xd4b01921, L"lineHeight", (XFA_ATTRIBUTE_CALLBACK)&CJX_Para::lineHeight,
-     XFA_Attribute::LineHeight, XFA_ScriptType::Basic},
-    {0xe18b5659, L"spaceAbove", (XFA_ATTRIBUTE_CALLBACK)&CJX_Para::spaceAbove,
-     XFA_Attribute::SpaceAbove, XFA_ScriptType::Basic},
-
-    /* part */
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-
-    /* pdfa */
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-
-    /* filter */
-    {0xc0811ed, L"use", (XFA_ATTRIBUTE_CALLBACK)&CJX_Filter::use,
-     XFA_Attribute::Use, XFA_ScriptType::Basic},
-    {0xbc254332, L"usehref", (XFA_ATTRIBUTE_CALLBACK)&CJX_Filter::usehref,
-     XFA_Attribute::Usehref, XFA_ScriptType::Basic},
-    {0xd861f8af, L"addRevocationInfo",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Filter::addRevocationInfo,
-     XFA_Attribute::AddRevocationInfo, XFA_ScriptType::Basic},
-
-    /* present */
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-
-    /* pagination */
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-
-    /* encoding */
-    {0xc0811ed, L"use", (XFA_ATTRIBUTE_CALLBACK)&CJX_Encoding::use,
-     XFA_Attribute::Use, XFA_ScriptType::Basic},
-    {0xbc254332, L"usehref", (XFA_ATTRIBUTE_CALLBACK)&CJX_Encoding::usehref,
-     XFA_Attribute::Usehref, XFA_ScriptType::Basic},
-
-    /* event */
-    {0xbb8df5d, L"ref", (XFA_ATTRIBUTE_CALLBACK)&CJX_Event::ref,
-     XFA_Attribute::Ref, XFA_ScriptType::Basic},
-    {0xc0811ed, L"use", (XFA_ATTRIBUTE_CALLBACK)&CJX_Event::use,
-     XFA_Attribute::Use, XFA_ScriptType::Basic},
-    {0xbc254332, L"usehref", (XFA_ATTRIBUTE_CALLBACK)&CJX_Event::usehref,
-     XFA_Attribute::Usehref, XFA_ScriptType::Basic},
-    {0xd6128d8d, L"activity", (XFA_ATTRIBUTE_CALLBACK)&CJX_Event::activity,
-     XFA_Attribute::Activity, XFA_ScriptType::Basic},
-
-    /* whitespace */
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-
-    /* defaultUi */
-    {0xc0811ed, L"use", (XFA_ATTRIBUTE_CALLBACK)&CJX_DefaultUi::use,
-     XFA_Attribute::Use, XFA_ScriptType::Basic},
-    {0xbc254332, L"usehref", (XFA_ATTRIBUTE_CALLBACK)&CJX_DefaultUi::usehref,
-     XFA_Attribute::Usehref, XFA_ScriptType::Basic},
-
-    /* dataModel */
-
-    /* barcode */
-    {0x43e349b, L"dataRowCount",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Barcode::dataRowCount,
-     XFA_Attribute::DataRowCount, XFA_ScriptType::Basic},
-    {0xc0811ed, L"use", (XFA_ATTRIBUTE_CALLBACK)&CJX_Barcode::use,
-     XFA_Attribute::Use, XFA_ScriptType::Basic},
-    {0x28e17e91, L"dataPrep", (XFA_ATTRIBUTE_CALLBACK)&CJX_Barcode::dataPrep,
-     XFA_Attribute::DataPrep, XFA_ScriptType::Basic},
-    {0x2f16a382, L"type", (XFA_ATTRIBUTE_CALLBACK)&CJX_Barcode::type,
-     XFA_Attribute::Type, XFA_ScriptType::Basic},
-    {0x3650557e, L"textLocation",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Barcode::textLocation,
-     XFA_Attribute::TextLocation, XFA_ScriptType::Basic},
-    {0x3b582286, L"moduleWidth",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Barcode::moduleWidth,
-     XFA_Attribute::ModuleWidth, XFA_ScriptType::Basic},
-    {0x52666f1c, L"printCheckDigit",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Barcode::printCheckDigit,
-     XFA_Attribute::PrintCheckDigit, XFA_ScriptType::Basic},
-    {0x5404d6df, L"moduleHeight",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Barcode::moduleHeight,
-     XFA_Attribute::ModuleHeight, XFA_ScriptType::Basic},
-    {0x5ab23b6c, L"startChar", (XFA_ATTRIBUTE_CALLBACK)&CJX_Barcode::startChar,
-     XFA_Attribute::StartChar, XFA_ScriptType::Basic},
-    {0x7c732a66, L"truncate", (XFA_ATTRIBUTE_CALLBACK)&CJX_Barcode::truncate,
-     XFA_Attribute::Truncate, XFA_ScriptType::Basic},
-    {0x8d181d61, L"wideNarrowRatio",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Barcode::wideNarrowRatio,
-     XFA_Attribute::WideNarrowRatio, XFA_ScriptType::Basic},
-    {0x99800d7a, L"errorCorrectionLevel",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Barcode::errorCorrectionLevel,
-     XFA_Attribute::ErrorCorrectionLevel, XFA_ScriptType::Basic},
-    {0x9a63da3d, L"upsMode", (XFA_ATTRIBUTE_CALLBACK)&CJX_Barcode::upsMode,
-     XFA_Attribute::UpsMode, XFA_ScriptType::Basic},
-    {0xaf754613, L"checksum", (XFA_ATTRIBUTE_CALLBACK)&CJX_Barcode::checksum,
-     XFA_Attribute::Checksum, XFA_ScriptType::Basic},
-    {0xb045fbc5, L"charEncoding",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Barcode::charEncoding,
-     XFA_Attribute::CharEncoding, XFA_ScriptType::Basic},
-    {0xbc254332, L"usehref", (XFA_ATTRIBUTE_CALLBACK)&CJX_Barcode::usehref,
-     XFA_Attribute::Usehref, XFA_ScriptType::Basic},
-    {0xc035c6b1, L"dataColumnCount",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Barcode::dataColumnCount,
-     XFA_Attribute::DataColumnCount, XFA_ScriptType::Basic},
-    {0xd3c84d25, L"rowColumnRatio",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Barcode::rowColumnRatio,
-     XFA_Attribute::RowColumnRatio, XFA_ScriptType::Basic},
-    {0xd57c513c, L"dataLength",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Barcode::dataLength,
-     XFA_Attribute::DataLength, XFA_ScriptType::Basic},
-    {0xf575ca75, L"endChar", (XFA_ATTRIBUTE_CALLBACK)&CJX_Barcode::endChar,
-     XFA_Attribute::EndChar, XFA_ScriptType::Basic},
-
-    /* timePattern */
-    {0x31b19c1, L"name",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Name, XFA_ScriptType::Basic},
-
-    /* batchOutput */
-    {0x28dee6e9, L"format",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Format, XFA_ScriptType::Basic},
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-
-    /* enforce */
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-
-    /* currencySymbols */
-
-    /* addSilentPrint */
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-
-    /* rename */
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-
-    /* operation */
-    {0xc0811ed, L"use", (XFA_ATTRIBUTE_CALLBACK)&CJX_Operation::use,
-     XFA_Attribute::Use, XFA_ScriptType::Basic},
-    {0x60d4c8b1, L"output", (XFA_ATTRIBUTE_CALLBACK)&CJX_Operation::output,
-     XFA_Attribute::Output, XFA_ScriptType::Basic},
-    {0xbc254332, L"usehref", (XFA_ATTRIBUTE_CALLBACK)&CJX_Operation::usehref,
-     XFA_Attribute::Usehref, XFA_ScriptType::Basic},
-    {0xd6a39990, L"input", (XFA_ATTRIBUTE_CALLBACK)&CJX_Operation::input,
-     XFA_Attribute::Input, XFA_ScriptType::Basic},
-
-    /* typefaces */
-
-    /* subjectDNs */
-    {0x2f16a382, L"type", (XFA_ATTRIBUTE_CALLBACK)&CJX_SubjectDNs::type,
-     XFA_Attribute::Type, XFA_ScriptType::Basic},
-
-    /* issuers */
-    {0xc0811ed, L"use", (XFA_ATTRIBUTE_CALLBACK)&CJX_Issuers::use,
-     XFA_Attribute::Use, XFA_ScriptType::Basic},
-    {0x2f16a382, L"type", (XFA_ATTRIBUTE_CALLBACK)&CJX_Issuers::type,
-     XFA_Attribute::Type, XFA_ScriptType::Basic},
-    {0xbc254332, L"usehref", (XFA_ATTRIBUTE_CALLBACK)&CJX_Issuers::usehref,
-     XFA_Attribute::Usehref, XFA_ScriptType::Basic},
-
-    /* signaturePseudoModel */
-
-    /* wsdlConnection */
-    {0x2b5df51e, L"dataDescription",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_WsdlConnection::dataDescription,
-     XFA_Attribute::DataDescription, XFA_ScriptType::Basic},
-
-    /* debug */
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-
-    /* delta */
-    {0x6c0d9600, L"currentValue",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Delta::currentValue, XFA_Attribute::Unknown,
-     XFA_ScriptType::Basic},
-    {0x942643f0, L"savedValue", (XFA_ATTRIBUTE_CALLBACK)&CJX_Delta::savedValue,
-     XFA_Attribute::Unknown, XFA_ScriptType::Basic},
-    {0xc8da4da7, L"target", (XFA_ATTRIBUTE_CALLBACK)&CJX_Delta::target,
-     XFA_Attribute::Unknown, XFA_ScriptType::Basic},
-
-    /* eraNames */
-
-    /* modifyAnnots */
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-
-    /* startNode */
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-
-    /* button */
-    {0xc0811ed, L"use", (XFA_ATTRIBUTE_CALLBACK)&CJX_Button::use,
-     XFA_Attribute::Use, XFA_ScriptType::Basic},
-    {0xbc254332, L"usehref", (XFA_ATTRIBUTE_CALLBACK)&CJX_Button::usehref,
-     XFA_Attribute::Usehref, XFA_ScriptType::Basic},
-    {0xd4cc53f8, L"highlight", (XFA_ATTRIBUTE_CALLBACK)&CJX_Button::highlight,
-     XFA_Attribute::Highlight, XFA_ScriptType::Basic},
-
-    /* format */
-    {0xc0811ed, L"use", (XFA_ATTRIBUTE_CALLBACK)&CJX_Format::use,
-     XFA_Attribute::Use, XFA_ScriptType::Basic},
-    {0xbc254332, L"usehref", (XFA_ATTRIBUTE_CALLBACK)&CJX_Format::usehref,
-     XFA_Attribute::Usehref, XFA_ScriptType::Basic},
-
-    /* border */
-    {0x5518c25, L"break", (XFA_ATTRIBUTE_CALLBACK)&CJX_Border::breakValue,
-     XFA_Attribute::Break, XFA_ScriptType::Basic},
-    {0xc0811ed, L"use", (XFA_ATTRIBUTE_CALLBACK)&CJX_Border::use,
-     XFA_Attribute::Use, XFA_ScriptType::Basic},
-    {0x570ce835, L"presence", (XFA_ATTRIBUTE_CALLBACK)&CJX_Border::presence,
-     XFA_Attribute::Presence, XFA_ScriptType::Basic},
-    {0x8e1c2921, L"relevant", (XFA_ATTRIBUTE_CALLBACK)&CJX_Border::relevant,
-     XFA_Attribute::Relevant, XFA_ScriptType::Basic},
-    {0xbc254332, L"usehref", (XFA_ATTRIBUTE_CALLBACK)&CJX_Border::usehref,
-     XFA_Attribute::Usehref, XFA_ScriptType::Basic},
-    {0xd996fa9b, L"hand", (XFA_ATTRIBUTE_CALLBACK)&CJX_Border::hand,
-     XFA_Attribute::Hand, XFA_ScriptType::Basic},
-
-    /* area */
-    {0x78, L"x", (XFA_ATTRIBUTE_CALLBACK)&CJX_Area::x, XFA_Attribute::X,
-     XFA_ScriptType::Basic},
-    {0x79, L"y", (XFA_ATTRIBUTE_CALLBACK)&CJX_Area::y, XFA_Attribute::Y,
-     XFA_ScriptType::Basic},
-    {0x21aed, L"id", (XFA_ATTRIBUTE_CALLBACK)&CJX_Area::id, XFA_Attribute::Id,
-     XFA_ScriptType::Basic},
-    {0x31b19c1, L"name", (XFA_ATTRIBUTE_CALLBACK)&CJX_Area::name,
-     XFA_Attribute::Name, XFA_ScriptType::Basic},
-    {0xc0811ed, L"use", (XFA_ATTRIBUTE_CALLBACK)&CJX_Area::use,
-     XFA_Attribute::Use, XFA_ScriptType::Basic},
-    {0x1059ec18, L"level",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_Integer,
-     XFA_Attribute::Level, XFA_ScriptType::Basic},
-    {0x8e1c2921, L"relevant", (XFA_ATTRIBUTE_CALLBACK)&CJX_Area::relevant,
-     XFA_Attribute::Relevant, XFA_ScriptType::Basic},
-    {0xac06e2b0, L"colSpan", (XFA_ATTRIBUTE_CALLBACK)&CJX_Area::colSpan,
-     XFA_Attribute::ColSpan, XFA_ScriptType::Basic},
-    {0xbc254332, L"usehref", (XFA_ATTRIBUTE_CALLBACK)&CJX_Area::usehref,
-     XFA_Attribute::Usehref, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-
-    /* hyphenation */
-    {0x21aed, L"id",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Id, XFA_ScriptType::Basic},
-    {0xc0811ed, L"use",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Use, XFA_ScriptType::Basic},
-    {0x2f105f72, L"wordCharacterCount",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::WordCharacterCount, XFA_ScriptType::Basic},
-    {0x3d123c26, L"hyphenate",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Hyphenate, XFA_ScriptType::Basic},
-    {0x66539c48, L"excludeInitialCap",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::ExcludeInitialCap, XFA_ScriptType::Basic},
-    {0x6a95c976, L"pushCharacterCount",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::PushCharacterCount, XFA_ScriptType::Basic},
-    {0x982bd892, L"remainCharacterCount",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::RemainCharacterCount, XFA_ScriptType::Basic},
-    {0xbc254332, L"usehref",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Usehref, XFA_ScriptType::Basic},
-    {0xe5c96d6a, L"excludeAllCaps",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::ExcludeAllCaps, XFA_ScriptType::Basic},
-
-    /* text */
-    {0xc0811ed, L"use", (XFA_ATTRIBUTE_CALLBACK)&CJX_Text::use,
-     XFA_Attribute::Use, XFA_ScriptType::Basic},
-    {0x8af2e657, L"maxChars", (XFA_ATTRIBUTE_CALLBACK)&CJX_Text::maxChars,
-     XFA_Attribute::MaxChars, XFA_ScriptType::Basic},
-    {0xa52682bd, L"{default}", (XFA_ATTRIBUTE_CALLBACK)&CJX_Text::defaultValue,
-     XFA_Attribute::Unknown, XFA_ScriptType::Basic},
-    {0xbc254332, L"usehref", (XFA_ATTRIBUTE_CALLBACK)&CJX_Text::usehref,
-     XFA_Attribute::Usehref, XFA_ScriptType::Basic},
-    {0xd6e27f1d, L"value", (XFA_ATTRIBUTE_CALLBACK)&CJX_Text::value,
-     XFA_Attribute::Unknown, XFA_ScriptType::Basic},
-
-    /* time */
-    {0xc0811ed, L"use", (XFA_ATTRIBUTE_CALLBACK)&CJX_Time::use,
-     XFA_Attribute::Use, XFA_ScriptType::Basic},
-    {0xa52682bd, L"{default}", (XFA_ATTRIBUTE_CALLBACK)&CJX_Time::defaultValue,
-     XFA_Attribute::Unknown, XFA_ScriptType::Basic},
-    {0xbc254332, L"usehref", (XFA_ATTRIBUTE_CALLBACK)&CJX_Time::usehref,
-     XFA_Attribute::Usehref, XFA_ScriptType::Basic},
-    {0xd6e27f1d, L"value", (XFA_ATTRIBUTE_CALLBACK)&CJX_Time::value,
-     XFA_Attribute::Unknown, XFA_ScriptType::Basic},
-
-    /* type */
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-
-    /* overprint */
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-
-    /* certificates */
-    {0xc080cd3, L"url", (XFA_ATTRIBUTE_CALLBACK)&CJX_Certificates::url,
-     XFA_Attribute::Url, XFA_ScriptType::Basic},
-    {0xc0811ed, L"use", (XFA_ATTRIBUTE_CALLBACK)&CJX_Certificates::use,
-     XFA_Attribute::Use, XFA_ScriptType::Basic},
-    {0xa6710262, L"credentialServerPolicy",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Certificates::credentialServerPolicy,
-     XFA_Attribute::CredentialServerPolicy, XFA_ScriptType::Basic},
-    {0xbc254332, L"usehref", (XFA_ATTRIBUTE_CALLBACK)&CJX_Certificates::usehref,
-     XFA_Attribute::Usehref, XFA_ScriptType::Basic},
-    {0xc2ba0923, L"urlPolicy",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Certificates::urlPolicy,
-     XFA_Attribute::UrlPolicy, XFA_ScriptType::Basic},
-
-    /* encryptionMethods */
-    {0xc0811ed, L"use",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Use, XFA_ScriptType::Basic},
-    {0x2f16a382, L"type",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Type, XFA_ScriptType::Basic},
-    {0xbc254332, L"usehref",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Usehref, XFA_ScriptType::Basic},
-
-    /* setProperty */
-    {0x47d03490, L"connection",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_SetProperty::connection,
-     XFA_Attribute::Connection, XFA_ScriptType::Basic},
-    {0xc8da4da7, L"target", (XFA_ATTRIBUTE_CALLBACK)&CJX_SetProperty::target,
-     XFA_Attribute::Target, XFA_ScriptType::Basic},
-
-    /* printerName */
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-
-    /* startPage */
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-
-    /* pageOffset */
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-
-    /* dateTime */
-    {0xc0811ed, L"use", (XFA_ATTRIBUTE_CALLBACK)&CJX_DateTime::use,
-     XFA_Attribute::Use, XFA_ScriptType::Basic},
-    {0xa52682bd, L"{default}",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_DateTime::defaultValue,
-     XFA_Attribute::Unknown, XFA_ScriptType::Basic},
-    {0xbc254332, L"usehref", (XFA_ATTRIBUTE_CALLBACK)&CJX_DateTime::usehref,
-     XFA_Attribute::Usehref, XFA_ScriptType::Basic},
-    {0xd6e27f1d, L"value", (XFA_ATTRIBUTE_CALLBACK)&CJX_DateTime::value,
-     XFA_Attribute::Unknown, XFA_ScriptType::Basic},
-
-    /* comb */
-    {0xc0811ed, L"use", (XFA_ATTRIBUTE_CALLBACK)&CJX_Comb::use,
-     XFA_Attribute::Use, XFA_ScriptType::Basic},
-    {0x78bff531, L"numberOfCells",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Comb::numberOfCells,
-     XFA_Attribute::NumberOfCells, XFA_ScriptType::Basic},
-    {0xbc254332, L"usehref", (XFA_ATTRIBUTE_CALLBACK)&CJX_Comb::usehref,
-     XFA_Attribute::Usehref, XFA_ScriptType::Basic},
-
-    /* pattern */
-    {0xc0811ed, L"use", (XFA_ATTRIBUTE_CALLBACK)&CJX_Pattern::use,
-     XFA_Attribute::Use, XFA_ScriptType::Basic},
-    {0x2f16a382, L"type", (XFA_ATTRIBUTE_CALLBACK)&CJX_Pattern::type,
-     XFA_Attribute::Type, XFA_ScriptType::Basic},
-    {0xbc254332, L"usehref", (XFA_ATTRIBUTE_CALLBACK)&CJX_Pattern::usehref,
-     XFA_Attribute::Usehref, XFA_ScriptType::Basic},
-
-    /* ifEmpty */
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-
-    /* suppressBanner */
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-
-    /* outputBin */
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-
-    /* field */
-    {0x68, L"h", (XFA_ATTRIBUTE_CALLBACK)&CJX_Field::h, XFA_Attribute::H,
-     XFA_ScriptType::Basic},
-    {0x77, L"w", (XFA_ATTRIBUTE_CALLBACK)&CJX_Field::w, XFA_Attribute::W,
-     XFA_ScriptType::Basic},
-    {0x78, L"x", (XFA_ATTRIBUTE_CALLBACK)&CJX_Field::x, XFA_Attribute::X,
-     XFA_ScriptType::Basic},
-    {0x79, L"y", (XFA_ATTRIBUTE_CALLBACK)&CJX_Field::y, XFA_Attribute::Y,
-     XFA_ScriptType::Basic},
-    {0x2282c73, L"hAlign", (XFA_ATTRIBUTE_CALLBACK)&CJX_Field::hAlign,
-     XFA_Attribute::HAlign, XFA_ScriptType::Basic},
-    {0xc0811ed, L"use", (XFA_ATTRIBUTE_CALLBACK)&CJX_Field::use,
-     XFA_Attribute::Use, XFA_ScriptType::Basic},
-    {0x1abbd7e0, L"dataNode",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Som_DataNode,
-     XFA_Attribute::Unknown, XFA_ScriptType::Object},
-    {0x25839852, L"access", (XFA_ATTRIBUTE_CALLBACK)&CJX_Field::access,
-     XFA_Attribute::Access, XFA_ScriptType::Basic},
-    {0x2ee7678f, L"rotate", (XFA_ATTRIBUTE_CALLBACK)&CJX_Field::rotate,
-     XFA_Attribute::Rotate, XFA_ScriptType::Basic},
-    {0x3b1ddd06, L"fillColor", (XFA_ATTRIBUTE_CALLBACK)&CJX_Field::fillColor,
-     XFA_Attribute::Unknown, XFA_ScriptType::Basic},
-    {0x54c399e3, L"formattedValue",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Field::formattedValue, XFA_Attribute::Unknown,
-     XFA_ScriptType::Basic},
-    {0x570ce835, L"presence", (XFA_ATTRIBUTE_CALLBACK)&CJX_Field::presence,
-     XFA_Attribute::Presence, XFA_ScriptType::Basic},
-    {0x5a3b375d, L"borderColor",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Field::borderColor, XFA_Attribute::Unknown,
-     XFA_ScriptType::Basic},
-    {0x5e936ed6, L"fontColor", (XFA_ATTRIBUTE_CALLBACK)&CJX_Field::fontColor,
-     XFA_Attribute::Unknown, XFA_ScriptType::Basic},
-    {0x6826c408, L"parentSubform",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Field::parentSubform, XFA_Attribute::Unknown,
-     XFA_ScriptType::Basic},
-    {0x79b67434, L"mandatoryMessage",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Field::mandatoryMessage,
-     XFA_Attribute::Unknown, XFA_ScriptType::Basic},
-    {0x7a7cc341, L"vAlign", (XFA_ATTRIBUTE_CALLBACK)&CJX_Field::vAlign,
-     XFA_Attribute::VAlign, XFA_ScriptType::Basic},
-    {0x7c2ff6ae, L"maxH", (XFA_ATTRIBUTE_CALLBACK)&CJX_Field::maxH,
-     XFA_Attribute::MaxH, XFA_ScriptType::Basic},
-    {0x7c2ff6bd, L"maxW", (XFA_ATTRIBUTE_CALLBACK)&CJX_Field::maxW,
-     XFA_Attribute::MaxW, XFA_ScriptType::Basic},
-    {0x7d02356c, L"minH", (XFA_ATTRIBUTE_CALLBACK)&CJX_Field::minH,
-     XFA_Attribute::MinH, XFA_ScriptType::Basic},
-    {0x7d02357b, L"minW", (XFA_ATTRIBUTE_CALLBACK)&CJX_Field::minW,
-     XFA_Attribute::MinW, XFA_ScriptType::Basic},
-    {0x85fd6faf, L"mandatory", (XFA_ATTRIBUTE_CALLBACK)&CJX_Field::mandatory,
-     XFA_Attribute::Unknown, XFA_ScriptType::Basic},
-    {0x8e1c2921, L"relevant", (XFA_ATTRIBUTE_CALLBACK)&CJX_Field::relevant,
-     XFA_Attribute::Relevant, XFA_ScriptType::Basic},
-    {0x964fb42e, L"formatMessage",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Field::formatMessage, XFA_Attribute::Unknown,
-     XFA_ScriptType::Basic},
-    {0xa03cf627, L"rawValue", (XFA_ATTRIBUTE_CALLBACK)&CJX_Field::rawValue,
-     XFA_Attribute::Unknown, XFA_ScriptType::Basic},
-    {0xa52682bd, L"{default}", (XFA_ATTRIBUTE_CALLBACK)&CJX_Field::defaultValue,
-     XFA_Attribute::Unknown, XFA_ScriptType::Basic},
-    {0xa60dd202, L"length",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Field_Length,
-     XFA_Attribute::Unknown, XFA_ScriptType::Basic},
-    {0xac06e2b0, L"colSpan", (XFA_ATTRIBUTE_CALLBACK)&CJX_Field::colSpan,
-     XFA_Attribute::ColSpan, XFA_ScriptType::Basic},
-    {0xbc254332, L"usehref", (XFA_ATTRIBUTE_CALLBACK)&CJX_Field::usehref,
-     XFA_Attribute::Usehref, XFA_ScriptType::Basic},
-    {0xbc8fa350, L"locale", (XFA_ATTRIBUTE_CALLBACK)&CJX_Field::locale,
-     XFA_Attribute::Locale, XFA_ScriptType::Basic},
-    {0xc2bd40fd, L"anchorType", (XFA_ATTRIBUTE_CALLBACK)&CJX_Field::anchorType,
-     XFA_Attribute::AnchorType, XFA_ScriptType::Basic},
-    {0xc4fed09b, L"accessKey", (XFA_ATTRIBUTE_CALLBACK)&CJX_Field::accessKey,
-     XFA_Attribute::AccessKey, XFA_ScriptType::Basic},
-    {0xcabfa3d0, L"validationMessage",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Field::validationMessage,
-     XFA_Attribute::Unknown, XFA_ScriptType::Basic},
-    {0xdcecd663, L"editValue", (XFA_ATTRIBUTE_CALLBACK)&CJX_Field::editValue,
-     XFA_Attribute::Unknown, XFA_ScriptType::Basic},
-    {0xe07e5061, L"selectedIndex",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Field::selectedIndex, XFA_Attribute::Unknown,
-     XFA_ScriptType::Basic},
-    {0xf65e34be, L"borderWidth",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Field::borderWidth, XFA_Attribute::Unknown,
-     XFA_ScriptType::Basic},
-
-    /* agent */
-    {0x31b19c1, L"name",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Name, XFA_ScriptType::Basic},
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-
-    /* outputXSL */
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-
-    /* adjustData */
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-
-    /* autoSave */
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-
-    /* contentArea */
-    {0x68, L"h", (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::H, XFA_ScriptType::Basic},
-    {0x77, L"w", (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::W, XFA_ScriptType::Basic},
-    {0x78, L"x", (XFA_ATTRIBUTE_CALLBACK)&CJX_ContentArea::x, XFA_Attribute::X,
-     XFA_ScriptType::Basic},
-    {0x79, L"y", (XFA_ATTRIBUTE_CALLBACK)&CJX_ContentArea::y, XFA_Attribute::Y,
-     XFA_ScriptType::Basic},
-    {0xc0811ed, L"use", (XFA_ATTRIBUTE_CALLBACK)&CJX_ContentArea::use,
-     XFA_Attribute::Use, XFA_ScriptType::Basic},
-    {0x8e1c2921, L"relevant",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_ContentArea::relevant,
-     XFA_Attribute::Relevant, XFA_ScriptType::Basic},
-    {0xbc254332, L"usehref", (XFA_ATTRIBUTE_CALLBACK)&CJX_ContentArea::usehref,
-     XFA_Attribute::Usehref, XFA_ScriptType::Basic},
-
-    /* eventPseudoModel */
-    {0xd843798, L"fullText",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_EventPseudoModel::fullText,
-     XFA_Attribute::Unknown, XFA_ScriptType::Basic},
-    {0x1b6d1cf5, L"reenter",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_EventPseudoModel::reenter,
-     XFA_Attribute::Unknown, XFA_ScriptType::Basic},
-    {0x1e6ffa9a, L"prevContentType",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_EventPseudoModel::prevContentType,
-     XFA_Attribute::Unknown, XFA_ScriptType::Basic},
-    {0x25a3c206, L"soapFaultString",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_EventPseudoModel::soapFaultString,
-     XFA_Attribute::Unknown, XFA_ScriptType::Basic},
-    {0x2e00c007, L"newContentType",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_EventPseudoModel::newContentType,
-     XFA_Attribute::Unknown, XFA_ScriptType::Basic},
-    {0x4570500f, L"modifier",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_EventPseudoModel::modifier,
-     XFA_Attribute::Unknown, XFA_ScriptType::Basic},
-    {0x50e2e33b, L"selEnd",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_EventPseudoModel::selEnd,
-     XFA_Attribute::Unknown, XFA_ScriptType::Basic},
-    {0x57de87c2, L"prevText",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_EventPseudoModel::prevText,
-     XFA_Attribute::Unknown, XFA_ScriptType::Basic},
-    {0x6ea04e0a, L"soapFaultCode",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_EventPseudoModel::soapFaultCode,
-     XFA_Attribute::Unknown, XFA_ScriptType::Basic},
-    {0x6f6556cf, L"newText",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_EventPseudoModel::newText,
-     XFA_Attribute::Unknown, XFA_ScriptType::Basic},
-    {0x891f4606, L"change",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_EventPseudoModel::change,
-     XFA_Attribute::Unknown, XFA_ScriptType::Basic},
-    {0x8fa3c19e, L"shift", (XFA_ATTRIBUTE_CALLBACK)&CJX_EventPseudoModel::shift,
-     XFA_Attribute::Unknown, XFA_ScriptType::Basic},
-    {0xa9d9b2e1, L"keyDown",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_EventPseudoModel::keyDown,
-     XFA_Attribute::Unknown, XFA_ScriptType::Basic},
-    {0xbfc89db2, L"selStart",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_EventPseudoModel::selStart,
-     XFA_Attribute::Unknown, XFA_ScriptType::Basic},
-    {0xc32a5812, L"commitKey",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_EventPseudoModel::commitKey,
-     XFA_Attribute::Unknown, XFA_ScriptType::Basic},
-    {0xc8da4da7, L"target",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_EventPseudoModel::target,
-     XFA_Attribute::Unknown, XFA_ScriptType::Basic},
-
-    /* wsdlAddress */
-    {0xc0811ed, L"use", (XFA_ATTRIBUTE_CALLBACK)&CJX_WsdlAddress::use,
-     XFA_Attribute::Use, XFA_ScriptType::Basic},
-    {0xbc254332, L"usehref", (XFA_ATTRIBUTE_CALLBACK)&CJX_WsdlAddress::usehref,
-     XFA_Attribute::Usehref, XFA_ScriptType::Basic},
-
-    /* solid */
-    {0xc0811ed, L"use", (XFA_ATTRIBUTE_CALLBACK)&CJX_Solid::use,
-     XFA_Attribute::Use, XFA_ScriptType::Basic},
-    {0xbc254332, L"usehref", (XFA_ATTRIBUTE_CALLBACK)&CJX_Solid::usehref,
-     XFA_Attribute::Usehref, XFA_ScriptType::Basic},
-
-    /* dateTimeSymbols */
-
-    /* encryptionLevel */
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-
-    /* edge */
-    {0xa2e3514, L"cap", (XFA_ATTRIBUTE_CALLBACK)&CJX_Edge::cap,
-     XFA_Attribute::Cap, XFA_ScriptType::Basic},
-    {0xc0811ed, L"use", (XFA_ATTRIBUTE_CALLBACK)&CJX_Edge::use,
-     XFA_Attribute::Use, XFA_ScriptType::Basic},
-    {0x5392ea58, L"stroke", (XFA_ATTRIBUTE_CALLBACK)&CJX_Edge::stroke,
-     XFA_Attribute::Stroke, XFA_ScriptType::Basic},
-    {0x570ce835, L"presence", (XFA_ATTRIBUTE_CALLBACK)&CJX_Edge::presence,
-     XFA_Attribute::Presence, XFA_ScriptType::Basic},
-    {0x94446dcc, L"thickness", (XFA_ATTRIBUTE_CALLBACK)&CJX_Edge::thickness,
-     XFA_Attribute::Thickness, XFA_ScriptType::Basic},
-    {0xbc254332, L"usehref", (XFA_ATTRIBUTE_CALLBACK)&CJX_Edge::usehref,
-     XFA_Attribute::Usehref, XFA_ScriptType::Basic},
-
-    /* stipple */
-    {0xc0811ed, L"use", (XFA_ATTRIBUTE_CALLBACK)&CJX_Stipple::use,
-     XFA_Attribute::Use, XFA_ScriptType::Basic},
-    {0x1ec8ab2c, L"rate", (XFA_ATTRIBUTE_CALLBACK)&CJX_Stipple::rate,
-     XFA_Attribute::Rate, XFA_ScriptType::Basic},
-    {0xbc254332, L"usehref", (XFA_ATTRIBUTE_CALLBACK)&CJX_Stipple::usehref,
-     XFA_Attribute::Usehref, XFA_ScriptType::Basic},
-
-    /* attributes */
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-
-    /* versionControl */
-    {0x7b29630a, L"sourceBelow",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::SourceBelow, XFA_ScriptType::Basic},
-    {0x8fc36c0a, L"outputBelow",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::OutputBelow, XFA_ScriptType::Basic},
-    {0xe996b2fe, L"sourceAbove",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::SourceAbove, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-
-    /* meridiem */
-
-    /* exclGroup */
-    {0x68, L"h", (XFA_ATTRIBUTE_CALLBACK)&CJX_ExclGroup::h, XFA_Attribute::H,
-     XFA_ScriptType::Basic},
-    {0x77, L"w", (XFA_ATTRIBUTE_CALLBACK)&CJX_ExclGroup::w, XFA_Attribute::W,
-     XFA_ScriptType::Basic},
-    {0x78, L"x", (XFA_ATTRIBUTE_CALLBACK)&CJX_ExclGroup::x, XFA_Attribute::X,
-     XFA_ScriptType::Basic},
-    {0x79, L"y", (XFA_ATTRIBUTE_CALLBACK)&CJX_ExclGroup::y, XFA_Attribute::Y,
-     XFA_ScriptType::Basic},
-    {0x2282c73, L"hAlign", (XFA_ATTRIBUTE_CALLBACK)&CJX_ExclGroup::hAlign,
-     XFA_Attribute::HAlign, XFA_ScriptType::Basic},
-    {0xc0811ed, L"use", (XFA_ATTRIBUTE_CALLBACK)&CJX_ExclGroup::use,
-     XFA_Attribute::Use, XFA_ScriptType::Basic},
-    {0xf23332f, L"errorText",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_ExclGroup_ErrorText,
-     XFA_Attribute::Unknown, XFA_ScriptType::Basic},
-    {0x1abbd7e0, L"dataNode",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Som_DataNode,
-     XFA_Attribute::Unknown, XFA_ScriptType::Object},
-    {0x25839852, L"access", (XFA_ATTRIBUTE_CALLBACK)&CJX_ExclGroup::access,
-     XFA_Attribute::Access, XFA_ScriptType::Basic},
-    {0x3b1ddd06, L"fillColor",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_ExclGroup::fillColor, XFA_Attribute::Unknown,
-     XFA_ScriptType::Basic},
-    {0x570ce835, L"presence", (XFA_ATTRIBUTE_CALLBACK)&CJX_ExclGroup::presence,
-     XFA_Attribute::Presence, XFA_ScriptType::Basic},
-    {0x5a3b375d, L"borderColor",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_ExclGroup::borderColor,
-     XFA_Attribute::Unknown, XFA_ScriptType::Basic},
-    {0x79b67434, L"mandatoryMessage",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_ExclGroup::mandatoryMessage,
-     XFA_Attribute::Unknown, XFA_ScriptType::Basic},
-    {0x7a7cc341, L"vAlign", (XFA_ATTRIBUTE_CALLBACK)&CJX_ExclGroup::vAlign,
-     XFA_Attribute::VAlign, XFA_ScriptType::Basic},
-    {0x7c2ff6ae, L"maxH", (XFA_ATTRIBUTE_CALLBACK)&CJX_ExclGroup::maxH,
-     XFA_Attribute::MaxH, XFA_ScriptType::Basic},
-    {0x7c2ff6bd, L"maxW", (XFA_ATTRIBUTE_CALLBACK)&CJX_ExclGroup::maxW,
-     XFA_Attribute::MaxW, XFA_ScriptType::Basic},
-    {0x7d02356c, L"minH", (XFA_ATTRIBUTE_CALLBACK)&CJX_ExclGroup::minH,
-     XFA_Attribute::MinH, XFA_ScriptType::Basic},
-    {0x7d02357b, L"minW", (XFA_ATTRIBUTE_CALLBACK)&CJX_ExclGroup::minW,
-     XFA_Attribute::MinW, XFA_ScriptType::Basic},
-    {0x7e7e845e, L"layout", (XFA_ATTRIBUTE_CALLBACK)&CJX_ExclGroup::layout,
-     XFA_Attribute::Layout, XFA_ScriptType::Basic},
-    {0x846599f8, L"transient",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_ExclGroup::transient, XFA_Attribute::Unknown,
-     XFA_ScriptType::Basic},
-    {0x85fd6faf, L"mandatory",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_ExclGroup::mandatory, XFA_Attribute::Unknown,
-     XFA_ScriptType::Basic},
-    {0x8e1c2921, L"relevant", (XFA_ATTRIBUTE_CALLBACK)&CJX_ExclGroup::relevant,
-     XFA_Attribute::Relevant, XFA_ScriptType::Basic},
-    {0xa03cf627, L"rawValue", (XFA_ATTRIBUTE_CALLBACK)&CJX_ExclGroup::rawValue,
-     XFA_Attribute::Unknown, XFA_ScriptType::Basic},
-    {0xa52682bd, L"{default}",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_ExclGroup::defaultValue,
-     XFA_Attribute::Unknown, XFA_ScriptType::Basic},
-    {0xac06e2b0, L"colSpan", (XFA_ATTRIBUTE_CALLBACK)&CJX_ExclGroup::colSpan,
-     XFA_Attribute::ColSpan, XFA_ScriptType::Basic},
-    {0xbc254332, L"usehref", (XFA_ATTRIBUTE_CALLBACK)&CJX_ExclGroup::usehref,
-     XFA_Attribute::Usehref, XFA_ScriptType::Basic},
-    {0xc2bd40fd, L"anchorType",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_ExclGroup::anchorType,
-     XFA_Attribute::AnchorType, XFA_ScriptType::Basic},
-    {0xc4fed09b, L"accessKey",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_ExclGroup::accessKey,
-     XFA_Attribute::AccessKey, XFA_ScriptType::Basic},
-    {0xcabfa3d0, L"validationMessage",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_ExclGroup::validationMessage,
-     XFA_Attribute::Unknown, XFA_ScriptType::Basic},
-    {0xf65e34be, L"borderWidth",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_ExclGroup::borderWidth,
-     XFA_Attribute::Unknown, XFA_ScriptType::Basic},
-
-    /* toolTip */
-    {0xc0811ed, L"use", (XFA_ATTRIBUTE_CALLBACK)&CJX_ToolTip::use,
-     XFA_Attribute::Use, XFA_ScriptType::Basic},
-    {0xbc254332, L"usehref", (XFA_ATTRIBUTE_CALLBACK)&CJX_ToolTip::usehref,
-     XFA_Attribute::Usehref, XFA_ScriptType::Basic},
-
-    /* compress */
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xeda9017a, L"scope",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Scope, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-
-    /* reason */
-    {0xc0811ed, L"use", (XFA_ATTRIBUTE_CALLBACK)&CJX_Reason::use,
-     XFA_Attribute::Use, XFA_ScriptType::Basic},
-    {0xbc254332, L"usehref", (XFA_ATTRIBUTE_CALLBACK)&CJX_Reason::usehref,
-     XFA_Attribute::Usehref, XFA_ScriptType::Basic},
-
-    /* execute */
-    {0xc0811ed, L"use", (XFA_ATTRIBUTE_CALLBACK)&CJX_Execute::use,
-     XFA_Attribute::Use, XFA_ScriptType::Basic},
-    {0x47d03490, L"connection",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Execute::connection,
-     XFA_Attribute::Connection, XFA_ScriptType::Basic},
-    {0x6cfa828a, L"runAt", (XFA_ATTRIBUTE_CALLBACK)&CJX_Execute::runAt,
-     XFA_Attribute::RunAt, XFA_ScriptType::Basic},
-    {0xa1b0d2f5, L"executeType",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Execute::executeType,
-     XFA_Attribute::ExecuteType, XFA_ScriptType::Basic},
-    {0xbc254332, L"usehref", (XFA_ATTRIBUTE_CALLBACK)&CJX_Execute::usehref,
-     XFA_Attribute::Usehref, XFA_ScriptType::Basic},
-
-    /* contentCopy */
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-
-    /* dateTimeEdit */
-    {0xc0811ed, L"use", (XFA_ATTRIBUTE_CALLBACK)&CJX_DateTimeEdit::use,
-     XFA_Attribute::Use, XFA_ScriptType::Basic},
-    {0xbc254332, L"usehref", (XFA_ATTRIBUTE_CALLBACK)&CJX_DateTimeEdit::usehref,
-     XFA_Attribute::Usehref, XFA_ScriptType::Basic},
-    {0xe6f99487, L"hScrollPolicy",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_DateTimeEdit::hScrollPolicy,
-     XFA_Attribute::HScrollPolicy, XFA_ScriptType::Basic},
-
-    /* config */
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-
-    /* image */
-    {0xc0811ed, L"use", (XFA_ATTRIBUTE_CALLBACK)&CJX_Image::use,
-     XFA_Attribute::Use, XFA_ScriptType::Basic},
-    {0x42fed1fd, L"contentType",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Image::contentType,
-     XFA_Attribute::ContentType, XFA_ScriptType::Basic},
-    {0x54fa722c, L"transferEncoding",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Image::transferEncoding,
-     XFA_Attribute::TransferEncoding, XFA_ScriptType::Basic},
-    {0xa52682bd, L"{default}", (XFA_ATTRIBUTE_CALLBACK)&CJX_Image::defaultValue,
-     XFA_Attribute::Unknown, XFA_ScriptType::Basic},
-    {0xbc254332, L"usehref", (XFA_ATTRIBUTE_CALLBACK)&CJX_Image::usehref,
-     XFA_Attribute::Usehref, XFA_ScriptType::Basic},
-    {0xd171b240, L"aspect", (XFA_ATTRIBUTE_CALLBACK)&CJX_Image::aspect,
-     XFA_Attribute::Aspect, XFA_ScriptType::Basic},
-    {0xd6e27f1d, L"value", (XFA_ATTRIBUTE_CALLBACK)&CJX_Image::value,
-     XFA_Attribute::Unknown, XFA_ScriptType::Basic},
-    {0xdb55fec5, L"href", (XFA_ATTRIBUTE_CALLBACK)&CJX_Image::href,
-     XFA_Attribute::Href, XFA_ScriptType::Basic},
-
-    /* #xHTML */
-    {0xd6e27f1d, L"value",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Value, XFA_ScriptType::Basic},
-
-    /* numberOfCopies */
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-
-    /* behaviorOverride */
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-
-    /* timeStamp */
-    {0xc0811ed, L"use", (XFA_ATTRIBUTE_CALLBACK)&CJX_TimeStamp::use,
-     XFA_Attribute::Use, XFA_ScriptType::Basic},
-    {0x2f16a382, L"type", (XFA_ATTRIBUTE_CALLBACK)&CJX_TimeStamp::type,
-     XFA_Attribute::Type, XFA_ScriptType::Basic},
-    {0x7f6fd3d7, L"server", (XFA_ATTRIBUTE_CALLBACK)&CJX_TimeStamp::server,
-     XFA_Attribute::Server, XFA_ScriptType::Basic},
-    {0xbc254332, L"usehref", (XFA_ATTRIBUTE_CALLBACK)&CJX_TimeStamp::usehref,
-     XFA_Attribute::Usehref, XFA_ScriptType::Basic},
-
-    /* month */
-
-    /* viewerPreferences */
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-
-    /* scriptModel */
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-
-    /* decimal */
-    {0xc0811ed, L"use", (XFA_ATTRIBUTE_CALLBACK)&CJX_Decimal::use,
-     XFA_Attribute::Use, XFA_ScriptType::Basic},
-    {0x4b8bc840, L"fracDigits",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Decimal::fracDigits,
-     XFA_Attribute::FracDigits, XFA_ScriptType::Basic},
-    {0xa52682bd, L"{default}",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Decimal::defaultValue, XFA_Attribute::Unknown,
-     XFA_ScriptType::Basic},
-    {0xbc254332, L"usehref", (XFA_ATTRIBUTE_CALLBACK)&CJX_Decimal::usehref,
-     XFA_Attribute::Usehref, XFA_ScriptType::Basic},
-    {0xd6e27f1d, L"value", (XFA_ATTRIBUTE_CALLBACK)&CJX_Decimal::value,
-     XFA_Attribute::Unknown, XFA_ScriptType::Basic},
-    {0xde7f92ba, L"leadDigits",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Decimal::leadDigits,
-     XFA_Attribute::LeadDigits, XFA_ScriptType::Basic},
-
-    /* subform */
-    {0x68, L"h", (XFA_ATTRIBUTE_CALLBACK)&CJX_Subform::h, XFA_Attribute::H,
-     XFA_ScriptType::Basic},
-    {0x77, L"w", (XFA_ATTRIBUTE_CALLBACK)&CJX_Subform::w, XFA_Attribute::W,
-     XFA_ScriptType::Basic},
-    {0x78, L"x", (XFA_ATTRIBUTE_CALLBACK)&CJX_Subform::x, XFA_Attribute::X,
-     XFA_ScriptType::Basic},
-    {0x79, L"y", (XFA_ATTRIBUTE_CALLBACK)&CJX_Subform::y, XFA_Attribute::Y,
-     XFA_ScriptType::Basic},
-    {0x2282c73, L"hAlign", (XFA_ATTRIBUTE_CALLBACK)&CJX_Subform::hAlign,
-     XFA_Attribute::HAlign, XFA_ScriptType::Basic},
-    {0xc0811ed, L"use", (XFA_ATTRIBUTE_CALLBACK)&CJX_Subform::use,
-     XFA_Attribute::Use, XFA_ScriptType::Basic},
-    {0x1414d431, L"allowMacro",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Subform::allowMacro,
-     XFA_Attribute::AllowMacro, XFA_ScriptType::Basic},
-    {0x1517dfa1, L"columnWidths",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Subform::columnWidths,
-     XFA_Attribute::ColumnWidths, XFA_ScriptType::Basic},
-    {0x1abbd7e0, L"dataNode",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Som_DataNode,
-     XFA_Attribute::Unknown, XFA_ScriptType::Object},
-    {0x1ee2d24d, L"instanceIndex",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Subform::instanceIndex,
-     XFA_Attribute::Unknown, XFA_ScriptType::Basic},
-    {0x25839852, L"access",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-
-     XFA_Attribute::Access, XFA_ScriptType::Basic},
-    {0x3b1ddd06, L"fillColor",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Som_FillColor,
-     XFA_Attribute::Unknown, XFA_ScriptType::Basic},
-    {0x570ce835, L"presence", (XFA_ATTRIBUTE_CALLBACK)&CJX_Subform::presence,
-     XFA_Attribute::Presence, XFA_ScriptType::Basic},
-    {0x5a3b375d, L"borderColor",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Som_BorderColor,
-     XFA_Attribute::Unknown, XFA_ScriptType::Basic},
-    {0x7a7cc341, L"vAlign", (XFA_ATTRIBUTE_CALLBACK)&CJX_Subform::vAlign,
-     XFA_Attribute::VAlign, XFA_ScriptType::Basic},
-    {0x7c2ff6ae, L"maxH", (XFA_ATTRIBUTE_CALLBACK)&CJX_Subform::maxH,
-     XFA_Attribute::MaxH, XFA_ScriptType::Basic},
-    {0x7c2ff6bd, L"maxW", (XFA_ATTRIBUTE_CALLBACK)&CJX_Subform::maxW,
-     XFA_Attribute::MaxW, XFA_ScriptType::Basic},
-    {0x7d02356c, L"minH", (XFA_ATTRIBUTE_CALLBACK)&CJX_Subform::minH,
-     XFA_Attribute::MinH, XFA_ScriptType::Basic},
-    {0x7d02357b, L"minW", (XFA_ATTRIBUTE_CALLBACK)&CJX_Subform::minW,
-     XFA_Attribute::MinW, XFA_ScriptType::Basic},
-    {0x7e7e845e, L"layout", (XFA_ATTRIBUTE_CALLBACK)&CJX_Subform::layout,
-     XFA_Attribute::Layout, XFA_ScriptType::Basic},
-    {0x8e1c2921, L"relevant", (XFA_ATTRIBUTE_CALLBACK)&CJX_Subform::relevant,
-     XFA_Attribute::Relevant, XFA_ScriptType::Basic},
-    {0x9cc17d75, L"mergeMode",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-
-     XFA_Attribute::MergeMode, XFA_ScriptType::Basic},
-    {0x9f3e9510, L"instanceManager",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Subform_InstanceManager,
-     XFA_Attribute::Unknown, XFA_ScriptType::Object},
-    {0xac06e2b0, L"colSpan", (XFA_ATTRIBUTE_CALLBACK)&CJX_Subform::colSpan,
-     XFA_Attribute::ColSpan, XFA_ScriptType::Basic},
-    {0xbc254332, L"usehref", (XFA_ATTRIBUTE_CALLBACK)&CJX_Subform::usehref,
-     XFA_Attribute::Usehref, XFA_ScriptType::Basic},
-    {0xbc8fa350, L"locale", (XFA_ATTRIBUTE_CALLBACK)&CJX_Subform::locale,
-     XFA_Attribute::Unknown, XFA_ScriptType::Basic},
-    {0xc2bd40fd, L"anchorType",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Subform::anchorType,
-     XFA_Attribute::AnchorType, XFA_ScriptType::Basic},
-    {0xcabfa3d0, L"validationMessage",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Subform::validationMessage,
-     XFA_Attribute::Unknown, XFA_ScriptType::Basic},
-    {0xe4c3a5e5, L"restoreState",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Subform::restoreState,
-     XFA_Attribute::RestoreState, XFA_ScriptType::Basic},
-    {0xeda9017a, L"scope", (XFA_ATTRIBUTE_CALLBACK)&CJX_Subform::scope,
-     XFA_Attribute::Scope, XFA_ScriptType::Basic},
-    {0xf65e34be, L"borderWidth",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Som_BorderWidth,
-     XFA_Attribute::Unknown, XFA_ScriptType::Basic},
-
-    /* select */
-    {0xc0811ed, L"use", (XFA_ATTRIBUTE_CALLBACK)&CJX_Select::use,
-     XFA_Attribute::Use, XFA_ScriptType::Basic},
-    {0xbc254332, L"usehref", (XFA_ATTRIBUTE_CALLBACK)&CJX_Select::usehref,
-     XFA_Attribute::Usehref, XFA_ScriptType::Basic},
-
-    /* window */
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-
-    /* localeSet */
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-
-    /* handler */
-    {0xc0811ed, L"use", (XFA_ATTRIBUTE_CALLBACK)&CJX_Handler::use,
-     XFA_Attribute::Use, XFA_ScriptType::Basic},
-    {0x2f16a382, L"type", (XFA_ATTRIBUTE_CALLBACK)&CJX_Handler::type,
-     XFA_Attribute::Type, XFA_ScriptType::Basic},
-    {0x5a50e9e6, L"version", (XFA_ATTRIBUTE_CALLBACK)&CJX_Handler::version,
-     XFA_Attribute::Unknown, XFA_ScriptType::Basic},
-    {0xbc254332, L"usehref", (XFA_ATTRIBUTE_CALLBACK)&CJX_Handler::usehref,
-     XFA_Attribute::Usehref, XFA_ScriptType::Basic},
-
-    /* hostPseudoModel */
-    {0x31b19c1, L"name", (XFA_ATTRIBUTE_CALLBACK)&CJX_HostPseudoModel::name,
-     XFA_Attribute::Unknown, XFA_ScriptType::Basic},
-    {0x66c1ae9, L"validationsEnabled",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_HostPseudoModel::validationsEnabled,
-     XFA_Attribute::Unknown, XFA_ScriptType::Basic},
-    {0x14d04502, L"title", (XFA_ATTRIBUTE_CALLBACK)&CJX_HostPseudoModel::title,
-     XFA_Attribute::Unknown, XFA_ScriptType::Basic},
-    {0x392ae445, L"platform",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_HostPseudoModel::platform,
-     XFA_Attribute::Unknown, XFA_ScriptType::Basic},
-    {0x5a50e9e6, L"version",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_HostPseudoModel::version,
-     XFA_Attribute::Unknown, XFA_ScriptType::Basic},
-    {0x66cb1eed, L"variation",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_HostPseudoModel::variation,
-     XFA_Attribute::Unknown, XFA_ScriptType::Basic},
-    {0x7717cbc4, L"language",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_HostPseudoModel::language,
-     XFA_Attribute::Unknown, XFA_ScriptType::Basic},
-    {0x86698963, L"appType",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_HostPseudoModel::appType,
-     XFA_Attribute::Unknown, XFA_ScriptType::Basic},
-    {0x94ff9e8d, L"calculationsEnabled",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_HostPseudoModel::calculationsEnabled,
-     XFA_Attribute::Unknown, XFA_ScriptType::Basic},
-    {0xbcd44940, L"currentPage",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_HostPseudoModel::currentPage,
-     XFA_Attribute::Unknown, XFA_ScriptType::Basic},
-    {0xd592b920, L"numPages",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_HostPseudoModel::numPages,
-     XFA_Attribute::Unknown, XFA_ScriptType::Basic},
-
-    /* presence */
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-
-    /* record */
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-
-    /* embed */
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-
-    /* version */
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-
-    /* command */
-    {0xc0811ed, L"use", (XFA_ATTRIBUTE_CALLBACK)&CJX_Command::use,
-     XFA_Attribute::Use, XFA_ScriptType::Basic},
-    {0x24d85167, L"timeout", (XFA_ATTRIBUTE_CALLBACK)&CJX_Command::timeout,
-     XFA_Attribute::Timeout, XFA_ScriptType::Basic},
-    {0xbc254332, L"usehref", (XFA_ATTRIBUTE_CALLBACK)&CJX_Command::usehref,
-     XFA_Attribute::Usehref, XFA_ScriptType::Basic},
-
-    /* copies */
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-
-    /* staple */
-    {0x7d9fd7c5, L"mode",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Mode, XFA_ScriptType::Basic},
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-
-    /* submitFormat */
-    {0x7d9fd7c5, L"mode",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_SubmitFormat_Mode,
-     XFA_Attribute::Unknown, XFA_ScriptType::Basic},
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-
-    /* boolean */
-    {0xc0811ed, L"use", (XFA_ATTRIBUTE_CALLBACK)&CJX_Boolean::use,
-     XFA_Attribute::Use, XFA_ScriptType::Basic},
-    {0xa52682bd, L"{default}",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Boolean::defaultValue, XFA_Attribute::Unknown,
-     XFA_ScriptType::Basic},
-    {0xbc254332, L"usehref", (XFA_ATTRIBUTE_CALLBACK)&CJX_Boolean::usehref,
-     XFA_Attribute::Usehref, XFA_ScriptType::Basic},
-    {0xd6e27f1d, L"value", (XFA_ATTRIBUTE_CALLBACK)&CJX_Boolean::value,
-     XFA_Attribute::Unknown, XFA_ScriptType::Basic},
-
-    /* message */
-    {0xc0811ed, L"use", (XFA_ATTRIBUTE_CALLBACK)&CJX_Message::use,
-     XFA_Attribute::Use, XFA_ScriptType::Basic},
-    {0xbc254332, L"usehref", (XFA_ATTRIBUTE_CALLBACK)&CJX_Message::usehref,
-     XFA_Attribute::Usehref, XFA_ScriptType::Basic},
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-
-    /* output */
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-
-    /* psMap */
-
-    /* excludeNS */
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-
-    /* assist */
-    {0xc0811ed, L"use", (XFA_ATTRIBUTE_CALLBACK)&CJX_Assist::use,
-     XFA_Attribute::Use, XFA_ScriptType::Basic},
-    {0x2038c9b2, L"role", (XFA_ATTRIBUTE_CALLBACK)&CJX_Assist::role,
-     XFA_Attribute::Role, XFA_ScriptType::Basic},
-    {0xbc254332, L"usehref", (XFA_ATTRIBUTE_CALLBACK)&CJX_Assist::usehref,
-     XFA_Attribute::Usehref, XFA_ScriptType::Basic},
-
-    /* picture */
-    {0xc0811ed, L"use", (XFA_ATTRIBUTE_CALLBACK)&CJX_Picture::use,
-     XFA_Attribute::Use, XFA_ScriptType::Basic},
-    {0xa52682bd, L"{default}",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Picture::defaultValue, XFA_Attribute::Unknown,
-     XFA_ScriptType::Basic},
-    {0xbc254332, L"usehref", (XFA_ATTRIBUTE_CALLBACK)&CJX_Picture::usehref,
-     XFA_Attribute::Usehref, XFA_ScriptType::Basic},
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xd6e27f1d, L"value", (XFA_ATTRIBUTE_CALLBACK)&CJX_Picture::value,
-     XFA_Attribute::Unknown, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-
-    /* traversal */
-    {0xc0811ed, L"use", (XFA_ATTRIBUTE_CALLBACK)&CJX_Traversal::use,
-     XFA_Attribute::Use, XFA_ScriptType::Basic},
-    {0xbc254332, L"usehref", (XFA_ATTRIBUTE_CALLBACK)&CJX_Traversal::usehref,
-     XFA_Attribute::Usehref, XFA_ScriptType::Basic},
-
-    /* silentPrint */
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-
-    /* webClient */
-    {0x31b19c1, L"name",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Name, XFA_ScriptType::Basic},
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-
-    /* layoutPseudoModel */
-    {0xfcef86b5, L"ready",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_LayoutPseudoModel::ready,
-     XFA_Attribute::Unknown, XFA_ScriptType::Basic},
-
-    /* producer */
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-
-    /* corner */
-    {0xc0811ed, L"use", (XFA_ATTRIBUTE_CALLBACK)&CJX_Corner::use,
-     XFA_Attribute::Use, XFA_ScriptType::Basic},
-    {0x5392ea58, L"stroke", (XFA_ATTRIBUTE_CALLBACK)&CJX_Corner::stroke,
-     XFA_Attribute::Stroke, XFA_ScriptType::Basic},
-    {0x570ce835, L"presence", (XFA_ATTRIBUTE_CALLBACK)&CJX_Corner::presence,
-     XFA_Attribute::Presence, XFA_ScriptType::Basic},
-    {0x7b95e661, L"inverted", (XFA_ATTRIBUTE_CALLBACK)&CJX_Corner::inverted,
-     XFA_Attribute::Inverted, XFA_ScriptType::Basic},
-    {0x94446dcc, L"thickness", (XFA_ATTRIBUTE_CALLBACK)&CJX_Corner::thickness,
-     XFA_Attribute::Thickness, XFA_ScriptType::Basic},
-    {0xbc254332, L"usehref", (XFA_ATTRIBUTE_CALLBACK)&CJX_Corner::usehref,
-     XFA_Attribute::Usehref, XFA_ScriptType::Basic},
-    {0xe8dddf50, L"join", (XFA_ATTRIBUTE_CALLBACK)&CJX_Corner::join,
-     XFA_Attribute::Join, XFA_ScriptType::Basic},
-    {0xe948b9a8, L"radius", (XFA_ATTRIBUTE_CALLBACK)&CJX_Corner::radius,
-     XFA_Attribute::Radius, XFA_ScriptType::Basic},
-
-    /* msgId */
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-
-    /* color */
-    {0xc0811ed, L"use", (XFA_ATTRIBUTE_CALLBACK)&CJX_Color::use,
-     XFA_Attribute::Use, XFA_ScriptType::Basic},
-    {0xabfa6c4f, L"cSpace", (XFA_ATTRIBUTE_CALLBACK)&CJX_Color::cSpace,
-     XFA_Attribute::CSpace, XFA_ScriptType::Basic},
-    {0xbc254332, L"usehref", (XFA_ATTRIBUTE_CALLBACK)&CJX_Color::usehref,
-     XFA_Attribute::Usehref, XFA_ScriptType::Basic},
-    {0xd6e27f1d, L"value", (XFA_ATTRIBUTE_CALLBACK)&CJX_Color::value,
-     XFA_Attribute::Value, XFA_ScriptType::Basic},
-
-    /* keep */
-    {0x3848b3f, L"next", (XFA_ATTRIBUTE_CALLBACK)&CJX_Keep::next,
-     XFA_Attribute::Next, XFA_ScriptType::Basic},
-    {0xc0811ed, L"use", (XFA_ATTRIBUTE_CALLBACK)&CJX_Keep::use,
-     XFA_Attribute::Use, XFA_ScriptType::Basic},
-    {0x6a3405dd, L"previous", (XFA_ATTRIBUTE_CALLBACK)&CJX_Keep::previous,
-     XFA_Attribute::Previous, XFA_ScriptType::Basic},
-    {0xbc254332, L"usehref", (XFA_ATTRIBUTE_CALLBACK)&CJX_Keep::usehref,
-     XFA_Attribute::Usehref, XFA_ScriptType::Basic},
-    {0xf6b59543, L"intact", (XFA_ATTRIBUTE_CALLBACK)&CJX_Keep::intact,
-     XFA_Attribute::Intact, XFA_ScriptType::Basic},
-
-    /* query */
-    {0xc0811ed, L"use", (XFA_ATTRIBUTE_CALLBACK)&CJX_Query::use,
-     XFA_Attribute::Use, XFA_ScriptType::Basic},
-    {0x268b7ec1, L"commandType",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Query::commandType,
-     XFA_Attribute::CommandType, XFA_ScriptType::Basic},
-    {0xbc254332, L"usehref", (XFA_ATTRIBUTE_CALLBACK)&CJX_Query::usehref,
-     XFA_Attribute::Usehref, XFA_ScriptType::Basic},
-
-    /* insert */
-    {0xc0811ed, L"use", (XFA_ATTRIBUTE_CALLBACK)&CJX_Insert::use,
-     XFA_Attribute::Use, XFA_ScriptType::Basic},
-    {0xbc254332, L"usehref", (XFA_ATTRIBUTE_CALLBACK)&CJX_Insert::usehref,
-     XFA_Attribute::Usehref, XFA_ScriptType::Basic},
-
-    /* imageEdit */
-    {0xc0811ed, L"use", (XFA_ATTRIBUTE_CALLBACK)&CJX_ImageEdit::use,
-     XFA_Attribute::Use, XFA_ScriptType::Basic},
-    {0xbc254332, L"usehref", (XFA_ATTRIBUTE_CALLBACK)&CJX_ImageEdit::usehref,
-     XFA_Attribute::Usehref, XFA_ScriptType::Basic},
-    {0xbde9abda, L"data", (XFA_ATTRIBUTE_CALLBACK)&CJX_ImageEdit::data,
-     XFA_Attribute::Data, XFA_ScriptType::Basic},
-
-    /* validate */
-    {0xc0811ed, L"use", (XFA_ATTRIBUTE_CALLBACK)&CJX_Validate::use,
-     XFA_Attribute::Use, XFA_ScriptType::Basic},
-    {0x5b707a35, L"scriptTest",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Validate::scriptTest,
-     XFA_Attribute::ScriptTest, XFA_ScriptType::Basic},
-    {0x6b6ddcfb, L"nullTest", (XFA_ATTRIBUTE_CALLBACK)&CJX_Validate::nullTest,
-     XFA_Attribute::NullTest, XFA_ScriptType::Basic},
-    {0xbc254332, L"usehref", (XFA_ATTRIBUTE_CALLBACK)&CJX_Validate::usehref,
-     XFA_Attribute::Usehref, XFA_ScriptType::Basic},
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xe64b1129, L"formatTest",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Validate::formatTest,
-     XFA_Attribute::FormatTest, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-
-    /* digestMethods */
-    {0xc0811ed, L"use", (XFA_ATTRIBUTE_CALLBACK)&CJX_DigestMethods::use,
-     XFA_Attribute::Use, XFA_ScriptType::Basic},
-    {0x2f16a382, L"type", (XFA_ATTRIBUTE_CALLBACK)&CJX_DigestMethods::type,
-     XFA_Attribute::Type, XFA_ScriptType::Basic},
-    {0xbc254332, L"usehref",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_DigestMethods::usehref,
-     XFA_Attribute::Usehref, XFA_ScriptType::Basic},
-
-    /* numberPatterns */
-
-    /* pageSet */
-    {0xc0811ed, L"use", (XFA_ATTRIBUTE_CALLBACK)&CJX_PageSet::use,
-     XFA_Attribute::Use, XFA_ScriptType::Basic},
-    {0x8c99377e, L"relation", (XFA_ATTRIBUTE_CALLBACK)&CJX_PageSet::relation,
-     XFA_Attribute::Relation, XFA_ScriptType::Basic},
-    {0x8e1c2921, L"relevant", (XFA_ATTRIBUTE_CALLBACK)&CJX_PageSet::relevant,
-     XFA_Attribute::Relevant, XFA_ScriptType::Basic},
-    {0xbc254332, L"usehref", (XFA_ATTRIBUTE_CALLBACK)&CJX_PageSet::usehref,
-     XFA_Attribute::Usehref, XFA_ScriptType::Basic},
-
-    /* integer */
-    {0xc0811ed, L"use", (XFA_ATTRIBUTE_CALLBACK)&CJX_Integer::use,
-     XFA_Attribute::Use, XFA_ScriptType::Basic},
-    {0xa52682bd, L"{default}",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Integer::defaultValue, XFA_Attribute::Unknown,
-     XFA_ScriptType::Basic},
-    {0xbc254332, L"usehref", (XFA_ATTRIBUTE_CALLBACK)&CJX_Integer::usehref,
-     XFA_Attribute::Usehref, XFA_ScriptType::Basic},
-    {0xd6e27f1d, L"value", (XFA_ATTRIBUTE_CALLBACK)&CJX_Integer::value,
-     XFA_Attribute::Unknown, XFA_ScriptType::Basic},
-
-    /* soapAddress */
-    {0xc0811ed, L"use", (XFA_ATTRIBUTE_CALLBACK)&CJX_SoapAddress::use,
-     XFA_Attribute::Use, XFA_ScriptType::Basic},
-    {0xbc254332, L"usehref", (XFA_ATTRIBUTE_CALLBACK)&CJX_SoapAddress::usehref,
-     XFA_Attribute::Usehref, XFA_ScriptType::Basic},
-
-    /* equate */
-    {0x25363, L"to",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::To, XFA_ScriptType::Basic},
-    {0x66642f8f, L"force",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Force, XFA_ScriptType::Basic},
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xcd7f7b54, L"from",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::From, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-
-    /* formFieldFilling */
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-
-    /* pageRange */
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-
-    /* update */
-    {0xc0811ed, L"use", (XFA_ATTRIBUTE_CALLBACK)&CJX_Update::use,
-     XFA_Attribute::Use, XFA_ScriptType::Basic},
-    {0xbc254332, L"usehref", (XFA_ATTRIBUTE_CALLBACK)&CJX_Update::usehref,
-     XFA_Attribute::Usehref, XFA_ScriptType::Basic},
-
-    /* connectString */
-    {0xc0811ed, L"use", (XFA_ATTRIBUTE_CALLBACK)&CJX_ConnectString::use,
-     XFA_Attribute::Use, XFA_ScriptType::Basic},
-    {0xbc254332, L"usehref",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_ConnectString::usehref,
-     XFA_Attribute::Usehref, XFA_ScriptType::Basic},
-
-    /* mode */
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-
-    /* layout */
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-
-    /* #xml */
-    {0xd6e27f1d, L"value",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Value, XFA_ScriptType::Basic},
-
-    /* xsdConnection */
-    {0x2b5df51e, L"dataDescription",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_XsdConnection::dataDescription,
-     XFA_Attribute::DataDescription, XFA_ScriptType::Basic},
-
-    /* traverse */
-    {0xbb8df5d, L"ref", (XFA_ATTRIBUTE_CALLBACK)&CJX_Traverse::ref,
-     XFA_Attribute::Ref, XFA_ScriptType::Basic},
-    {0xc0811ed, L"use", (XFA_ATTRIBUTE_CALLBACK)&CJX_Traverse::use,
-     XFA_Attribute::Use, XFA_ScriptType::Basic},
-    {0x226ca8f1, L"operation", (XFA_ATTRIBUTE_CALLBACK)&CJX_Traverse::operation,
-     XFA_Attribute::Operation, XFA_ScriptType::Basic},
-    {0xbc254332, L"usehref", (XFA_ATTRIBUTE_CALLBACK)&CJX_Traverse::usehref,
-     XFA_Attribute::Usehref, XFA_ScriptType::Basic},
-
-    /* encodings */
-    {0xc0811ed, L"use", (XFA_ATTRIBUTE_CALLBACK)&CJX_Encodings::use,
-     XFA_Attribute::Use, XFA_ScriptType::Basic},
-    {0x2f16a382, L"type", (XFA_ATTRIBUTE_CALLBACK)&CJX_Encodings::type,
-     XFA_Attribute::Type, XFA_ScriptType::Basic},
-    {0xbc254332, L"usehref", (XFA_ATTRIBUTE_CALLBACK)&CJX_Encodings::usehref,
-     XFA_Attribute::Usehref, XFA_ScriptType::Basic},
-
-    /* template */
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-
-    /* acrobat */
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-
-    /* validationMessaging */
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-
-    /* signing */
-    {0xc0811ed, L"use", (XFA_ATTRIBUTE_CALLBACK)&CJX_Signing::use,
-     XFA_Attribute::Use, XFA_ScriptType::Basic},
-    {0x2f16a382, L"type", (XFA_ATTRIBUTE_CALLBACK)&CJX_Signing::type,
-     XFA_Attribute::Type, XFA_ScriptType::Basic},
-    {0xbc254332, L"usehref", (XFA_ATTRIBUTE_CALLBACK)&CJX_Signing::usehref,
-     XFA_Attribute::Usehref, XFA_ScriptType::Basic},
-
-    /* dataWindow */
-    {0xfb67185, L"recordsBefore",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_DataWindow::recordsBefore,
-     XFA_Attribute::Unknown, XFA_ScriptType::Basic},
-    {0x21d5dfcb, L"currentRecordNumber",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_DataWindow::currentRecordNumber,
-     XFA_Attribute::Unknown, XFA_ScriptType::Basic},
-    {0x312af044, L"recordsAfter",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_DataWindow::recordsAfter,
-     XFA_Attribute::Unknown, XFA_ScriptType::Basic},
-    {0x6aab37cb, L"isDefined",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_DataWindow::isDefined, XFA_Attribute::Unknown,
-     XFA_ScriptType::Basic},
-
-    /* script */
-    {0xc0811ed, L"use", (XFA_ATTRIBUTE_CALLBACK)&CJX_Script::use,
-     XFA_Attribute::Use, XFA_ScriptType::Basic},
-    {0x42fed1fd, L"contentType",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Script::contentType,
-     XFA_Attribute::ContentType, XFA_ScriptType::Basic},
-    {0x6cfa828a, L"runAt", (XFA_ATTRIBUTE_CALLBACK)&CJX_Script::runAt,
-     XFA_Attribute::RunAt, XFA_ScriptType::Basic},
-    {0xa021b738, L"stateless", (XFA_ATTRIBUTE_CALLBACK)&CJX_Script::stateless,
-     XFA_Attribute::Unknown, XFA_ScriptType::Basic},
-    {0xa52682bd, L"{default}",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Script::defaultValue, XFA_Attribute::Unknown,
-     XFA_ScriptType::Basic},
-    {0xadc4c77b, L"binding", (XFA_ATTRIBUTE_CALLBACK)&CJX_Script::binding,
-     XFA_Attribute::Binding, XFA_ScriptType::Basic},
-    {0xbc254332, L"usehref", (XFA_ATTRIBUTE_CALLBACK)&CJX_Script::usehref,
-     XFA_Attribute::Usehref, XFA_ScriptType::Basic},
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xd6e27f1d, L"value", (XFA_ATTRIBUTE_CALLBACK)&CJX_Script::value,
-     XFA_Attribute::Unknown, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-
-    /* addViewerPreferences */
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-
-    /* alwaysEmbed */
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-
-    /* passwordEdit */
-    {0xc0811ed, L"use", (XFA_ATTRIBUTE_CALLBACK)&CJX_PasswordEdit::use,
-     XFA_Attribute::Use, XFA_ScriptType::Basic},
-    {0x7a0cc471, L"passwordChar",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_PasswordEdit::passwordChar,
-     XFA_Attribute::PasswordChar, XFA_ScriptType::Basic},
-    {0xbc254332, L"usehref", (XFA_ATTRIBUTE_CALLBACK)&CJX_PasswordEdit::usehref,
-     XFA_Attribute::Usehref, XFA_ScriptType::Basic},
-    {0xe6f99487, L"hScrollPolicy",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_PasswordEdit::hScrollPolicy,
-     XFA_Attribute::HScrollPolicy, XFA_ScriptType::Basic},
-
-    /* numericEdit */
-    {0xc0811ed, L"use", (XFA_ATTRIBUTE_CALLBACK)&CJX_NumericEdit::use,
-     XFA_Attribute::Use, XFA_ScriptType::Basic},
-    {0xbc254332, L"usehref", (XFA_ATTRIBUTE_CALLBACK)&CJX_NumericEdit::usehref,
-     XFA_Attribute::Usehref, XFA_ScriptType::Basic},
-    {0xe6f99487, L"hScrollPolicy",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_NumericEdit::hScrollPolicy,
-     XFA_Attribute::HScrollPolicy, XFA_ScriptType::Basic},
-
-    /* encryptionMethod */
-    {0xc0811ed, L"use",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Use, XFA_ScriptType::Basic},
-    {0xbc254332, L"usehref",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Usehref, XFA_ScriptType::Basic},
-
-    /* change */
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-
-    /* pageArea */
-    {0xc0811ed, L"use", (XFA_ATTRIBUTE_CALLBACK)&CJX_PageArea::use,
-     XFA_Attribute::Use, XFA_ScriptType::Basic},
-    {0x14a32d52, L"pagePosition",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_PageArea::pagePosition,
-     XFA_Attribute::PagePosition, XFA_ScriptType::Basic},
-    {0x8340ea66, L"oddOrEven", (XFA_ATTRIBUTE_CALLBACK)&CJX_PageArea::oddOrEven,
-     XFA_Attribute::OddOrEven, XFA_ScriptType::Basic},
-    {0x8e1c2921, L"relevant", (XFA_ATTRIBUTE_CALLBACK)&CJX_PageArea::relevant,
-     XFA_Attribute::Relevant, XFA_ScriptType::Basic},
-    {0xa85e74f3, L"initialNumber",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_PageArea::initialNumber,
-     XFA_Attribute::InitialNumber, XFA_ScriptType::Basic},
-    {0xbc254332, L"usehref", (XFA_ATTRIBUTE_CALLBACK)&CJX_PageArea::usehref,
-     XFA_Attribute::Usehref, XFA_ScriptType::Basic},
-    {0xbe9ba472, L"numbered", (XFA_ATTRIBUTE_CALLBACK)&CJX_PageArea::numbered,
-     XFA_Attribute::Numbered, XFA_ScriptType::Basic},
-    {0xd70798c2, L"blankOrNotBlank",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_PageArea::blankOrNotBlank,
-     XFA_Attribute::BlankOrNotBlank, XFA_ScriptType::Basic},
-
-    /* submitUrl */
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xd6e27f1d, L"value",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Som_DefaultValue,
-     XFA_Attribute::Unknown, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-
-    /* oids */
-    {0xc0811ed, L"use", (XFA_ATTRIBUTE_CALLBACK)&CJX_Oids::use,
-     XFA_Attribute::Use, XFA_ScriptType::Basic},
-    {0x2f16a382, L"type", (XFA_ATTRIBUTE_CALLBACK)&CJX_Oids::type,
-     XFA_Attribute::Type, XFA_ScriptType::Basic},
-    {0xbc254332, L"usehref", (XFA_ATTRIBUTE_CALLBACK)&CJX_Oids::usehref,
-     XFA_Attribute::Usehref, XFA_ScriptType::Basic},
-
-    /* signature */
-    {0xc0811ed, L"use", (XFA_ATTRIBUTE_CALLBACK)&CJX_Signature::use,
-     XFA_Attribute::Use, XFA_ScriptType::Basic},
-    {0xbc254332, L"usehref", (XFA_ATTRIBUTE_CALLBACK)&CJX_Signature::usehref,
-     XFA_Attribute::Usehref, XFA_ScriptType::Basic},
-
-    /* aDBE_JSConsole */
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-
-    /* caption */
-    {0xc0811ed, L"use", (XFA_ATTRIBUTE_CALLBACK)&CJX_Caption::use,
-     XFA_Attribute::Use, XFA_ScriptType::Basic},
-    {0x34ae103c, L"reserve", (XFA_ATTRIBUTE_CALLBACK)&CJX_Caption::reserve,
-     XFA_Attribute::Reserve, XFA_ScriptType::Basic},
-    {0x570ce835, L"presence", (XFA_ATTRIBUTE_CALLBACK)&CJX_Caption::presence,
-     XFA_Attribute::Presence, XFA_ScriptType::Basic},
-    {0xbc254332, L"usehref", (XFA_ATTRIBUTE_CALLBACK)&CJX_Caption::usehref,
-     XFA_Attribute::Usehref, XFA_ScriptType::Basic},
-    {0xf2009339, L"placement", (XFA_ATTRIBUTE_CALLBACK)&CJX_Caption::placement,
-     XFA_Attribute::Placement, XFA_ScriptType::Basic},
-
-    /* relevant */
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-
-    /* flipLabel */
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-
-    /* exData */
-    {0xc0811ed, L"use", (XFA_ATTRIBUTE_CALLBACK)&CJX_ExData::use,
-     XFA_Attribute::Use, XFA_ScriptType::Basic},
-    {0x42fed1fd, L"contentType",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_ExData::contentType,
-     XFA_Attribute::ContentType, XFA_ScriptType::Basic},
-    {0x54fa722c, L"transferEncoding",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_ExData::transferEncoding,
-     XFA_Attribute::TransferEncoding, XFA_ScriptType::Basic},
-    {0xa52682bd, L"{default}",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_ExData::defaultValue, XFA_Attribute::Unknown,
-     XFA_ScriptType::Basic},
-    {0xbc254332, L"usehref", (XFA_ATTRIBUTE_CALLBACK)&CJX_ExData::usehref,
-     XFA_Attribute::Usehref, XFA_ScriptType::Basic},
-    {0xc4547a08, L"maxLength", (XFA_ATTRIBUTE_CALLBACK)&CJX_ExData::maxLength,
-     XFA_Attribute::MaxLength, XFA_ScriptType::Basic},
-    {0xd6e27f1d, L"value",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Som_DefaultValue,
-     XFA_Attribute::Unknown, XFA_ScriptType::Basic},
-    {0xdb55fec5, L"href", (XFA_ATTRIBUTE_CALLBACK)&CJX_ExData::href,
-     XFA_Attribute::Href, XFA_ScriptType::Basic},
-
-    /* dayNames */
-    {0x29418bb7, L"abbr",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Abbr, XFA_ScriptType::Basic},
-
-    /* soapAction */
-    {0xc0811ed, L"use", (XFA_ATTRIBUTE_CALLBACK)&CJX_SoapAction::use,
-     XFA_Attribute::Use, XFA_ScriptType::Basic},
-    {0xbc254332, L"usehref", (XFA_ATTRIBUTE_CALLBACK)&CJX_SoapAction::usehref,
-     XFA_Attribute::Usehref, XFA_ScriptType::Basic},
-
-    /* defaultTypeface */
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xf531b059, L"writingScript",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::WritingScript, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-
-    /* manifest */
-    {0xc0811ed, L"use", (XFA_ATTRIBUTE_CALLBACK)&CJX_Manifest::use,
-     XFA_Attribute::Use, XFA_ScriptType::Basic},
-    {0x1b8dce3e, L"action", (XFA_ATTRIBUTE_CALLBACK)&CJX_Manifest::action,
-     XFA_Attribute::Action, XFA_ScriptType::Basic},
-    {0xa52682bd, L"{default}",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Manifest::defaultValue,
-     XFA_Attribute::Unknown, XFA_ScriptType::Basic},
-    {0xbc254332, L"usehref", (XFA_ATTRIBUTE_CALLBACK)&CJX_Manifest::usehref,
-     XFA_Attribute::Usehref, XFA_ScriptType::Basic},
-
-    /* overflow */
-    {0xc0811ed, L"use", (XFA_ATTRIBUTE_CALLBACK)&CJX_Overflow::use,
-     XFA_Attribute::Use, XFA_ScriptType::Basic},
-    {0x9dcc3ab3, L"trailer", (XFA_ATTRIBUTE_CALLBACK)&CJX_Overflow::trailer,
-     XFA_Attribute::Trailer, XFA_ScriptType::Basic},
-    {0xbc254332, L"usehref", (XFA_ATTRIBUTE_CALLBACK)&CJX_Overflow::usehref,
-     XFA_Attribute::Usehref, XFA_ScriptType::Basic},
-    {0xc8da4da7, L"target", (XFA_ATTRIBUTE_CALLBACK)&CJX_Overflow::target,
-     XFA_Attribute::Target, XFA_ScriptType::Basic},
-    {0xcbcaf66d, L"leader", (XFA_ATTRIBUTE_CALLBACK)&CJX_Overflow::leader,
-     XFA_Attribute::Leader, XFA_ScriptType::Basic},
-
-    /* linear */
-    {0xc0811ed, L"use", (XFA_ATTRIBUTE_CALLBACK)&CJX_Linear::use,
-     XFA_Attribute::Use, XFA_ScriptType::Basic},
-    {0x2f16a382, L"type", (XFA_ATTRIBUTE_CALLBACK)&CJX_Linear::type,
-     XFA_Attribute::Type, XFA_ScriptType::Basic},
-    {0xbc254332, L"usehref", (XFA_ATTRIBUTE_CALLBACK)&CJX_Linear::usehref,
-     XFA_Attribute::Usehref, XFA_ScriptType::Basic},
-
-    /* currencySymbol */
-    {0x31b19c1, L"name",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Name, XFA_ScriptType::Basic},
-
-    /* delete */
-    {0xc0811ed, L"use", (XFA_ATTRIBUTE_CALLBACK)&CJX_Delete::use,
-     XFA_Attribute::Use, XFA_ScriptType::Basic},
-    {0xbc254332, L"usehref", (XFA_ATTRIBUTE_CALLBACK)&CJX_Delete::usehref,
-     XFA_Attribute::Usehref, XFA_ScriptType::Basic},
-
-    /* deltas */
-
-    /* digestMethod */
-    {0xc0811ed, L"use", (XFA_ATTRIBUTE_CALLBACK)&CJX_DigestMethod::use,
-     XFA_Attribute::Use, XFA_ScriptType::Basic},
-    {0xbc254332, L"usehref", (XFA_ATTRIBUTE_CALLBACK)&CJX_DigestMethod::usehref,
-     XFA_Attribute::Usehref, XFA_ScriptType::Basic},
-
-    /* instanceManager */
-    {0xb3543a6, L"max", (XFA_ATTRIBUTE_CALLBACK)&CJX_InstanceManager::max,
-     XFA_Attribute::Unknown, XFA_ScriptType::Basic},
-    {0xb356ca4, L"min", (XFA_ATTRIBUTE_CALLBACK)&CJX_InstanceManager::min,
-     XFA_Attribute::Unknown, XFA_ScriptType::Basic},
-    {0x6f544d49, L"count", (XFA_ATTRIBUTE_CALLBACK)&CJX_InstanceManager::count,
-     XFA_Attribute::Unknown, XFA_ScriptType::Basic},
-
-    /* equateRange */
-    {0x25363, L"to",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::To, XFA_ScriptType::Basic},
-    {0xa0933954, L"unicodeRange",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::UnicodeRange, XFA_ScriptType::Basic},
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xcd7f7b54, L"from",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::From, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-
-    /* medium */
-    {0xc0811ed, L"use", (XFA_ATTRIBUTE_CALLBACK)&CJX_Medium::use,
-     XFA_Attribute::Use, XFA_ScriptType::Basic},
-    {0x4ef3d02c, L"orientation",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Medium::orientation,
-     XFA_Attribute::Orientation, XFA_ScriptType::Basic},
-    {0x65e30c67, L"imagingBBox",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Medium::imagingBBox,
-     XFA_Attribute::ImagingBBox, XFA_ScriptType::Basic},
-    {0x9041d4b0, L"short", (XFA_ATTRIBUTE_CALLBACK)&CJX_Medium::shortValue,
-     XFA_Attribute::Short, XFA_ScriptType::Basic},
-    {0xbc254332, L"usehref", (XFA_ATTRIBUTE_CALLBACK)&CJX_Medium::usehref,
-     XFA_Attribute::Usehref, XFA_ScriptType::Basic},
-    {0xe349d044, L"stock", (XFA_ATTRIBUTE_CALLBACK)&CJX_Medium::stock,
-     XFA_Attribute::Stock, XFA_ScriptType::Basic},
-    {0xf6b4afb0, L"long", (XFA_ATTRIBUTE_CALLBACK)&CJX_Medium::longValue,
-     XFA_Attribute::Long, XFA_ScriptType::Basic},
-
-    /* textEdit */
-    {0x5ce6195, L"vScrollPolicy",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_TextEdit::vScrollPolicy,
-     XFA_Attribute::VScrollPolicy, XFA_ScriptType::Basic},
-    {0xc0811ed, L"use", (XFA_ATTRIBUTE_CALLBACK)&CJX_TextEdit::use,
-     XFA_Attribute::Use, XFA_ScriptType::Basic},
-    {0x1ef3a64a, L"allowRichText",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_TextEdit::allowRichText,
-     XFA_Attribute::AllowRichText, XFA_ScriptType::Basic},
-    {0x5a32e493, L"multiLine", (XFA_ATTRIBUTE_CALLBACK)&CJX_TextEdit::multiLine,
-     XFA_Attribute::MultiLine, XFA_ScriptType::Basic},
-    {0xbc254332, L"usehref", (XFA_ATTRIBUTE_CALLBACK)&CJX_TextEdit::usehref,
-     XFA_Attribute::Usehref, XFA_ScriptType::Basic},
-    {0xe6f99487, L"hScrollPolicy",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_TextEdit::hScrollPolicy,
-     XFA_Attribute::HScrollPolicy, XFA_ScriptType::Basic},
-
-    /* templateCache */
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xd52482e0, L"maxEntries",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::MaxEntries, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-
-    /* compressObjectStream */
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-
-    /* dataValue */
-    {0x42fed1fd, L"contentType",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_DataValue::contentType,
-     XFA_Attribute::ContentType, XFA_ScriptType::Basic},
-    {0x8855805f, L"contains", (XFA_ATTRIBUTE_CALLBACK)&CJX_DataValue::contains,
-     XFA_Attribute::Contains, XFA_ScriptType::Basic},
-    {0xa52682bd, L"{default}",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_DataValue::defaultValue,
-     XFA_Attribute::Unknown, XFA_ScriptType::Basic},
-    {0xd6e27f1d, L"value", (XFA_ATTRIBUTE_CALLBACK)&CJX_DataValue::value,
-     XFA_Attribute::Unknown, XFA_ScriptType::Basic},
-    {0xe372ae97, L"isNull", (XFA_ATTRIBUTE_CALLBACK)&CJX_DataValue::isNull,
-     XFA_Attribute::IsNull, XFA_ScriptType::Basic},
-
-    /* accessibleContent */
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-
-    /* nodeList */
-
-    /* includeXDPContent */
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-
-    /* xmlConnection */
-    {0x2b5df51e, L"dataDescription",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_XmlConnection::dataDescription,
-     XFA_Attribute::DataDescription, XFA_ScriptType::Basic},
-
-    /* validateApprovalSignatures */
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-
-    /* signData */
-    {0xbb8df5d, L"ref", (XFA_ATTRIBUTE_CALLBACK)&CJX_SignData::ref,
-     XFA_Attribute::Ref, XFA_ScriptType::Basic},
-    {0xc0811ed, L"use", (XFA_ATTRIBUTE_CALLBACK)&CJX_SignData::use,
-     XFA_Attribute::Use, XFA_ScriptType::Basic},
-    {0x226ca8f1, L"operation", (XFA_ATTRIBUTE_CALLBACK)&CJX_SignData::operation,
-     XFA_Attribute::Operation, XFA_ScriptType::Basic},
-    {0xbc254332, L"usehref", (XFA_ATTRIBUTE_CALLBACK)&CJX_SignData::usehref,
-     XFA_Attribute::Usehref, XFA_ScriptType::Basic},
-    {0xc8da4da7, L"target", (XFA_ATTRIBUTE_CALLBACK)&CJX_SignData::target,
-     XFA_Attribute::Target, XFA_ScriptType::Basic},
-
-    /* packets */
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-
-    /* datePattern */
-    {0x31b19c1, L"name",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Name, XFA_ScriptType::Basic},
-
-    /* duplexOption */
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-
-    /* base */
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-
-    /* bind */
-    {0xbb8df5d, L"ref", (XFA_ATTRIBUTE_CALLBACK)&CJX_Bind::ref,
-     XFA_Attribute::Ref, XFA_ScriptType::Basic},
-    {0xc0811ed, L"use", (XFA_ATTRIBUTE_CALLBACK)&CJX_Bind::use,
-     XFA_Attribute::Use, XFA_ScriptType::Basic},
-    {0x42fed1fd, L"contentType", (XFA_ATTRIBUTE_CALLBACK)&CJX_Bind::contentType,
-     XFA_Attribute::ContentType, XFA_ScriptType::Basic},
-    {0x54fa722c, L"transferEncoding",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Bind::transferEncoding,
-     XFA_Attribute::TransferEncoding, XFA_ScriptType::Basic},
-    {0xbc254332, L"usehref", (XFA_ATTRIBUTE_CALLBACK)&CJX_Bind::usehref,
-     XFA_Attribute::Usehref, XFA_ScriptType::Basic},
-    {0xf197844d, L"match", (XFA_ATTRIBUTE_CALLBACK)&CJX_Bind::match,
-     XFA_Attribute::Match, XFA_ScriptType::Basic},
-
-    /* compression */
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-
-    /* user */
-    {0xc0811ed, L"use", (XFA_ATTRIBUTE_CALLBACK)&CJX_User::use,
-     XFA_Attribute::Use, XFA_ScriptType::Basic},
-    {0xbc254332, L"usehref", (XFA_ATTRIBUTE_CALLBACK)&CJX_User::usehref,
-     XFA_Attribute::Usehref, XFA_ScriptType::Basic},
-
-    /* rectangle */
-    {0xc0811ed, L"use", (XFA_ATTRIBUTE_CALLBACK)&CJX_Rectangle::use,
-     XFA_Attribute::Use, XFA_ScriptType::Basic},
-    {0xbc254332, L"usehref", (XFA_ATTRIBUTE_CALLBACK)&CJX_Rectangle::usehref,
-     XFA_Attribute::Usehref, XFA_ScriptType::Basic},
-    {0xd996fa9b, L"hand", (XFA_ATTRIBUTE_CALLBACK)&CJX_Rectangle::hand,
-     XFA_Attribute::Hand, XFA_ScriptType::Basic},
-
-    /* effectiveOutputPolicy */
-    {0x21aed, L"id",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Id, XFA_ScriptType::Basic},
-    {0x31b19c1, L"name",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Name, XFA_ScriptType::Basic},
-    {0xc0811ed, L"use",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Use, XFA_ScriptType::Basic},
-    {0xbc254332, L"usehref",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Usehref, XFA_ScriptType::Basic},
-
-    /* aDBE_JSDebugger */
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-
-    /* acrobat7 */
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-
-    /* interactive */
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-
-    /* locale */
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-
-    /* currentPage */
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-
-    /* data */
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-
-    /* date */
-    {0xc0811ed, L"use", (XFA_ATTRIBUTE_CALLBACK)&CJX_Date::use,
-     XFA_Attribute::Use, XFA_ScriptType::Basic},
-    {0xa52682bd, L"{default}", (XFA_ATTRIBUTE_CALLBACK)&CJX_Date::defaultValue,
-     XFA_Attribute::Unknown, XFA_ScriptType::Basic},
-    {0xbc254332, L"usehref", (XFA_ATTRIBUTE_CALLBACK)&CJX_Date::usehref,
-     XFA_Attribute::Usehref, XFA_ScriptType::Basic},
-    {0xd6e27f1d, L"value", (XFA_ATTRIBUTE_CALLBACK)&CJX_Date::value,
-     XFA_Attribute::Unknown, XFA_ScriptType::Basic},
-
-    /* desc */
-    {0xc0811ed, L"use", (XFA_ATTRIBUTE_CALLBACK)&CJX_Desc::use,
-     XFA_Attribute::Use, XFA_ScriptType::Basic},
-    {0xbc254332, L"usehref", (XFA_ATTRIBUTE_CALLBACK)&CJX_Desc::usehref,
-     XFA_Attribute::Usehref, XFA_ScriptType::Basic},
-
-    /* encrypt */
-    {0xc0811ed, L"use", (XFA_ATTRIBUTE_CALLBACK)&CJX_Encrypt::use,
-     XFA_Attribute::Use, XFA_ScriptType::Basic},
-    {0x28dee6e9, L"format", (XFA_ATTRIBUTE_CALLBACK)&CJX_Encrypt::format,
-     XFA_Attribute::Unknown, XFA_ScriptType::Basic},
-    {0xbc254332, L"usehref", (XFA_ATTRIBUTE_CALLBACK)&CJX_Encrypt::usehref,
-     XFA_Attribute::Usehref, XFA_ScriptType::Basic},
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-
-    /* draw */
-    {0x68, L"h", (XFA_ATTRIBUTE_CALLBACK)&CJX_Draw::h, XFA_Attribute::H,
-     XFA_ScriptType::Basic},
-    {0x77, L"w", (XFA_ATTRIBUTE_CALLBACK)&CJX_Draw::w, XFA_Attribute::W,
-     XFA_ScriptType::Basic},
-    {0x78, L"x", (XFA_ATTRIBUTE_CALLBACK)&CJX_Draw::x, XFA_Attribute::X,
-     XFA_ScriptType::Basic},
-    {0x79, L"y", (XFA_ATTRIBUTE_CALLBACK)&CJX_Draw::y, XFA_Attribute::Y,
-     XFA_ScriptType::Basic},
-    {0x2282c73, L"hAlign", (XFA_ATTRIBUTE_CALLBACK)&CJX_Draw::hAlign,
-     XFA_Attribute::HAlign, XFA_ScriptType::Basic},
-    {0xc0811ed, L"use", (XFA_ATTRIBUTE_CALLBACK)&CJX_Draw::use,
-     XFA_Attribute::Use, XFA_ScriptType::Basic},
-    {0x2ee7678f, L"rotate", (XFA_ATTRIBUTE_CALLBACK)&CJX_Draw::rotate,
-     XFA_Attribute::Rotate, XFA_ScriptType::Basic},
-    {0x570ce835, L"presence", (XFA_ATTRIBUTE_CALLBACK)&CJX_Draw::presence,
-     XFA_Attribute::Presence, XFA_ScriptType::Basic},
-    {0x7a7cc341, L"vAlign", (XFA_ATTRIBUTE_CALLBACK)&CJX_Draw::vAlign,
-     XFA_Attribute::VAlign, XFA_ScriptType::Basic},
-    {0x7c2ff6ae, L"maxH", (XFA_ATTRIBUTE_CALLBACK)&CJX_Draw::maxH,
-     XFA_Attribute::MaxH, XFA_ScriptType::Basic},
-    {0x7c2ff6bd, L"maxW", (XFA_ATTRIBUTE_CALLBACK)&CJX_Draw::maxW,
-     XFA_Attribute::MaxW, XFA_ScriptType::Basic},
-    {0x7d02356c, L"minH", (XFA_ATTRIBUTE_CALLBACK)&CJX_Draw::minH,
-     XFA_Attribute::MinH, XFA_ScriptType::Basic},
-    {0x7d02357b, L"minW", (XFA_ATTRIBUTE_CALLBACK)&CJX_Draw::minW,
-     XFA_Attribute::MinW, XFA_ScriptType::Basic},
-    {0x8e1c2921, L"relevant", (XFA_ATTRIBUTE_CALLBACK)&CJX_Draw::relevant,
-     XFA_Attribute::Relevant, XFA_ScriptType::Basic},
-    {0xa03cf627, L"rawValue", (XFA_ATTRIBUTE_CALLBACK)&CJX_Draw::rawValue,
-     XFA_Attribute::Unknown, XFA_ScriptType::Basic},
-    {0xa52682bd, L"{default}", (XFA_ATTRIBUTE_CALLBACK)&CJX_Draw::defaultValue,
-     XFA_Attribute::Unknown, XFA_ScriptType::Basic},
-    {0xac06e2b0, L"colSpan", (XFA_ATTRIBUTE_CALLBACK)&CJX_Draw::colSpan,
-     XFA_Attribute::ColSpan, XFA_ScriptType::Basic},
-    {0xbc254332, L"usehref", (XFA_ATTRIBUTE_CALLBACK)&CJX_Draw::usehref,
-     XFA_Attribute::Usehref, XFA_ScriptType::Basic},
-    {0xbc8fa350, L"locale", (XFA_ATTRIBUTE_CALLBACK)&CJX_Draw::locale,
-     XFA_Attribute::Locale, XFA_ScriptType::Basic},
-    {0xc2bd40fd, L"anchorType", (XFA_ATTRIBUTE_CALLBACK)&CJX_Draw::anchorType,
-     XFA_Attribute::AnchorType, XFA_ScriptType::Basic},
-
-    /* encryption */
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-
-    /* meridiemNames */
-
-    /* messaging */
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-
-    /* speak */
-    {0xc0811ed, L"use", (XFA_ATTRIBUTE_CALLBACK)&CJX_Speak::use,
-     XFA_Attribute::Use, XFA_ScriptType::Basic},
-    {0x39cdb0a2, L"priority", (XFA_ATTRIBUTE_CALLBACK)&CJX_Speak::priority,
-     XFA_Attribute::Priority, XFA_ScriptType::Basic},
-    {0xbc254332, L"usehref", (XFA_ATTRIBUTE_CALLBACK)&CJX_Speak::usehref,
-     XFA_Attribute::Usehref, XFA_ScriptType::Basic},
-    {0xeb511b54, L"disable", (XFA_ATTRIBUTE_CALLBACK)&CJX_Speak::disable,
-     XFA_Attribute::Disable, XFA_ScriptType::Basic},
-
-    /* dataGroup */
-
-    /* common */
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-
-    /* #text */
-    {0xd6e27f1d, L"value",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Value, XFA_ScriptType::Basic},
-
-    /* paginationOverride */
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-
-    /* reasons */
-    {0xc0811ed, L"use", (XFA_ATTRIBUTE_CALLBACK)&CJX_Reasons::use,
-     XFA_Attribute::Use, XFA_ScriptType::Basic},
-    {0x2f16a382, L"type", (XFA_ATTRIBUTE_CALLBACK)&CJX_Reasons::type,
-     XFA_Attribute::Type, XFA_ScriptType::Basic},
-    {0xbc254332, L"usehref", (XFA_ATTRIBUTE_CALLBACK)&CJX_Reasons::usehref,
-     XFA_Attribute::Usehref, XFA_ScriptType::Basic},
-
-    /* signatureProperties */
-    {0xc0811ed, L"use", (XFA_ATTRIBUTE_CALLBACK)&CJX_SignatureProperties::use,
-     XFA_Attribute::Use, XFA_ScriptType::Basic},
-    {0xbc254332, L"usehref",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_SignatureProperties::usehref,
-     XFA_Attribute::Usehref, XFA_ScriptType::Basic},
-
-    /* threshold */
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-
-    /* appearanceFilter */
-    {0x21aed, L"id",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Id, XFA_ScriptType::Basic},
-    {0xc0811ed, L"use",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Use, XFA_ScriptType::Basic},
-    {0x2f16a382, L"type",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Type, XFA_ScriptType::Basic},
-    {0xbc254332, L"usehref",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Usehref, XFA_ScriptType::Basic},
-
-    /* fill */
-    {0xc0811ed, L"use", (XFA_ATTRIBUTE_CALLBACK)&CJX_Fill::use,
-     XFA_Attribute::Use, XFA_ScriptType::Basic},
-    {0x570ce835, L"presence", (XFA_ATTRIBUTE_CALLBACK)&CJX_Fill::presence,
-     XFA_Attribute::Presence, XFA_ScriptType::Basic},
-    {0xbc254332, L"usehref", (XFA_ATTRIBUTE_CALLBACK)&CJX_Fill::usehref,
-     XFA_Attribute::Usehref, XFA_ScriptType::Basic},
-
-    /* font */
-    {0xcb0ac9, L"lineThrough", (XFA_ATTRIBUTE_CALLBACK)&CJX_Font::lineThrough,
-     XFA_Attribute::LineThrough, XFA_ScriptType::Basic},
-    {0x2c1c7f1, L"typeface", (XFA_ATTRIBUTE_CALLBACK)&CJX_Font::typeface,
-     XFA_Attribute::Typeface, XFA_ScriptType::Basic},
-    {0x8c74ae9, L"fontHorizontalScale",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Font::fontHorizontalScale,
-     XFA_Attribute::FontHorizontalScale, XFA_ScriptType::Basic},
-    {0xc0811ed, L"use", (XFA_ATTRIBUTE_CALLBACK)&CJX_Font::use,
-     XFA_Attribute::Use, XFA_ScriptType::Basic},
-    {0x2cd79033, L"kerningMode", (XFA_ATTRIBUTE_CALLBACK)&CJX_Font::kerningMode,
-     XFA_Attribute::KerningMode, XFA_ScriptType::Basic},
-    {0x3a0273a6, L"underline", (XFA_ATTRIBUTE_CALLBACK)&CJX_Font::underline,
-     XFA_Attribute::Underline, XFA_ScriptType::Basic},
-    {0x4873c601, L"baselineShift",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Font::baselineShift,
-     XFA_Attribute::BaselineShift, XFA_ScriptType::Basic},
-    {0x4b319767, L"overlinePeriod",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Font::overlinePeriod,
-     XFA_Attribute::OverlinePeriod, XFA_ScriptType::Basic},
-    {0x79543055, L"letterSpacing",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Font::letterSpacing,
-     XFA_Attribute::LetterSpacing, XFA_ScriptType::Basic},
-    {0x8ec6204c, L"lineThroughPeriod",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Font::lineThroughPeriod,
-     XFA_Attribute::LineThroughPeriod, XFA_ScriptType::Basic},
-    {0x907c7719, L"fontVerticalScale",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Font::fontVerticalScale,
-     XFA_Attribute::FontVerticalScale, XFA_ScriptType::Basic},
-    {0xa686975b, L"size", (XFA_ATTRIBUTE_CALLBACK)&CJX_Font::size,
-     XFA_Attribute::Size, XFA_ScriptType::Basic},
-    {0xb5e49bf2, L"posture", (XFA_ATTRIBUTE_CALLBACK)&CJX_Font::posture,
-     XFA_Attribute::Posture, XFA_ScriptType::Basic},
-    {0xbc254332, L"usehref", (XFA_ATTRIBUTE_CALLBACK)&CJX_Font::usehref,
-     XFA_Attribute::Usehref, XFA_ScriptType::Basic},
-    {0xbd6e1d88, L"weight", (XFA_ATTRIBUTE_CALLBACK)&CJX_Font::weight,
-     XFA_Attribute::Weight, XFA_ScriptType::Basic},
-    {0xbd96a0e9, L"underlinePeriod",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Font::underlinePeriod,
-     XFA_Attribute::UnderlinePeriod, XFA_ScriptType::Basic},
-    {0xc0ec9fa4, L"overline", (XFA_ATTRIBUTE_CALLBACK)&CJX_Font::overline,
-     XFA_Attribute::Overline, XFA_ScriptType::Basic},
-
-    /* form */
-    {0xaf754613, L"checksum",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Form_Checksum,
-     XFA_Attribute::Unknown, XFA_ScriptType::Basic},
-
-    /* mediumInfo */
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-
-    /* certificate */
-    {0xc0811ed, L"use", (XFA_ATTRIBUTE_CALLBACK)&CJX_Certificate::use,
-     XFA_Attribute::Use, XFA_ScriptType::Basic},
-    {0xbc254332, L"usehref", (XFA_ATTRIBUTE_CALLBACK)&CJX_Certificate::usehref,
-     XFA_Attribute::Usehref, XFA_ScriptType::Basic},
-
-    /* password */
-    {0xc0811ed, L"use", (XFA_ATTRIBUTE_CALLBACK)&CJX_Password::use,
-     XFA_Attribute::Use, XFA_ScriptType::Basic},
-    {0xbc254332, L"usehref", (XFA_ATTRIBUTE_CALLBACK)&CJX_Password::usehref,
-     XFA_Attribute::Usehref, XFA_ScriptType::Basic},
-
-    /* runScripts */
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-
-    /* trace */
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-
-    /* float */
-    {0xc0811ed, L"use", (XFA_ATTRIBUTE_CALLBACK)&CJX_Float::use,
-     XFA_Attribute::Use, XFA_ScriptType::Basic},
-    {0xa52682bd, L"{default}", (XFA_ATTRIBUTE_CALLBACK)&CJX_Float::defaultValue,
-     XFA_Attribute::Unknown, XFA_ScriptType::Basic},
-    {0xbc254332, L"usehref", (XFA_ATTRIBUTE_CALLBACK)&CJX_Float::usehref,
-     XFA_Attribute::Usehref, XFA_ScriptType::Basic},
-    {0xd6e27f1d, L"value", (XFA_ATTRIBUTE_CALLBACK)&CJX_Float::value,
-     XFA_Attribute::Unknown, XFA_ScriptType::Basic},
-
-    /* renderPolicy */
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-
-    /* logPseudoModel */
-
-    /* destination */
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-
-    /* value */
-    {0xc0811ed, L"use", (XFA_ATTRIBUTE_CALLBACK)&CJX_Value::use,
-     XFA_Attribute::Use, XFA_ScriptType::Basic},
-    {0x8e1c2921, L"relevant", (XFA_ATTRIBUTE_CALLBACK)&CJX_Value::relevant,
-     XFA_Attribute::Relevant, XFA_ScriptType::Basic},
-    {0xbc254332, L"usehref", (XFA_ATTRIBUTE_CALLBACK)&CJX_Value::usehref,
-     XFA_Attribute::Usehref, XFA_ScriptType::Basic},
-    {0xea7090a0, L"override", (XFA_ATTRIBUTE_CALLBACK)&CJX_Value::override,
-     XFA_Attribute::Override, XFA_ScriptType::Basic},
-
-    /* bookend */
-    {0xc0811ed, L"use", (XFA_ATTRIBUTE_CALLBACK)&CJX_Bookend::use,
-     XFA_Attribute::Use, XFA_ScriptType::Basic},
-    {0x9dcc3ab3, L"trailer", (XFA_ATTRIBUTE_CALLBACK)&CJX_Bookend::trailer,
-     XFA_Attribute::Trailer, XFA_ScriptType::Basic},
-    {0xbc254332, L"usehref", (XFA_ATTRIBUTE_CALLBACK)&CJX_Bookend::usehref,
-     XFA_Attribute::Usehref, XFA_ScriptType::Basic},
-    {0xcbcaf66d, L"leader", (XFA_ATTRIBUTE_CALLBACK)&CJX_Bookend::leader,
-     XFA_Attribute::Leader, XFA_ScriptType::Basic},
-
-    /* exObject */
-    {0xc0811ed, L"use", (XFA_ATTRIBUTE_CALLBACK)&CJX_ExObject::use,
-     XFA_Attribute::Use, XFA_ScriptType::Basic},
-    {0x60a61edd, L"codeType", (XFA_ATTRIBUTE_CALLBACK)&CJX_ExObject::codeType,
-     XFA_Attribute::CodeType, XFA_ScriptType::Basic},
-    {0xb373a862, L"archive", (XFA_ATTRIBUTE_CALLBACK)&CJX_ExObject::archive,
-     XFA_Attribute::Archive, XFA_ScriptType::Basic},
-    {0xbc254332, L"usehref", (XFA_ATTRIBUTE_CALLBACK)&CJX_ExObject::usehref,
-     XFA_Attribute::Usehref, XFA_ScriptType::Basic},
-    {0xe1a26b56, L"codeBase", (XFA_ATTRIBUTE_CALLBACK)&CJX_ExObject::codeBase,
-     XFA_Attribute::CodeBase, XFA_ScriptType::Basic},
-    {0xeb091003, L"classId", (XFA_ATTRIBUTE_CALLBACK)&CJX_ExObject::classId,
-     XFA_Attribute::ClassId, XFA_ScriptType::Basic},
-
-    /* openAction */
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-
-    /* neverEmbed */
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-
-    /* bindItems */
-    {0x47d03490, L"connection",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_BindItems::connection,
-     XFA_Attribute::Connection, XFA_ScriptType::Basic},
-    {0xc39a88bd, L"labelRef", (XFA_ATTRIBUTE_CALLBACK)&CJX_BindItems::labelRef,
-     XFA_Attribute::LabelRef, XFA_ScriptType::Basic},
-    {0xd50f903a, L"valueRef", (XFA_ATTRIBUTE_CALLBACK)&CJX_BindItems::valueRef,
-     XFA_Attribute::ValueRef, XFA_ScriptType::Basic},
-
-    /* calculate */
-    {0xc0811ed, L"use", (XFA_ATTRIBUTE_CALLBACK)&CJX_Calculate::use,
-     XFA_Attribute::Use, XFA_ScriptType::Basic},
-    {0xbc254332, L"usehref", (XFA_ATTRIBUTE_CALLBACK)&CJX_Calculate::usehref,
-     XFA_Attribute::Usehref, XFA_ScriptType::Basic},
-    {0xea7090a0, L"override", (XFA_ATTRIBUTE_CALLBACK)&CJX_Calculate::override,
-     XFA_Attribute::Override, XFA_ScriptType::Basic},
-
-    /* print */
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-
-    /* extras */
-    {0xc0811ed, L"use", (XFA_ATTRIBUTE_CALLBACK)&CJX_Extras::use,
-     XFA_Attribute::Use, XFA_ScriptType::Basic},
-    {0x2f16a382, L"type", (XFA_ATTRIBUTE_CALLBACK)&CJX_Extras::type,
-     XFA_Attribute::Unknown, XFA_ScriptType::Basic},
-    {0xbc254332, L"usehref", (XFA_ATTRIBUTE_CALLBACK)&CJX_Extras::usehref,
-     XFA_Attribute::Usehref, XFA_ScriptType::Basic},
-
-    /* proto */
-
-    /* dSigData */
-
-    /* creator */
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-
-    /* connect */
-    {0xbb8df5d, L"ref", (XFA_ATTRIBUTE_CALLBACK)&CJX_Connect::ref,
-     XFA_Attribute::Ref, XFA_ScriptType::Basic},
-    {0xc0811ed, L"use", (XFA_ATTRIBUTE_CALLBACK)&CJX_Connect::use,
-     XFA_Attribute::Use, XFA_ScriptType::Basic},
-    {0x24d85167, L"timeout", (XFA_ATTRIBUTE_CALLBACK)&CJX_Connect::timeout,
-     XFA_Attribute::Timeout, XFA_ScriptType::Basic},
-    {0x47d03490, L"connection",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Connect::connection,
-     XFA_Attribute::Connection, XFA_ScriptType::Basic},
-    {0x552d9ad5, L"usage", (XFA_ATTRIBUTE_CALLBACK)&CJX_Connect::usage,
-     XFA_Attribute::Usage, XFA_ScriptType::Basic},
-    {0xbc254332, L"usehref", (XFA_ATTRIBUTE_CALLBACK)&CJX_Connect::usehref,
-     XFA_Attribute::Usehref, XFA_ScriptType::Basic},
-    {0xc860f30a, L"delayedOpen",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Connect::delayedOpen,
-     XFA_Attribute::DelayedOpen, XFA_ScriptType::Basic},
-
-    /* permissions */
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-
-    /* connectionSet */
-
-    /* submit */
-    {0xc0811ed, L"use", (XFA_ATTRIBUTE_CALLBACK)&CJX_Submit::use,
-     XFA_Attribute::Use, XFA_ScriptType::Basic},
-    {0x28dee6e9, L"format", (XFA_ATTRIBUTE_CALLBACK)&CJX_Submit::format,
-     XFA_Attribute::Format, XFA_ScriptType::Basic},
-    {0x824f21b7, L"embedPDF", (XFA_ATTRIBUTE_CALLBACK)&CJX_Submit::embedPDF,
-     XFA_Attribute::EmbedPDF, XFA_ScriptType::Basic},
-    {0xbc254332, L"usehref", (XFA_ATTRIBUTE_CALLBACK)&CJX_Submit::usehref,
-     XFA_Attribute::Usehref, XFA_ScriptType::Basic},
-    {0xc8da4da7, L"target", (XFA_ATTRIBUTE_CALLBACK)&CJX_Submit::target,
-     XFA_Attribute::Target, XFA_ScriptType::Basic},
-    {0xdc75676c, L"textEncoding",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Submit::textEncoding,
-     XFA_Attribute::TextEncoding, XFA_ScriptType::Basic},
-    {0xf889e747, L"xdpContent", (XFA_ATTRIBUTE_CALLBACK)&CJX_Submit::xdpContent,
-     XFA_Attribute::XdpContent, XFA_ScriptType::Basic},
-
-    /* range */
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-
-    /* linearized */
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-
-    /* packet */
-    {0x97be91b, L"content", (XFA_ATTRIBUTE_CALLBACK)&CJX_Packet::content,
-     XFA_Attribute::Unknown, XFA_ScriptType::Basic},
-
-    /* rootElement */
-    {0xc0811ed, L"use", (XFA_ATTRIBUTE_CALLBACK)&CJX_RootElement::use,
-     XFA_Attribute::Use, XFA_ScriptType::Basic},
-    {0xbc254332, L"usehref", (XFA_ATTRIBUTE_CALLBACK)&CJX_RootElement::usehref,
-     XFA_Attribute::Usehref, XFA_ScriptType::Basic},
-
-    /* plaintextMetadata */
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-
-    /* numberSymbols */
-
-    /* printHighQuality */
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-
-    /* driver */
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-
-    /* incrementalLoad */
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-
-    /* subjectDN */
-    {0x4156ee3f, L"delimiter",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_SubjectDN::delimiter,
-     XFA_Attribute::Delimiter, XFA_ScriptType::Basic},
-
-    /* compressLogicalStructure */
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-
-    /* incrementalMerge */
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-
-    /* radial */
-    {0xc0811ed, L"use", (XFA_ATTRIBUTE_CALLBACK)&CJX_Radial::use,
-     XFA_Attribute::Use, XFA_ScriptType::Basic},
-    {0x2f16a382, L"type", (XFA_ATTRIBUTE_CALLBACK)&CJX_Radial::type,
-     XFA_Attribute::Type, XFA_ScriptType::Basic},
-    {0xbc254332, L"usehref", (XFA_ATTRIBUTE_CALLBACK)&CJX_Radial::usehref,
-     XFA_Attribute::Usehref, XFA_ScriptType::Basic},
-
-    /* variables */
-    {0xc0811ed, L"use", (XFA_ATTRIBUTE_CALLBACK)&CJX_Variables::use,
-     XFA_Attribute::Use, XFA_ScriptType::Basic},
-    {0xbc254332, L"usehref", (XFA_ATTRIBUTE_CALLBACK)&CJX_Variables::usehref,
-     XFA_Attribute::Usehref, XFA_ScriptType::Basic},
-
-    /* timePatterns */
-
-    /* effectiveInputPolicy */
-    {0x21aed, L"id",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Id, XFA_ScriptType::Basic},
-    {0x31b19c1, L"name",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Name, XFA_ScriptType::Basic},
-    {0xc0811ed, L"use",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Use, XFA_ScriptType::Basic},
-    {0xbc254332, L"usehref",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Usehref, XFA_ScriptType::Basic},
-
-    /* nameAttr */
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-
-    /* conformance */
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-
-    /* transform */
-    {0xbb8df5d, L"ref",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Ref, XFA_ScriptType::Basic},
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-
-    /* lockDocument */
-    {0x21aed, L"id",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Id, XFA_ScriptType::Basic},
-    {0xc0811ed, L"use",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Use, XFA_ScriptType::Basic},
-    {0x2f16a382, L"type",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Type, XFA_ScriptType::Basic},
-    {0xbc254332, L"usehref",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Usehref, XFA_ScriptType::Basic},
-
-    /* breakAfter */
-    {0xc0811ed, L"use", (XFA_ATTRIBUTE_CALLBACK)&CJX_BreakAfter::use,
-     XFA_Attribute::Use, XFA_ScriptType::Basic},
-    {0x453eaf38, L"startNew", (XFA_ATTRIBUTE_CALLBACK)&CJX_BreakAfter::startNew,
-     XFA_Attribute::StartNew, XFA_ScriptType::Basic},
-    {0x9dcc3ab3, L"trailer", (XFA_ATTRIBUTE_CALLBACK)&CJX_BreakAfter::trailer,
-     XFA_Attribute::Trailer, XFA_ScriptType::Basic},
-    {0xa6118c89, L"targetType",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_BreakAfter::targetType,
-     XFA_Attribute::TargetType, XFA_ScriptType::Basic},
-    {0xbc254332, L"usehref", (XFA_ATTRIBUTE_CALLBACK)&CJX_BreakAfter::usehref,
-     XFA_Attribute::Usehref, XFA_ScriptType::Basic},
-    {0xc8da4da7, L"target", (XFA_ATTRIBUTE_CALLBACK)&CJX_BreakAfter::target,
-     XFA_Attribute::Target, XFA_ScriptType::Basic},
-    {0xcbcaf66d, L"leader", (XFA_ATTRIBUTE_CALLBACK)&CJX_BreakAfter::leader,
-     XFA_Attribute::Leader, XFA_ScriptType::Basic},
-
-    /* line */
-    {0xc0811ed, L"use", (XFA_ATTRIBUTE_CALLBACK)&CJX_Line::use,
-     XFA_Attribute::Use, XFA_ScriptType::Basic},
-    {0xabef37e3, L"slope", (XFA_ATTRIBUTE_CALLBACK)&CJX_Line::slope,
-     XFA_Attribute::Slope, XFA_ScriptType::Basic},
-    {0xbc254332, L"usehref", (XFA_ATTRIBUTE_CALLBACK)&CJX_Line::usehref,
-     XFA_Attribute::Usehref, XFA_ScriptType::Basic},
-    {0xd996fa9b, L"hand", (XFA_ATTRIBUTE_CALLBACK)&CJX_Line::hand,
-     XFA_Attribute::Hand, XFA_ScriptType::Basic},
-
-    /* list */
-    {0xa60dd202, L"length", (XFA_ATTRIBUTE_CALLBACK)&CJX_List::length,
-     XFA_Attribute::Unknown, XFA_ScriptType::Basic},
-
-    /* source */
-    {0x20146, L"db", (XFA_ATTRIBUTE_CALLBACK)&CJX_Source::db,
-     XFA_Attribute::Unknown, XFA_ScriptType::Basic},
-    {0xc0811ed, L"use", (XFA_ATTRIBUTE_CALLBACK)&CJX_Source::use,
-     XFA_Attribute::Use, XFA_ScriptType::Basic},
-    {0xbc254332, L"usehref", (XFA_ATTRIBUTE_CALLBACK)&CJX_Source::usehref,
-     XFA_Attribute::Usehref, XFA_ScriptType::Basic},
-
-    /* occur */
-    {0xb3543a6, L"max", (XFA_ATTRIBUTE_CALLBACK)&CJX_Occur::max,
-     XFA_Attribute::Unknown, XFA_ScriptType::Basic},
-    {0xb356ca4, L"min", (XFA_ATTRIBUTE_CALLBACK)&CJX_Occur::min,
-     XFA_Attribute::Unknown, XFA_ScriptType::Basic},
-    {0xc0811ed, L"use", (XFA_ATTRIBUTE_CALLBACK)&CJX_Occur::use,
-     XFA_Attribute::Use, XFA_ScriptType::Basic},
-    {0x7d0b5fca, L"initial", (XFA_ATTRIBUTE_CALLBACK)&CJX_Occur::initial,
-     XFA_Attribute::Initial, XFA_ScriptType::Basic},
-    {0xbc254332, L"usehref", (XFA_ATTRIBUTE_CALLBACK)&CJX_Occur::usehref,
-     XFA_Attribute::Usehref, XFA_ScriptType::Basic},
-
-    /* pickTrayByPDFSize */
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-
-    /* monthNames */
-    {0x29418bb7, L"abbr",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Abbr, XFA_ScriptType::Basic},
-
-    /* severity */
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-
-    /* groupParent */
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-
-    /* documentAssembly */
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-
-    /* numberSymbol */
-    {0x31b19c1, L"name",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Name, XFA_ScriptType::Basic},
-
-    /* tagged */
-    {0xbe52dfbf, L"desc",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_String,
-     XFA_Attribute::Desc, XFA_ScriptType::Basic},
-    {0xf6b47749, L"lock",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Attribute_BOOL,
-     XFA_Attribute::Lock, XFA_ScriptType::Basic},
-
-    /* items */
-    {0xbb8df5d, L"ref", (XFA_ATTRIBUTE_CALLBACK)&CJX_Items::ref,
-     XFA_Attribute::Ref, XFA_ScriptType::Basic},
-    {0xc0811ed, L"use", (XFA_ATTRIBUTE_CALLBACK)&CJX_Items::use,
-     XFA_Attribute::Use, XFA_ScriptType::Basic},
-    {0x570ce835, L"presence", (XFA_ATTRIBUTE_CALLBACK)&CJX_Items::presence,
-     XFA_Attribute::Presence, XFA_ScriptType::Basic},
-    {0xa5b410cf, L"save", (XFA_ATTRIBUTE_CALLBACK)&CJX_Items::save,
-     XFA_Attribute::Save, XFA_ScriptType::Basic},
-    {0xbc254332, L"usehref", (XFA_ATTRIBUTE_CALLBACK)&CJX_Items::usehref,
-     XFA_Attribute::Usehref, XFA_ScriptType::Basic},
-
-    /* object */
-    {0xb2c80857, L"className", (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::className,
-     XFA_Attribute::Unknown, XFA_ScriptType::Basic},
-
-    /* list */
-    {0xa60dd202, L"length", (XFA_ATTRIBUTE_CALLBACK)&CJX_List::length,
-     XFA_Attribute::Unknown, XFA_ScriptType::Basic},
-
-    /* [unknown] */
-
-    /* tree */
-    {0x31b19c1, L"name", (XFA_ATTRIBUTE_CALLBACK)&CJX_Tree::name,
-     XFA_Attribute::Name, XFA_ScriptType::Basic},
-    {0x9f9d0f9, L"all", (XFA_ATTRIBUTE_CALLBACK)&CJX_Tree::all,
-     XFA_Attribute::Unknown, XFA_ScriptType::Object},
-    {0x4df15659, L"nodes", (XFA_ATTRIBUTE_CALLBACK)&CJX_Tree::nodes,
-     XFA_Attribute::Unknown, XFA_ScriptType::Object},
-    {0x78a8d6cf, L"classAll", (XFA_ATTRIBUTE_CALLBACK)&CJX_Tree::classAll,
-     XFA_Attribute::Unknown, XFA_ScriptType::Object},
-    {0xcad6d8ca, L"parent", (XFA_ATTRIBUTE_CALLBACK)&CJX_Tree::parent,
-     XFA_Attribute::Unknown, XFA_ScriptType::Object},
-    {0xd5679c78, L"index", (XFA_ATTRIBUTE_CALLBACK)&CJX_Tree::index,
-     XFA_Attribute::Unknown, XFA_ScriptType::Basic},
-    {0xdb5b4bce, L"classIndex", (XFA_ATTRIBUTE_CALLBACK)&CJX_Tree::classIndex,
-     XFA_Attribute::Unknown, XFA_ScriptType::Basic},
-    {0xe4989adf, L"somExpression",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Tree::somExpression, XFA_Attribute::Unknown,
-     XFA_ScriptType::Basic},
-
-    /* node */
-    {0x21aed, L"id", (XFA_ATTRIBUTE_CALLBACK)&CJX_Node::id, XFA_Attribute::Id,
-     XFA_ScriptType::Basic},
-    {0x234a1, L"ns", (XFA_ATTRIBUTE_CALLBACK)&CJX_Node::ns,
-     XFA_Attribute::Unknown, XFA_ScriptType::Basic},
-    {0x50d1a9d1, L"model", (XFA_ATTRIBUTE_CALLBACK)&CJX_Node::model,
-     XFA_Attribute::Unknown, XFA_ScriptType::Object},
-    {0xacb4823f, L"isContainer", (XFA_ATTRIBUTE_CALLBACK)&CJX_Node::isContainer,
-     XFA_Attribute::Unknown, XFA_ScriptType::Basic},
-    {0xe372ae97, L"isNull", (XFA_ATTRIBUTE_CALLBACK)&CJX_Node::isNull,
-     XFA_Attribute::Unknown, XFA_ScriptType::Basic},
-    {0xfe612a5b, L"oneOfChild", (XFA_ATTRIBUTE_CALLBACK)&CJX_Node::oneOfChild,
-     XFA_Attribute::Unknown, XFA_ScriptType::Object},
-
-    /* [unknown] */
-
-    /* [unknown] */
-
-    /* model */
-    {0x97c1c65, L"context", (XFA_ATTRIBUTE_CALLBACK)&CJX_Model::context,
-     XFA_Attribute::Unknown, XFA_ScriptType::Object},
-    {0x58be2870, L"aliasNode", (XFA_ATTRIBUTE_CALLBACK)&CJX_Model::aliasNode,
-     XFA_Attribute::Unknown, XFA_ScriptType::Object},
-
-    /* [unknown] */
-    {0xa52682bd, L"{default}",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Som_DefaultValue,
-     XFA_Attribute::Unknown, XFA_ScriptType::Basic},
-    {0xd6e27f1d, L"value",
-     (XFA_ATTRIBUTE_CALLBACK)&CJX_Object::Script_Som_DefaultValue,
-     XFA_Attribute::Unknown, XFA_ScriptType::Basic},
-};
-const int32_t g_iSomAttributeCount = FX_ArraySize(g_SomAttributeData);
diff --git a/xfa/fxfa/parser/xfa_basic_data_enum.cpp b/xfa/fxfa/parser/xfa_basic_data_enum.cpp
deleted file mode 100644
index 33c5cf4..0000000
--- a/xfa/fxfa/parser/xfa_basic_data_enum.cpp
+++ /dev/null
@@ -1,281 +0,0 @@
-// Copyright 2016 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
-
-#include "xfa/fxfa/parser/xfa_basic_data.h"
-
-#include "xfa/fxfa/fxfa_basic.h"
-
-const XFA_AttributeEnumInfo g_XFAEnumData[] = {
-    {0x2a, L"*", XFA_AttributeEnum::Asterisk},
-    {0x2f, L"/", XFA_AttributeEnum::Slash},
-    {0x5c, L"\\", XFA_AttributeEnum::Backslash},
-    {0x239bd, L"on", XFA_AttributeEnum::On},
-    {0x25356, L"tb", XFA_AttributeEnum::Tb},
-    {0x25885, L"up", XFA_AttributeEnum::Up},
-    {0x91b281, L"metaData", XFA_AttributeEnum::MetaData},
-    {0x1f8dedb, L"delegate", XFA_AttributeEnum::Delegate},
-    {0x2a6c55a, L"postSubmit", XFA_AttributeEnum::PostSubmit},
-    {0x31b19c1, L"name", XFA_AttributeEnum::Name},
-    {0x378a38a, L"cross", XFA_AttributeEnum::Cross},
-    {0x3848b3f, L"next", XFA_AttributeEnum::Next},
-    {0x48b6670, L"none", XFA_AttributeEnum::None},
-    {0x51aafe5, L"shortEdge", XFA_AttributeEnum::ShortEdge},
-    {0x55264c4, L"1mod10_1mod11", XFA_AttributeEnum::Checksum_1mod10_1mod11},
-    {0x5a5c519, L"height", XFA_AttributeEnum::Height},
-    {0x89ce549, L"crossDiagonal", XFA_AttributeEnum::CrossDiagonal},
-    {0x9f9d0f9, L"all", XFA_AttributeEnum::All},
-    {0x9f9db48, L"any", XFA_AttributeEnum::Any},
-    {0xa126261, L"toRight", XFA_AttributeEnum::ToRight},
-    {0xa36de29, L"matchTemplate", XFA_AttributeEnum::MatchTemplate},
-    {0xa48d040, L"dpl", XFA_AttributeEnum::Dpl},
-    {0xa559c05, L"invisible", XFA_AttributeEnum::Invisible},
-    {0xa7d48e3, L"fit", XFA_AttributeEnum::Fit},
-    {0xa8a8f80, L"width", XFA_AttributeEnum::Width},
-    {0xab466bb, L"preSubmit", XFA_AttributeEnum::PreSubmit},
-    {0xacc5785, L"ipl", XFA_AttributeEnum::Ipl},
-    {0xafab0f8, L"flateCompress", XFA_AttributeEnum::FlateCompress},
-    {0xb355816, L"med", XFA_AttributeEnum::Med},
-    {0xb69ef77, L"odd", XFA_AttributeEnum::Odd},
-    {0xb69f9bb, L"off", XFA_AttributeEnum::Off},
-    {0xb843dba, L"pdf", XFA_AttributeEnum::Pdf},
-    {0xbb912b8, L"row", XFA_AttributeEnum::Row},
-    {0xbedaf33, L"top", XFA_AttributeEnum::Top},
-    {0xc56afcc, L"xdp", XFA_AttributeEnum::Xdp},
-    {0xc56ba02, L"xfd", XFA_AttributeEnum::Xfd},
-    {0xc56ddf1, L"xml", XFA_AttributeEnum::Xml},
-    {0xc8b65f3, L"zip", XFA_AttributeEnum::Zip},
-    {0xc8b89d6, L"zpl", XFA_AttributeEnum::Zpl},
-    {0xf55d7ee, L"visible", XFA_AttributeEnum::Visible},
-    {0xfe3596a, L"exclude", XFA_AttributeEnum::Exclude},
-    {0x109d7ce7, L"mouseEnter", XFA_AttributeEnum::MouseEnter},
-    {0x10f1bc0c, L"pair", XFA_AttributeEnum::Pair},
-    {0x1154efe6, L"filter", XFA_AttributeEnum::Filter},
-    {0x125bc94b, L"moveLast", XFA_AttributeEnum::MoveLast},
-    {0x12e1f1f0, L"exportAndImport", XFA_AttributeEnum::ExportAndImport},
-    {0x13000c60, L"push", XFA_AttributeEnum::Push},
-    {0x138ee315, L"portrait", XFA_AttributeEnum::Portrait},
-    {0x14da2125, L"default", XFA_AttributeEnum::Default},
-    {0x157749a5, L"storedProc", XFA_AttributeEnum::StoredProc},
-    {0x16641198, L"stayBOF", XFA_AttributeEnum::StayBOF},
-    {0x16b2fc5b, L"stayEOF", XFA_AttributeEnum::StayEOF},
-    {0x17fad373, L"postPrint", XFA_AttributeEnum::PostPrint},
-    {0x193207d0, L"usCarrier", XFA_AttributeEnum::UsCarrier},
-    {0x193ade3e, L"right", XFA_AttributeEnum::Right},
-    {0x1bfc72d9, L"preOpen", XFA_AttributeEnum::PreOpen},
-    {0x1cc9317a, L"actual", XFA_AttributeEnum::Actual},
-    {0x1f31df1e, L"rest", XFA_AttributeEnum::Rest},
-    {0x1fb1bf14, L"topCenter", XFA_AttributeEnum::TopCenter},
-    {0x207de667, L"standardSymbol", XFA_AttributeEnum::StandardSymbol},
-    {0x2196a452, L"initialize", XFA_AttributeEnum::Initialize},
-    {0x23bd40c7, L"justifyAll", XFA_AttributeEnum::JustifyAll},
-    {0x247cf3e9, L"normal", XFA_AttributeEnum::Normal},
-    {0x25aa946b, L"landscape", XFA_AttributeEnum::Landscape},
-    {0x2739b5c9, L"nonInteractive", XFA_AttributeEnum::NonInteractive},
-    {0x27410f03, L"mouseExit", XFA_AttributeEnum::MouseExit},
-    {0x2854e62c, L"minus", XFA_AttributeEnum::Minus},
-    {0x287e936a, L"diagonalLeft", XFA_AttributeEnum::DiagonalLeft},
-    {0x2972a98f, L"simplexPaginated", XFA_AttributeEnum::SimplexPaginated},
-    {0x29d8225f, L"document", XFA_AttributeEnum::Document},
-    {0x2a9d3016, L"warning", XFA_AttributeEnum::Warning},
-    {0x2b35b6d9, L"auto", XFA_AttributeEnum::Auto},
-    {0x2c1653d9, L"below", XFA_AttributeEnum::Below},
-    {0x2c1f0540, L"bottomLeft", XFA_AttributeEnum::BottomLeft},
-    {0x2c44e816, L"bottomCenter", XFA_AttributeEnum::BottomCenter},
-    {0x2cd3e9f3, L"tcpl", XFA_AttributeEnum::Tcpl},
-    {0x2d08af85, L"text", XFA_AttributeEnum::Text},
-    {0x2dc478eb, L"grouping", XFA_AttributeEnum::Grouping},
-    {0x2ef3afdd, L"secureSymbol", XFA_AttributeEnum::SecureSymbol},
-    {0x2f2dd29a, L"preExecute", XFA_AttributeEnum::PreExecute},
-    {0x33c43dec, L"docClose", XFA_AttributeEnum::DocClose},
-    {0x33f25bb5, L"keyset", XFA_AttributeEnum::Keyset},
-    {0x34e363da, L"vertical", XFA_AttributeEnum::Vertical},
-    {0x361fa1b6, L"preSave", XFA_AttributeEnum::PreSave},
-    {0x36f1c6d8, L"preSign", XFA_AttributeEnum::PreSign},
-    {0x399f02b5, L"bottom", XFA_AttributeEnum::Bottom},
-    {0x3b0ab096, L"toTop", XFA_AttributeEnum::ToTop},
-    {0x3c752495, L"verify", XFA_AttributeEnum::Verify},
-    {0x3ce05d68, L"first", XFA_AttributeEnum::First},
-    {0x3ecead94, L"contentArea", XFA_AttributeEnum::ContentArea},
-    {0x40623b5b, L"solid", XFA_AttributeEnum::Solid},
-    {0x42c6cd8d, L"pessimistic", XFA_AttributeEnum::Pessimistic},
-    {0x43ddc6bf, L"duplexPaginated", XFA_AttributeEnum::DuplexPaginated},
-    {0x442f68c8, L"round", XFA_AttributeEnum::Round},
-    {0x45efb847, L"remerge", XFA_AttributeEnum::Remerge},
-    {0x46972265, L"ordered", XFA_AttributeEnum::Ordered},
-    {0x46f95531, L"percent", XFA_AttributeEnum::Percent},
-    {0x46fd25ae, L"even", XFA_AttributeEnum::Even},
-    {0x4731d6ba, L"exit", XFA_AttributeEnum::Exit},
-    {0x4977356b, L"toolTip", XFA_AttributeEnum::ToolTip},
-    {0x49b980ee, L"orderedOccurrence", XFA_AttributeEnum::OrderedOccurrence},
-    {0x4a7e2dfe, L"readOnly", XFA_AttributeEnum::ReadOnly},
-    {0x4c4e8acb, L"currency", XFA_AttributeEnum::Currency},
-    {0x4dcf25f8, L"concat", XFA_AttributeEnum::Concat},
-    {0x4febb826, L"Thai", XFA_AttributeEnum::Thai},
-    {0x50ef95b2, L"embossed", XFA_AttributeEnum::Embossed},
-    {0x516e35ce, L"formdata", XFA_AttributeEnum::Formdata},
-    {0x52fa6f0e, L"Greek", XFA_AttributeEnum::Greek},
-    {0x54034c2f, L"decimal", XFA_AttributeEnum::Decimal},
-    {0x542c7300, L"select", XFA_AttributeEnum::Select},
-    {0x551f0ae5, L"longEdge", XFA_AttributeEnum::LongEdge},
-    {0x55520a8a, L"protected", XFA_AttributeEnum::Protected},
-    {0x559f76f3, L"bottomRight", XFA_AttributeEnum::BottomRight},
-    {0x568cb500, L"zero", XFA_AttributeEnum::Zero},
-    {0x56bcecb7, L"forwardOnly", XFA_AttributeEnum::ForwardOnly},
-    {0x56bf456b, L"docReady", XFA_AttributeEnum::DocReady},
-    {0x573cb40c, L"hidden", XFA_AttributeEnum::Hidden},
-    {0x582e3424, L"include", XFA_AttributeEnum::Include},
-    {0x58a3dd29, L"dashed", XFA_AttributeEnum::Dashed},
-    {0x5955b22b, L"multiSelect", XFA_AttributeEnum::MultiSelect},
-    {0x598d5c53, L"inactive", XFA_AttributeEnum::Inactive},
-    {0x59c8f27d, L"embed", XFA_AttributeEnum::Embed},
-    {0x5e7555e8, L"static", XFA_AttributeEnum::Static},
-    {0x606d4def, L"onEntry", XFA_AttributeEnum::OnEntry},
-    {0x6195eafb, L"Cyrillic", XFA_AttributeEnum::Cyrillic},
-    {0x6491b0f3, L"nonBlank", XFA_AttributeEnum::NonBlank},
-    {0x67bef031, L"topRight", XFA_AttributeEnum::TopRight},
-    {0x67df5ebd, L"Hebrew", XFA_AttributeEnum::Hebrew},
-    {0x6aea98be, L"topLeft", XFA_AttributeEnum::TopLeft},
-    {0x6c51afc1, L"center", XFA_AttributeEnum::Center},
-    {0x7145e6bf, L"moveFirst", XFA_AttributeEnum::MoveFirst},
-    {0x7375465c, L"diamond", XFA_AttributeEnum::Diamond},
-    {0x7461aef4, L"pageOdd", XFA_AttributeEnum::PageOdd},
-    {0x75f8aeb2, L"1mod10", XFA_AttributeEnum::Checksum_1mod10},
-    {0x76d708e0, L"Korean", XFA_AttributeEnum::Korean},
-    {0x789f14d7, L"aboveEmbedded", XFA_AttributeEnum::AboveEmbedded},
-    {0x792ea39f, L"zipCompress", XFA_AttributeEnum::ZipCompress},
-    {0x7a5b7193, L"numeric", XFA_AttributeEnum::Numeric},
-    {0x7abec0d2, L"circle", XFA_AttributeEnum::Circle},
-    {0x7afbba38, L"toBottom", XFA_AttributeEnum::ToBottom},
-    {0x7b95e661, L"inverted", XFA_AttributeEnum::Inverted},
-    {0x7baca2e3, L"update", XFA_AttributeEnum::Update},
-    {0x7eb5da2c, L"isoname", XFA_AttributeEnum::Isoname},
-    {0x7f6fd3d7, L"server", XFA_AttributeEnum::Server},
-    {0x814f82b5, L"position", XFA_AttributeEnum::Position},
-    {0x82deacf0, L"middleCenter", XFA_AttributeEnum::MiddleCenter},
-    {0x83a49dc6, L"optional", XFA_AttributeEnum::Optional},
-    {0x861a116f, L"usePrinterSetting", XFA_AttributeEnum::UsePrinterSetting},
-    {0x86701ce0, L"outline", XFA_AttributeEnum::Outline},
-    {0x8808385e, L"indexChange", XFA_AttributeEnum::IndexChange},
-    {0x891f4606, L"change", XFA_AttributeEnum::Change},
-    {0x89939f36, L"pageArea", XFA_AttributeEnum::PageArea},
-    {0x8b5c3b25, L"once", XFA_AttributeEnum::Once},
-    {0x8b5c6962, L"only", XFA_AttributeEnum::Only},
-    {0x8b90e1f2, L"open", XFA_AttributeEnum::Open},
-    {0x8bcfe96e, L"caption", XFA_AttributeEnum::Caption},
-    {0x8ce83ef8, L"raised", XFA_AttributeEnum::Raised},
-    {0x8d269cae, L"justify", XFA_AttributeEnum::Justify},
-    {0x8fd520dc, L"refAndDescendants", XFA_AttributeEnum::RefAndDescendants},
-    {0x9041d4b0, L"short", XFA_AttributeEnum::Short},
-    {0x90c94426, L"pageFront", XFA_AttributeEnum::PageFront},
-    {0x936beee5, L"monospace", XFA_AttributeEnum::Monospace},
-    {0x947fa00f, L"middle", XFA_AttributeEnum::Middle},
-    {0x9528a7b4, L"prePrint", XFA_AttributeEnum::PrePrint},
-    {0x959ab231, L"always", XFA_AttributeEnum::Always},
-    {0x96d61bf0, L"unknown", XFA_AttributeEnum::Unknown},
-    {0x997194ee, L"toLeft", XFA_AttributeEnum::ToLeft},
-    {0x9a83a3cd, L"above", XFA_AttributeEnum::Above},
-    {0x9d0d71c7, L"dashDot", XFA_AttributeEnum::DashDot},
-    {0x9df56f3e, L"gregorian", XFA_AttributeEnum::Gregorian},
-    {0x9f6723fd, L"Roman", XFA_AttributeEnum::Roman},
-    {0x9f693b21, L"mouseDown", XFA_AttributeEnum::MouseDown},
-    {0xa1429b36, L"symbol", XFA_AttributeEnum::Symbol},
-    {0xa5aa45cb, L"pageEven", XFA_AttributeEnum::PageEven},
-    {0xa68635f1, L"sign", XFA_AttributeEnum::Sign},
-    {0xa7315093, L"addNew", XFA_AttributeEnum::AddNew},
-    {0xa7a773fa, L"star", XFA_AttributeEnum::Star},
-    {0xa7d57b45, L"optimistic", XFA_AttributeEnum::Optimistic},
-    {0xa8077321, L"rl-tb", XFA_AttributeEnum::Rl_tb},
-    {0xa8f1468d, L"middleRight", XFA_AttributeEnum::MiddleRight},
-    {0xaa84a1f1, L"maintain", XFA_AttributeEnum::Maintain},
-    {0xab40b12c, L"package", XFA_AttributeEnum::Package},
-    {0xac8b4d85, L"SimplifiedChinese", XFA_AttributeEnum::SimplifiedChinese},
-    {0xadae6744, L"toCenter", XFA_AttributeEnum::ToCenter},
-    {0xb0129df1, L"back", XFA_AttributeEnum::Back},
-    {0xb0f088cf, L"unspecified", XFA_AttributeEnum::Unspecified},
-    {0xb1271067, L"batchOptimistic", XFA_AttributeEnum::BatchOptimistic},
-    {0xb18313a1, L"bold", XFA_AttributeEnum::Bold},
-    {0xb1833cad, L"both", XFA_AttributeEnum::Both},
-    {0xb221123f, L"butt", XFA_AttributeEnum::Butt},
-    {0xb40c36bf, L"client", XFA_AttributeEnum::Client},
-    {0xb56c7053, L"2mod10", XFA_AttributeEnum::Checksum_2mod10},
-    {0xb683a345, L"imageOnly", XFA_AttributeEnum::ImageOnly},
-    {0xb7732dea, L"horizontal", XFA_AttributeEnum::Horizontal},
-    {0xb88652a4, L"dotted", XFA_AttributeEnum::Dotted},
-    {0xbb2f2880, L"userControl", XFA_AttributeEnum::UserControl},
-    {0xbbb79c5d, L"diagonalRight", XFA_AttributeEnum::DiagonalRight},
-    {0xbd077154, L"consumeData", XFA_AttributeEnum::ConsumeData},
-    {0xbd3fb11e, L"check", XFA_AttributeEnum::Check},
-    {0xbde9abda, L"data", XFA_AttributeEnum::Data},
-    {0xbf5a02d8, L"down", XFA_AttributeEnum::Down},
-    {0xbf7450ee, L"sansSerif", XFA_AttributeEnum::SansSerif},
-    {0xc02d649f, L"inline", XFA_AttributeEnum::Inline},
-    {0xc11a9e3a, L"TraditionalChinese", XFA_AttributeEnum::TraditionalChinese},
-    {0xc16169d8, L"warn", XFA_AttributeEnum::Warn},
-    {0xc16f071f, L"refOnly", XFA_AttributeEnum::RefOnly},
-    {0xc27c8ba5, L"interactiveForms", XFA_AttributeEnum::InteractiveForms},
-    {0xc2d1b15c, L"word", XFA_AttributeEnum::Word},
-    {0xc3621288, L"unordered", XFA_AttributeEnum::Unordered},
-    {0xc5251981, L"required", XFA_AttributeEnum::Required},
-    {0xc7088e7d, L"importOnly", XFA_AttributeEnum::ImportOnly},
-    {0xc72cf0e3, L"belowEmbedded", XFA_AttributeEnum::BelowEmbedded},
-    {0xc819cf07, L"Japanese", XFA_AttributeEnum::Japanese},
-    {0xcdce56b3, L"full", XFA_AttributeEnum::Full},
-    {0xce0122e3, L"rl-row", XFA_AttributeEnum::Rl_row},
-    {0xcf7d71f1, L"Vietnamese", XFA_AttributeEnum::Vietnamese},
-    {0xcfde3e09, L"EastEuropeanRoman", XFA_AttributeEnum::EastEuropeanRoman},
-    {0xd576d08e, L"mouseUp", XFA_AttributeEnum::MouseUp},
-    {0xd7a92904, L"exportOnly", XFA_AttributeEnum::ExportOnly},
-    {0xd8ed1467, L"clear", XFA_AttributeEnum::Clear},
-    {0xd95657a6, L"click", XFA_AttributeEnum::Click},
-    {0xd96c7de5, L"base64", XFA_AttributeEnum::Base64},
-    {0xd9f47f36, L"close", XFA_AttributeEnum::Close},
-    {0xdb075bde, L"host", XFA_AttributeEnum::Host},
-    {0xdb103411, L"global", XFA_AttributeEnum::Global},
-    {0xdb647188, L"blank", XFA_AttributeEnum::Blank},
-    {0xdb9be968, L"table", XFA_AttributeEnum::Table},
-    {0xdf590fbb, L"import", XFA_AttributeEnum::Import},
-    {0xe0e573fb, L"custom", XFA_AttributeEnum::Custom},
-    {0xe0ecc79a, L"middleLeft", XFA_AttributeEnum::MiddleLeft},
-    {0xe1452019, L"postExecute", XFA_AttributeEnum::PostExecute},
-    {0xe1911d98, L"radix", XFA_AttributeEnum::Radix},
-    {0xe25fa7b8, L"postOpen", XFA_AttributeEnum::PostOpen},
-    {0xe28dce7e, L"enter", XFA_AttributeEnum::Enter},
-    {0xe2c44de4, L"ignore", XFA_AttributeEnum::Ignore},
-    {0xe2cd8c61, L"lr-tb", XFA_AttributeEnum::Lr_tb},
-    {0xe2da8336, L"fantasy", XFA_AttributeEnum::Fantasy},
-    {0xe31d5396, L"italic", XFA_AttributeEnum::Italic},
-    {0xe7ada113, L"author", XFA_AttributeEnum::Author},
-    {0xe8e7cc18, L"toEdge", XFA_AttributeEnum::ToEdge},
-    {0xe97aa98b, L"choice", XFA_AttributeEnum::Choice},
-    {0xeafd2a38, L"disabled", XFA_AttributeEnum::Disabled},
-    {0xeb2b7972, L"crossHatch", XFA_AttributeEnum::CrossHatch},
-    {0xeb2db2d7, L"dataRef", XFA_AttributeEnum::DataRef},
-    {0xec35dc6e, L"dashDotDot", XFA_AttributeEnum::DashDotDot},
-    {0xef85d351, L"square", XFA_AttributeEnum::Square},
-    {0xf2102445, L"dynamic", XFA_AttributeEnum::Dynamic},
-    {0xf272c7be, L"manual", XFA_AttributeEnum::Manual},
-    {0xf2bbb64d, L"etched", XFA_AttributeEnum::Etched},
-    {0xf3b8fc6c, L"validationState", XFA_AttributeEnum::ValidationState},
-    {0xf42f2b81, L"cursive", XFA_AttributeEnum::Cursive},
-    {0xf54481d4, L"last", XFA_AttributeEnum::Last},
-    {0xf5ad782b, L"left", XFA_AttributeEnum::Left},
-    {0xf616da2e, L"link", XFA_AttributeEnum::Link},
-    {0xf6b4afb0, L"long", XFA_AttributeEnum::Long},
-    {0xf8636460, L"internationalCarrier",
-     XFA_AttributeEnum::InternationalCarrier},
-    {0xf9fb37ac, L"PDF1.3", XFA_AttributeEnum::PDF1_3},
-    {0xf9fb37af, L"PDF1.6", XFA_AttributeEnum::PDF1_6},
-    {0xfbce7f19, L"serif", XFA_AttributeEnum::Serif},
-    {0xfc82d695, L"postSave", XFA_AttributeEnum::PostSave},
-    {0xfcef86b5, L"ready", XFA_AttributeEnum::Ready},
-    {0xfd54fbb7, L"postSign", XFA_AttributeEnum::PostSign},
-    {0xfdc0aae2, L"Arabic", XFA_AttributeEnum::Arabic},
-    {0xfe06d2ca, L"error", XFA_AttributeEnum::Error},
-    {0xfefc4885, L"urlencoded", XFA_AttributeEnum::Urlencoded},
-    {0xff795ad2, L"lowered", XFA_AttributeEnum::Lowered},
-};
-const int32_t g_iXFAEnumCount =
-    sizeof(g_XFAEnumData) / sizeof(XFA_AttributeEnumInfo);
diff --git a/xfa/fxfa/parser/xfa_basic_data_unittest.cpp b/xfa/fxfa/parser/xfa_basic_data_unittest.cpp
new file mode 100644
index 0000000..b9307d5
--- /dev/null
+++ b/xfa/fxfa/parser/xfa_basic_data_unittest.cpp
@@ -0,0 +1,101 @@
+// Copyright 2018 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/xfa_basic_data.h"
+
+#include <utility>
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+TEST(XFABasicDataTest, GetPacketByName) {
+  Optional<XFA_PACKETINFO> result = XFA_GetPacketByName(L"");
+  EXPECT_FALSE(result.has_value());
+
+  result = XFA_GetPacketByName(L"nonesuch");
+  EXPECT_FALSE(result.has_value());
+
+  result = XFA_GetPacketByName(L"datasets");
+  ASSERT_TRUE(result.has_value());
+  EXPECT_EQ(XFA_PacketType::Datasets, result.value().packet_type);
+
+  result = XFA_GetPacketByName(L"sourceSet");
+  ASSERT_TRUE(result.has_value());
+  EXPECT_EQ(XFA_PacketType::SourceSet, result.value().packet_type);
+}
+
+TEST(XFABasicDataTest, PacketToName) {
+  XFA_PACKETINFO result = XFA_GetPacketByIndex(XFA_PacketType::Datasets);
+  EXPECT_STREQ(L"datasets", result.name);
+
+  result = XFA_GetPacketByIndex(XFA_PacketType::ConnectionSet);
+  EXPECT_STREQ(L"connectionSet", result.name);
+}
+
+TEST(XFABasicDataTest, GetElementByName) {
+  EXPECT_EQ(XFA_Element::Unknown, XFA_GetElementByName(L""));
+  EXPECT_EQ(XFA_Element::Unknown, XFA_GetElementByName(L"nonesuch"));
+  EXPECT_EQ(XFA_Element::ConnectionSet, XFA_GetElementByName(L"connectionSet"));
+  EXPECT_EQ(XFA_Element::Items, XFA_GetElementByName(L"items"));
+
+  // Internal elements are not retrievable by name.
+  EXPECT_EQ(XFA_Element::Unknown, XFA_GetElementByName(L"model"));
+}
+
+TEST(XFABasicDataTest, ElementToName) {
+  EXPECT_EQ("conformance", XFA_ElementToName(XFA_Element::Conformance));
+  EXPECT_EQ("tagged", XFA_ElementToName(XFA_Element::Tagged));
+
+  // Internal elements resolve back to real names.
+  EXPECT_EQ("node", XFA_ElementToName(XFA_Element::Node));
+}
+
+TEST(XFABasicDataTest, GetAttributeByName) {
+  Optional<XFA_ATTRIBUTEINFO> result = XFA_GetAttributeByName(L"");
+  EXPECT_FALSE(result.has_value());
+
+  result = XFA_GetAttributeByName(L"nonesuch");
+  EXPECT_FALSE(result.has_value());
+
+  result = XFA_GetAttributeByName(L"h");
+  ASSERT_TRUE(result.has_value());
+  EXPECT_EQ(XFA_Attribute::H, result.value().attribute);
+
+  result = XFA_GetAttributeByName(L"short");
+  ASSERT_TRUE(result.has_value());
+  EXPECT_EQ(XFA_Attribute::Short, result.value().attribute);
+
+  result = XFA_GetAttributeByName(L"decipherOnly");
+  ASSERT_TRUE(result.has_value());
+  EXPECT_EQ(XFA_Attribute::DecipherOnly, result.value().attribute);
+}
+
+TEST(XFABasicDataTest, AttributeToName) {
+  EXPECT_EQ("spaceBelow", XFA_AttributeToName(XFA_Attribute::SpaceBelow));
+  EXPECT_EQ("decipherOnly", XFA_AttributeToName(XFA_Attribute::DecipherOnly));
+}
+
+TEST(XFABasicDataTest, GetAttributeValueByName) {
+  Optional<XFA_AttributeValue> result = XFA_GetAttributeValueByName(L"");
+  EXPECT_FALSE(result.has_value());
+
+  result = XFA_GetAttributeValueByName(L"nonesuch");
+  EXPECT_FALSE(result.has_value());
+
+  result = XFA_GetAttributeValueByName(L"*");
+  ASSERT_TRUE(result.has_value());
+  EXPECT_EQ(XFA_AttributeValue::Asterisk, result.value());
+
+  result = XFA_GetAttributeValueByName(L"visible");
+  ASSERT_TRUE(result.has_value());
+  EXPECT_EQ(XFA_AttributeValue::Visible, result.value());
+
+  result = XFA_GetAttributeValueByName(L"lowered");
+  ASSERT_TRUE(result.has_value());
+  EXPECT_EQ(XFA_AttributeValue::Lowered, result.value());
+}
+
+TEST(XFABasicDataTest, AttributeValueToName) {
+  EXPECT_EQ("rl-tb", XFA_AttributeValueToName(XFA_AttributeValue::Rl_tb));
+  EXPECT_EQ("lowered", XFA_AttributeValueToName(XFA_AttributeValue::Lowered));
+}
diff --git a/xfa/fxfa/parser/xfa_document_datamerger_imp.cpp b/xfa/fxfa/parser/xfa_document_datamerger_imp.cpp
index f6f165f..dfd8cf0 100644
--- a/xfa/fxfa/parser/xfa_document_datamerger_imp.cpp
+++ b/xfa/fxfa/parser/xfa_document_datamerger_imp.cpp
@@ -6,502 +6,11 @@
 
 #include "xfa/fxfa/parser/xfa_document_datamerger_imp.h"
 
-#include <map>
-#include <vector>
-
-#include "core/fxcrt/fx_extension.h"
-#include "core/fxcrt/xml/cfx_xmlelement.h"
-#include "core/fxcrt/xml/cfx_xmlnode.h"
-#include "fxjs/cfxjse_engine.h"
-#include "fxjs/xfa/cjx_object.h"
-#include "third_party/base/logging.h"
-#include "third_party/base/stl_util.h"
-#include "xfa/fxfa/parser/cxfa_bind.h"
-#include "xfa/fxfa/parser/cxfa_datagroup.h"
 #include "xfa/fxfa/parser/cxfa_document.h"
-#include "xfa/fxfa/parser/cxfa_exdata.h"
-#include "xfa/fxfa/parser/cxfa_form.h"
-#include "xfa/fxfa/parser/cxfa_image.h"
-#include "xfa/fxfa/parser/cxfa_items.h"
-#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_occur.h"
-#include "xfa/fxfa/parser/cxfa_pageset.h"
-#include "xfa/fxfa/parser/cxfa_subform.h"
-#include "xfa/fxfa/parser/cxfa_template.h"
-#include "xfa/fxfa/parser/cxfa_traversestrategy_xfacontainernode.h"
-#include "xfa/fxfa/parser/cxfa_traversestrategy_xfanode.h"
-#include "xfa/fxfa/parser/cxfa_value.h"
-#include "xfa/fxfa/parser/xfa_resolvenode_rs.h"
-#include "xfa/fxfa/parser/xfa_utils.h"
 
-namespace {
-
-class CXFA_TraverseStrategy_DDGroup {
- public:
-  static CXFA_Node* GetFirstChild(CXFA_Node* pDDGroupNode) {
-    return pDDGroupNode->GetFirstChildByName(XFA_HASHCODE_Group);
-  }
-  static CXFA_Node* GetNextSibling(CXFA_Node* pDDGroupNode) {
-    return pDDGroupNode->GetNextSameNameSibling(XFA_HASHCODE_Group);
-  }
-  static CXFA_Node* GetParent(CXFA_Node* pDDGroupNode) {
-    return pDDGroupNode->GetParent();
-  }
-};
-
-struct RecurseRecord {
-  CXFA_Node* pTemplateChild;
-  CXFA_Node* pDataChild;
-};
-
-CXFA_Node* FormValueNode_CreateChild(CXFA_Node* pValueNode, XFA_Element iType) {
-  CXFA_Node* pChildNode = pValueNode->GetFirstChild();
-  if (!pChildNode) {
-    if (iType == XFA_Element::Unknown)
-      return nullptr;
-
-    pChildNode =
-        pValueNode->JSObject()->GetOrCreateProperty<CXFA_Node>(0, iType);
-  }
-  return pChildNode;
-}
-
-void FormValueNode_MatchNoneCreateChild(CXFA_Node* pFormNode) {
-  CXFA_WidgetAcc* pWidgetAcc = pFormNode->GetWidgetAcc();
-  ASSERT(pWidgetAcc);
-  pWidgetAcc->GetUIType();
-}
-
-bool FormValueNode_SetChildContent(CXFA_Node* pValueNode,
-                                   const WideString& wsContent,
-                                   XFA_Element iType = XFA_Element::Unknown) {
-  if (!pValueNode)
-    return false;
-
-  ASSERT(pValueNode->GetPacketType() == XFA_PacketType::Form);
-  CXFA_Node* pChildNode = FormValueNode_CreateChild(pValueNode, iType);
-  if (!pChildNode)
-    return false;
-
-  switch (pChildNode->GetObjectType()) {
-    case XFA_ObjectType::ContentNode: {
-      CXFA_Node* pContentRawDataNode = pChildNode->GetFirstChild();
-      if (!pContentRawDataNode) {
-        XFA_Element element = XFA_Element::Sharptext;
-        if (pChildNode->GetElementType() == XFA_Element::ExData) {
-          Optional<WideString> contentType =
-              pChildNode->JSObject()->TryAttribute(XFA_Attribute::ContentType,
-                                                   false);
-          if (contentType) {
-            if (*contentType == L"text/html")
-              element = XFA_Element::SharpxHTML;
-            else if (*contentType == L"text/xml")
-              element = XFA_Element::Sharpxml;
-          }
-        }
-        pContentRawDataNode = pChildNode->CreateSamePacketNode(element);
-        pChildNode->InsertChild(pContentRawDataNode, nullptr);
-      }
-      pContentRawDataNode->JSObject()->SetCData(XFA_Attribute::Value, wsContent,
-                                                false, false);
-      break;
-    }
-    case XFA_ObjectType::NodeC:
-    case XFA_ObjectType::TextNode:
-    case XFA_ObjectType::NodeV: {
-      pChildNode->JSObject()->SetCData(XFA_Attribute::Value, wsContent, false,
-                                       false);
-      break;
-    }
-    default:
-      NOTREACHED();
-      break;
-  }
-  return true;
-}
-
-void CreateDataBinding(CXFA_Node* pFormNode,
-                       CXFA_Node* pDataNode,
-                       bool bDataToForm) {
-  pFormNode->SetBindingNode(pDataNode);
-  pDataNode->AddBindItem(pFormNode);
-  XFA_Element eType = pFormNode->GetElementType();
-  if (eType != XFA_Element::Field && eType != XFA_Element::ExclGroup)
-    return;
-
-  CXFA_WidgetAcc* pWidgetAcc = pFormNode->GetWidgetAcc();
-  ASSERT(pWidgetAcc);
-  XFA_Element eUIType = pWidgetAcc->GetUIType();
-  auto* defValue = pFormNode->JSObject()->GetOrCreateProperty<CXFA_Value>(
-      0, XFA_Element::Value);
-  if (!bDataToForm) {
-    WideString wsValue;
-    switch (eUIType) {
-      case XFA_Element::ImageEdit: {
-        CXFA_Image* image = defValue ? defValue->GetImageIfExists() : nullptr;
-        WideString wsContentType;
-        WideString wsHref;
-        if (image) {
-          wsValue = image->GetContent();
-          wsContentType = image->GetContentType();
-          wsHref = image->GetHref();
-        }
-        CFX_XMLElement* pXMLDataElement =
-            static_cast<CFX_XMLElement*>(pDataNode->GetXMLMappingNode());
-        ASSERT(pXMLDataElement);
-
-        pDataNode->JSObject()->SetAttributeValue(
-            wsValue, pWidgetAcc->GetFormatDataValue(wsValue), false, false);
-        pDataNode->JSObject()->SetCData(XFA_Attribute::ContentType,
-                                        wsContentType, false, false);
-        if (!wsHref.IsEmpty())
-          pXMLDataElement->SetString(L"href", wsHref);
-
-        break;
-      }
-      case XFA_Element::ChoiceList:
-        wsValue = defValue ? defValue->GetChildValueContent() : L"";
-        if (pWidgetAcc->IsChoiceListMultiSelect()) {
-          std::vector<WideString> wsSelTextArray =
-              pWidgetAcc->GetSelectedItemsValue();
-          if (!wsSelTextArray.empty()) {
-            for (const auto& text : wsSelTextArray) {
-              CXFA_Node* pValue =
-                  pDataNode->CreateSamePacketNode(XFA_Element::DataValue);
-              pValue->JSObject()->SetCData(XFA_Attribute::Name, L"value", false,
-                                           false);
-              pValue->CreateXMLMappingNode();
-              pDataNode->InsertChild(pValue, nullptr);
-              pValue->JSObject()->SetCData(XFA_Attribute::Value, text, false,
-                                           false);
-            }
-          } else {
-            CFX_XMLNode* pXMLNode = pDataNode->GetXMLMappingNode();
-            ASSERT(pXMLNode->GetType() == FX_XMLNODE_Element);
-            static_cast<CFX_XMLElement*>(pXMLNode)->SetString(L"xfa:dataNode",
-                                                              L"dataGroup");
-          }
-        } else if (!wsValue.IsEmpty()) {
-          pDataNode->JSObject()->SetAttributeValue(
-              wsValue, pWidgetAcc->GetFormatDataValue(wsValue), false, false);
-        }
-        break;
-      case XFA_Element::CheckButton:
-        wsValue = defValue ? defValue->GetChildValueContent() : L"";
-        if (wsValue.IsEmpty())
-          break;
-
-        pDataNode->JSObject()->SetAttributeValue(
-            wsValue, pWidgetAcc->GetFormatDataValue(wsValue), false, false);
-        break;
-      case XFA_Element::ExclGroup: {
-        CXFA_Node* pChecked = nullptr;
-        CXFA_Node* pChild = pFormNode->GetFirstChild();
-        for (; pChild; pChild = pChild->GetNextSibling()) {
-          if (pChild->GetElementType() != XFA_Element::Field)
-            continue;
-
-          auto* pValue =
-              pChild->GetChild<CXFA_Value>(0, XFA_Element::Value, false);
-          if (!pValue)
-            continue;
-
-          wsValue = pValue->GetChildValueContent();
-          if (wsValue.IsEmpty())
-            continue;
-
-          CXFA_Items* pItems =
-              pChild->GetChild<CXFA_Items>(0, XFA_Element::Items, false);
-          if (!pItems)
-            continue;
-
-          CXFA_Node* pText = pItems->GetFirstChild();
-          if (!pText)
-            continue;
-
-          WideString wsContent = pText->JSObject()->GetContent(false);
-          if (wsContent == wsValue) {
-            pChecked = pChild;
-            pDataNode->JSObject()->SetAttributeValue(wsValue, wsValue, false,
-                                                     false);
-            pFormNode->JSObject()->SetCData(XFA_Attribute::Value, wsContent,
-                                            false, false);
-            break;
-          }
-        }
-        if (!pChecked)
-          break;
-
-        pChild = pFormNode->GetFirstChild();
-        for (; pChild; pChild = pChild->GetNextSibling()) {
-          if (pChild == pChecked)
-            continue;
-          if (pChild->GetElementType() != XFA_Element::Field)
-            continue;
-
-          CXFA_Value* pValue =
-              pChild->JSObject()->GetOrCreateProperty<CXFA_Value>(
-                  0, XFA_Element::Value);
-          CXFA_Items* pItems =
-              pChild->GetChild<CXFA_Items>(0, XFA_Element::Items, false);
-          CXFA_Node* pText = pItems ? pItems->GetFirstChild() : nullptr;
-          if (pText)
-            pText = pText->GetNextSibling();
-
-          WideString wsContent;
-          if (pText)
-            wsContent = pText->JSObject()->GetContent(false);
-
-          FormValueNode_SetChildContent(pValue, wsContent, XFA_Element::Text);
-        }
-        break;
-      }
-      case XFA_Element::NumericEdit: {
-        wsValue = defValue ? defValue->GetChildValueContent() : L"";
-        if (wsValue.IsEmpty())
-          break;
-
-        wsValue = pWidgetAcc->NormalizeNumStr(wsValue);
-        pDataNode->JSObject()->SetAttributeValue(
-            wsValue, pWidgetAcc->GetFormatDataValue(wsValue), false, false);
-        CXFA_Value* pValue =
-            pFormNode->JSObject()->GetOrCreateProperty<CXFA_Value>(
-                0, XFA_Element::Value);
-        FormValueNode_SetChildContent(pValue, wsValue, XFA_Element::Float);
-        break;
-      }
-      default:
-        wsValue = defValue ? defValue->GetChildValueContent() : L"";
-        if (wsValue.IsEmpty())
-          break;
-
-        pDataNode->JSObject()->SetAttributeValue(
-            wsValue, pWidgetAcc->GetFormatDataValue(wsValue), false, false);
-        break;
-    }
-    return;
-  }
-
-  WideString wsXMLValue = pDataNode->JSObject()->GetContent(false);
-  WideString wsNormalizeValue = pWidgetAcc->GetNormalizeDataValue(wsXMLValue);
-
-  pDataNode->JSObject()->SetAttributeValue(wsNormalizeValue, wsXMLValue, false,
-                                           false);
-  switch (eUIType) {
-    case XFA_Element::ImageEdit: {
-      FormValueNode_SetChildContent(defValue, wsNormalizeValue,
-                                    XFA_Element::Image);
-      CXFA_Image* image = defValue ? defValue->GetImageIfExists() : nullptr;
-      if (image) {
-        CFX_XMLElement* pXMLDataElement =
-            static_cast<CFX_XMLElement*>(pDataNode->GetXMLMappingNode());
-        ASSERT(pXMLDataElement);
-
-        WideString wsContentType =
-            pXMLDataElement->GetString(L"xfa:contentType");
-        if (!wsContentType.IsEmpty()) {
-          pDataNode->JSObject()->SetCData(XFA_Attribute::ContentType,
-                                          wsContentType, false, false);
-          image->SetContentType(wsContentType);
-        }
-
-        WideString wsHref = pXMLDataElement->GetString(L"href");
-        if (!wsHref.IsEmpty())
-          image->SetHref(wsHref);
-      }
-      break;
-    }
-    case XFA_Element::ChoiceList:
-      if (pWidgetAcc->IsChoiceListMultiSelect()) {
-        std::vector<CXFA_Node*> items = pDataNode->GetNodeList(
-            XFA_NODEFILTER_Children | XFA_NODEFILTER_Properties,
-            XFA_Element::Unknown);
-        if (!items.empty()) {
-          bool single = items.size() == 1;
-          wsNormalizeValue.clear();
-
-          for (CXFA_Node* pNode : items) {
-            WideString wsItem = pNode->JSObject()->GetContent(false);
-            if (single)
-              wsItem += L"\n";
-
-            wsNormalizeValue += wsItem;
-          }
-          CXFA_ExData* exData =
-              defValue ? defValue->GetExDataIfExists() : nullptr;
-          ASSERT(exData);
-
-          exData->SetContentType(single ? L"text/plain" : L"text/xml");
-        }
-        FormValueNode_SetChildContent(defValue, wsNormalizeValue,
-                                      XFA_Element::ExData);
-      } else {
-        FormValueNode_SetChildContent(defValue, wsNormalizeValue,
-                                      XFA_Element::Text);
-      }
-      break;
-    case XFA_Element::CheckButton:
-      FormValueNode_SetChildContent(defValue, wsNormalizeValue,
-                                    XFA_Element::Text);
-      break;
-    case XFA_Element::ExclGroup: {
-      pWidgetAcc->SetSelectedMemberByValue(wsNormalizeValue.AsStringView(),
-                                           false, false, false);
-      break;
-    }
-    case XFA_Element::DateTimeEdit:
-      FormValueNode_SetChildContent(defValue, wsNormalizeValue,
-                                    XFA_Element::DateTime);
-      break;
-    case XFA_Element::NumericEdit: {
-      WideString wsPicture =
-          pWidgetAcc->GetPictureContent(XFA_VALUEPICTURE_DataBind);
-      if (wsPicture.IsEmpty())
-        wsNormalizeValue = pWidgetAcc->NormalizeNumStr(wsNormalizeValue);
-
-      FormValueNode_SetChildContent(defValue, wsNormalizeValue,
-                                    XFA_Element::Float);
-      break;
-    }
-    case XFA_Element::Barcode:
-    case XFA_Element::Button:
-    case XFA_Element::PasswordEdit:
-    case XFA_Element::Signature:
-    case XFA_Element::TextEdit:
-    default:
-      FormValueNode_SetChildContent(defValue, wsNormalizeValue,
-                                    XFA_Element::Text);
-      break;
-  }
-}
-
-CXFA_Node* GetGlobalBinding(CXFA_Document* pDocument, uint32_t dwNameHash) {
-  auto it = pDocument->m_rgGlobalBinding.find(dwNameHash);
-  return it != pDocument->m_rgGlobalBinding.end() ? it->second : nullptr;
-}
-
-void RegisterGlobalBinding(CXFA_Document* pDocument,
-                           uint32_t dwNameHash,
-                           CXFA_Node* pDataNode) {
-  pDocument->m_rgGlobalBinding[dwNameHash] = pDataNode;
-}
-
-CXFA_Node* ScopeMatchGlobalBinding(CXFA_Node* pDataScope,
-                                   uint32_t dwNameHash,
-                                   XFA_Element eMatchDataNodeType,
-                                   bool bUpLevel) {
-  for (CXFA_Node *pCurDataScope = pDataScope, *pLastDataScope = nullptr;
-       pCurDataScope &&
-       pCurDataScope->GetPacketType() == XFA_PacketType::Datasets;
-       pLastDataScope = pCurDataScope,
-                 pCurDataScope = pCurDataScope->GetParent()) {
-    for (CXFA_Node* pDataChild = pCurDataScope->GetFirstChildByName(dwNameHash);
-         pDataChild;
-         pDataChild = pDataChild->GetNextSameNameSibling(dwNameHash)) {
-      if (pDataChild == pLastDataScope ||
-          (eMatchDataNodeType != XFA_Element::DataModel &&
-           pDataChild->GetElementType() != eMatchDataNodeType) ||
-          pDataChild->HasBindItem()) {
-        continue;
-      }
-      return pDataChild;
-    }
-
-    for (CXFA_DataGroup* pDataChild =
-             pCurDataScope->GetFirstChildByClass<CXFA_DataGroup>(
-                 XFA_Element::DataGroup);
-         pDataChild;
-         pDataChild = pDataChild->GetNextSameClassSibling<CXFA_DataGroup>(
-             XFA_Element::DataGroup)) {
-      CXFA_Node* pDataNode = ScopeMatchGlobalBinding(pDataChild, dwNameHash,
-                                                     eMatchDataNodeType, false);
-      if (pDataNode)
-        return pDataNode;
-    }
-    if (!bUpLevel)
-      break;
-  }
-  return nullptr;
-}
-
-CXFA_Node* FindGlobalDataNode(CXFA_Document* pDocument,
-                              const WideString& wsName,
-                              CXFA_Node* pDataScope,
-                              XFA_Element eMatchNodeType) {
-  if (wsName.IsEmpty())
-    return nullptr;
-
-  uint32_t dwNameHash = FX_HashCode_GetW(wsName.AsStringView(), false);
-  CXFA_Node* pBounded = GetGlobalBinding(pDocument, dwNameHash);
-  if (!pBounded) {
-    pBounded =
-        ScopeMatchGlobalBinding(pDataScope, dwNameHash, eMatchNodeType, true);
-    if (pBounded)
-      RegisterGlobalBinding(pDocument, dwNameHash, pBounded);
-  }
-  return pBounded;
-}
-
-CXFA_Node* FindOnceDataNode(CXFA_Document* pDocument,
-                            const WideString& wsName,
-                            CXFA_Node* pDataScope,
-                            XFA_Element eMatchNodeType) {
-  if (wsName.IsEmpty())
-    return nullptr;
-
-  uint32_t dwNameHash = FX_HashCode_GetW(wsName.AsStringView(), false);
-  CXFA_Node* pLastDataScope = nullptr;
-  for (CXFA_Node* pCurDataScope = pDataScope;
-       pCurDataScope &&
-       pCurDataScope->GetPacketType() == XFA_PacketType::Datasets;
-       pCurDataScope = pCurDataScope->GetParent()) {
-    for (CXFA_Node* pDataChild = pCurDataScope->GetFirstChildByName(dwNameHash);
-         pDataChild;
-         pDataChild = pDataChild->GetNextSameNameSibling(dwNameHash)) {
-      if (pDataChild == pLastDataScope || pDataChild->HasBindItem() ||
-          (eMatchNodeType != XFA_Element::DataModel &&
-           pDataChild->GetElementType() != eMatchNodeType)) {
-        continue;
-      }
-      return pDataChild;
-    }
-    pLastDataScope = pCurDataScope;
-  }
-  return nullptr;
-}
-
-CXFA_Node* FindDataRefDataNode(CXFA_Document* pDocument,
-                               const WideString& wsRef,
-                               CXFA_Node* pDataScope,
-                               XFA_Element eMatchNodeType,
-                               CXFA_Node* pTemplateNode,
-                               bool bForceBind,
-                               bool bUpLevel) {
-  uint32_t dFlags = XFA_RESOLVENODE_Children | XFA_RESOLVENODE_BindNew;
-  if (bUpLevel || wsRef != L"name")
-    dFlags |= (XFA_RESOLVENODE_Parent | XFA_RESOLVENODE_Siblings);
-
-  XFA_RESOLVENODE_RS rs;
-  pDocument->GetScriptContext()->ResolveObjects(
-      pDataScope, wsRef.AsStringView(), &rs, dFlags, pTemplateNode);
-  if (rs.dwFlags == XFA_ResolveNode_RSType_CreateNodeAll ||
-      rs.dwFlags == XFA_ResolveNode_RSType_CreateNodeMidAll ||
-      rs.objects.size() > 1) {
-    return pDocument->GetNotBindNode(rs.objects);
-  }
-
-  if (rs.dwFlags == XFA_ResolveNode_RSType_CreateNodeOne) {
-    CXFA_Object* pObject = !rs.objects.empty() ? rs.objects.front() : nullptr;
-    CXFA_Node* pNode = ToNode(pObject);
-    return (bForceBind || !pNode || !pNode->HasBindItem()) ? pNode : nullptr;
-  }
-  return nullptr;
-}
-
-bool NeedGenerateForm(CXFA_Node* pTemplateChild, bool bUseInstanceManager) {
+bool XFA_DataMerge_NeedGenerateForm(CXFA_Node* pTemplateChild,
+                                    bool bUseInstanceManager) {
   XFA_Element eType = pTemplateChild->GetElementType();
   if (eType == XFA_Element::Variables)
     return true;
@@ -514,740 +23,6 @@
   return true;
 }
 
-CXFA_Node* CloneOrMergeInstanceManager(CXFA_Document* pDocument,
-                                       CXFA_Node* pFormParent,
-                                       CXFA_Node* pTemplateNode,
-                                       std::vector<CXFA_Node*>* subforms) {
-  WideString wsSubformName =
-      pTemplateNode->JSObject()->GetCData(XFA_Attribute::Name);
-  WideString wsInstMgrNodeName = L"_" + wsSubformName;
-  uint32_t dwInstNameHash =
-      FX_HashCode_GetW(wsInstMgrNodeName.AsStringView(), false);
-  CXFA_Node* pExistingNode = XFA_DataMerge_FindFormDOMInstance(
-      pDocument, XFA_Element::InstanceManager, dwInstNameHash, pFormParent);
-  if (pExistingNode) {
-    uint32_t dwNameHash = pTemplateNode->GetNameHash();
-    for (CXFA_Node* pNode = pExistingNode->GetNextSibling(); pNode;) {
-      XFA_Element eCurType = pNode->GetElementType();
-      if (eCurType == XFA_Element::InstanceManager)
-        break;
-
-      if ((eCurType != XFA_Element::Subform) &&
-          (eCurType != XFA_Element::SubformSet)) {
-        pNode = pNode->GetNextSibling();
-        continue;
-      }
-      if (dwNameHash != pNode->GetNameHash())
-        break;
-
-      CXFA_Node* pNextNode = pNode->GetNextSibling();
-      pFormParent->RemoveChild(pNode, true);
-      subforms->push_back(pNode);
-      pNode = pNextNode;
-    }
-    pFormParent->RemoveChild(pExistingNode, true);
-    pFormParent->InsertChild(pExistingNode, nullptr);
-    pExistingNode->ClearFlag(XFA_NodeFlag_UnusedNode);
-    pExistingNode->SetTemplateNode(pTemplateNode);
-    return pExistingNode;
-  }
-
-  CXFA_Node* pNewNode =
-      pDocument->CreateNode(XFA_PacketType::Form, XFA_Element::InstanceManager);
-  wsInstMgrNodeName =
-      L"_" + pTemplateNode->JSObject()->GetCData(XFA_Attribute::Name);
-  pNewNode->JSObject()->SetCData(XFA_Attribute::Name, wsInstMgrNodeName, false,
-                                 false);
-  pFormParent->InsertChild(pNewNode, nullptr);
-  pNewNode->SetTemplateNode(pTemplateNode);
-  return pNewNode;
-}
-
-CXFA_Node* FindMatchingDataNode(
-    CXFA_Document* pDocument,
-    CXFA_Node* pTemplateNode,
-    CXFA_Node* pDataScope,
-    bool& bAccessedDataDOM,
-    bool bForceBind,
-    CXFA_NodeIteratorTemplate<CXFA_Node,
-                              CXFA_TraverseStrategy_XFAContainerNode>*
-        pIterator,
-    bool& bSelfMatch,
-    XFA_AttributeEnum& eBindMatch,
-    bool bUpLevel) {
-  CXFA_Node* pResult = nullptr;
-  CXFA_Node* pCurTemplateNode = pIterator->GetCurrent();
-  while (pCurTemplateNode) {
-    XFA_Element eMatchNodeType;
-    switch (pCurTemplateNode->GetElementType()) {
-      case XFA_Element::Subform:
-        eMatchNodeType = XFA_Element::DataGroup;
-        break;
-      case XFA_Element::Field: {
-        eMatchNodeType = XFA_FieldIsMultiListBox(pCurTemplateNode)
-                             ? XFA_Element::DataGroup
-                             : XFA_Element::DataValue;
-      } break;
-      case XFA_Element::ExclGroup:
-        eMatchNodeType = XFA_Element::DataValue;
-        break;
-      default:
-        pCurTemplateNode = pIterator->MoveToNext();
-        continue;
-    }
-
-    CXFA_Occur* pTemplateNodeOccur =
-        pCurTemplateNode->GetFirstChildByClass<CXFA_Occur>(XFA_Element::Occur);
-    if (pTemplateNodeOccur) {
-      int32_t iMin;
-      int32_t iMax;
-      int32_t iInit;
-      std::tie(iMin, iMax, iInit) = pTemplateNodeOccur->GetOccurInfo();
-      if (iMax == 0) {
-        pCurTemplateNode = pIterator->MoveToNext();
-        continue;
-      }
-    }
-
-    CXFA_Bind* pTemplateNodeBind =
-        pCurTemplateNode->GetFirstChildByClass<CXFA_Bind>(XFA_Element::Bind);
-    XFA_AttributeEnum eMatch =
-        pTemplateNodeBind
-            ? pTemplateNodeBind->JSObject()->GetEnum(XFA_Attribute::Match)
-            : XFA_AttributeEnum::Once;
-    eBindMatch = eMatch;
-    switch (eMatch) {
-      case XFA_AttributeEnum::None:
-        pCurTemplateNode = pIterator->MoveToNext();
-        continue;
-      case XFA_AttributeEnum::Global:
-        bAccessedDataDOM = true;
-        if (!bForceBind) {
-          pCurTemplateNode = pIterator->MoveToNext();
-          continue;
-        }
-        if (eMatchNodeType == XFA_Element::DataValue ||
-            (eMatchNodeType == XFA_Element::DataGroup &&
-             XFA_FieldIsMultiListBox(pTemplateNodeBind))) {
-          CXFA_Node* pGlobalBindNode = FindGlobalDataNode(
-              pDocument,
-              pCurTemplateNode->JSObject()->GetCData(XFA_Attribute::Name),
-              pDataScope, eMatchNodeType);
-          if (!pGlobalBindNode) {
-            pCurTemplateNode = pIterator->MoveToNext();
-            continue;
-          }
-          pResult = pGlobalBindNode;
-          break;
-        }
-      case XFA_AttributeEnum::Once: {
-        bAccessedDataDOM = true;
-        CXFA_Node* pOnceBindNode = FindOnceDataNode(
-            pDocument,
-            pCurTemplateNode->JSObject()->GetCData(XFA_Attribute::Name),
-            pDataScope, eMatchNodeType);
-        if (!pOnceBindNode) {
-          pCurTemplateNode = pIterator->MoveToNext();
-          continue;
-        }
-        pResult = pOnceBindNode;
-        break;
-      }
-      case XFA_AttributeEnum::DataRef: {
-        bAccessedDataDOM = true;
-        CXFA_Node* pDataRefBindNode = FindDataRefDataNode(
-            pDocument,
-            pTemplateNodeBind->JSObject()->GetCData(XFA_Attribute::Ref),
-            pDataScope, eMatchNodeType, pTemplateNode, bForceBind, bUpLevel);
-        if (pDataRefBindNode &&
-            pDataRefBindNode->GetElementType() == eMatchNodeType) {
-          pResult = pDataRefBindNode;
-        }
-        if (!pResult) {
-          pCurTemplateNode = pIterator->SkipChildrenAndMoveToNext();
-          continue;
-        }
-        break;
-      }
-      default:
-        break;
-    }
-    if (pCurTemplateNode == pTemplateNode && pResult)
-      bSelfMatch = true;
-    break;
-  }
-  return pResult;
-}
-
-void SortRecurseRecord(std::vector<RecurseRecord>* rgRecords,
-                       CXFA_Node* pDataScope,
-                       bool bChoiceMode) {
-  std::vector<RecurseRecord> rgResultRecord;
-  for (CXFA_Node* pNode = pDataScope->GetFirstChild(); pNode;
-       pNode = pNode->GetNextSibling()) {
-    auto it = std::find_if(rgRecords->begin(), rgRecords->end(),
-                           [pNode](const RecurseRecord& record) {
-                             return pNode == record.pDataChild;
-                           });
-    if (it != rgRecords->end()) {
-      rgResultRecord.push_back(*it);
-      rgRecords->erase(it);
-      if (bChoiceMode)
-        break;
-    }
-  }
-  if (rgResultRecord.empty())
-    return;
-
-  if (!bChoiceMode) {
-    rgResultRecord.insert(rgResultRecord.end(), rgRecords->begin(),
-                          rgRecords->end());
-  }
-  *rgRecords = rgResultRecord;
-}
-
-CXFA_Node* CopyContainer_SubformSet(CXFA_Document* pDocument,
-                                    CXFA_Node* pTemplateNode,
-                                    CXFA_Node* pFormParentNode,
-                                    CXFA_Node* pDataScope,
-                                    bool bOneInstance,
-                                    bool bDataMerge) {
-  XFA_Element eType = pTemplateNode->GetElementType();
-  CXFA_Node* pOccurNode = nullptr;
-  CXFA_Node* pFirstInstance = nullptr;
-  bool bUseInstanceManager =
-      pFormParentNode->GetElementType() != XFA_Element::Area;
-  CXFA_Node* pInstMgrNode = nullptr;
-  std::vector<CXFA_Node*> subformArray;
-  std::vector<CXFA_Node*>* pSearchArray = nullptr;
-  if (!bOneInstance &&
-      (eType == XFA_Element::SubformSet || eType == XFA_Element::Subform)) {
-    pInstMgrNode = bUseInstanceManager ? CloneOrMergeInstanceManager(
-                                             pDocument, pFormParentNode,
-                                             pTemplateNode, &subformArray)
-                                       : nullptr;
-    if (CXFA_Occur* pOccurTemplateNode =
-            pTemplateNode->GetFirstChildByClass<CXFA_Occur>(
-                XFA_Element::Occur)) {
-      pOccurNode = pInstMgrNode ? XFA_NodeMerge_CloneOrMergeContainer(
-                                      pDocument, pInstMgrNode,
-                                      pOccurTemplateNode, false, nullptr)
-                                : pOccurTemplateNode;
-    } else if (pInstMgrNode) {
-      pOccurNode =
-          pInstMgrNode->GetFirstChildByClass<CXFA_Occur>(XFA_Element::Occur);
-      if (pOccurNode)
-        pOccurNode->ClearFlag(XFA_NodeFlag_UnusedNode);
-    }
-    if (pInstMgrNode) {
-      pInstMgrNode->SetFlag(XFA_NodeFlag_Initialized, true);
-      pSearchArray = &subformArray;
-      if (pFormParentNode->GetElementType() == XFA_Element::PageArea) {
-        bOneInstance = true;
-        if (subformArray.empty())
-          pSearchArray = nullptr;
-      } else if (pTemplateNode->GetNameHash() == 0 && subformArray.empty()) {
-        pSearchArray = nullptr;
-      }
-    }
-  }
-
-  int32_t iMax = 1;
-  int32_t iInit = 1;
-  int32_t iMin = 1;
-  if (!bOneInstance && pOccurNode) {
-    std::tie(iMin, iMax, iInit) =
-        static_cast<CXFA_Occur*>(pOccurNode)->GetOccurInfo();
-  }
-
-  XFA_AttributeEnum eRelation =
-      eType == XFA_Element::SubformSet
-          ? pTemplateNode->JSObject()->GetEnum(XFA_Attribute::Relation)
-          : XFA_AttributeEnum::Ordered;
-  int32_t iCurRepeatIndex = 0;
-  XFA_AttributeEnum eParentBindMatch = XFA_AttributeEnum::None;
-  if (bDataMerge) {
-    CXFA_NodeIteratorTemplate<CXFA_Node, CXFA_TraverseStrategy_XFAContainerNode>
-        sNodeIterator(pTemplateNode);
-    bool bAccessedDataDOM = false;
-    if (eType == XFA_Element::SubformSet || eType == XFA_Element::Area) {
-      sNodeIterator.MoveToNext();
-    } else {
-      std::map<CXFA_Node*, CXFA_Node*> subformMapArray;
-      std::vector<CXFA_Node*> nodeArray;
-      for (; iMax < 0 || iCurRepeatIndex < iMax; iCurRepeatIndex++) {
-        bool bSelfMatch = false;
-        XFA_AttributeEnum eBindMatch = XFA_AttributeEnum::None;
-        CXFA_Node* pDataNode = FindMatchingDataNode(
-            pDocument, pTemplateNode, pDataScope, bAccessedDataDOM, false,
-            &sNodeIterator, bSelfMatch, eBindMatch, true);
-        if (!pDataNode || sNodeIterator.GetCurrent() != pTemplateNode)
-          break;
-
-        eParentBindMatch = eBindMatch;
-        CXFA_Node* pSubformNode = XFA_NodeMerge_CloneOrMergeContainer(
-            pDocument, pFormParentNode, pTemplateNode, false, pSearchArray);
-        if (!pFirstInstance)
-          pFirstInstance = pSubformNode;
-
-        CreateDataBinding(pSubformNode, pDataNode, true);
-        ASSERT(pSubformNode);
-        subformMapArray[pSubformNode] = pDataNode;
-        nodeArray.push_back(pSubformNode);
-      }
-
-      for (CXFA_Node* pSubform : nodeArray) {
-        CXFA_Node* pDataNode = nullptr;
-        auto it = subformMapArray.find(pSubform);
-        if (it != subformMapArray.end())
-          pDataNode = it->second;
-        for (CXFA_Node* pTemplateChild = pTemplateNode->GetFirstChild();
-             pTemplateChild;
-             pTemplateChild = pTemplateChild->GetNextSibling()) {
-          if (NeedGenerateForm(pTemplateChild, bUseInstanceManager)) {
-            XFA_NodeMerge_CloneOrMergeContainer(pDocument, pSubform,
-                                                pTemplateChild, true, nullptr);
-          } else if (pTemplateChild->IsContainerNode()) {
-            pDocument->DataMerge_CopyContainer(pTemplateChild, pSubform,
-                                               pDataNode, false, true, false);
-          }
-        }
-      }
-      subformMapArray.clear();
-    }
-
-    for (; iMax < 0 || iCurRepeatIndex < iMax; iCurRepeatIndex++) {
-      bool bSelfMatch = false;
-      XFA_AttributeEnum eBindMatch = XFA_AttributeEnum::None;
-      if (!FindMatchingDataNode(pDocument, pTemplateNode, pDataScope,
-                                bAccessedDataDOM, false, &sNodeIterator,
-                                bSelfMatch, eBindMatch, true)) {
-        break;
-      }
-      if (eBindMatch == XFA_AttributeEnum::DataRef &&
-          eParentBindMatch == XFA_AttributeEnum::DataRef) {
-        break;
-      }
-
-      if (eRelation == XFA_AttributeEnum::Choice ||
-          eRelation == XFA_AttributeEnum::Unordered) {
-        CXFA_Node* pSubformSetNode = XFA_NodeMerge_CloneOrMergeContainer(
-            pDocument, pFormParentNode, pTemplateNode, false, pSearchArray);
-        ASSERT(pSubformSetNode);
-        if (!pFirstInstance)
-          pFirstInstance = pSubformSetNode;
-
-        std::vector<RecurseRecord> rgItemMatchList;
-        std::vector<CXFA_Node*> rgItemUnmatchList;
-        for (CXFA_Node* pTemplateChild = pTemplateNode->GetFirstChild();
-             pTemplateChild;
-             pTemplateChild = pTemplateChild->GetNextSibling()) {
-          if (NeedGenerateForm(pTemplateChild, bUseInstanceManager)) {
-            XFA_NodeMerge_CloneOrMergeContainer(pDocument, pSubformSetNode,
-                                                pTemplateChild, true, nullptr);
-          } else if (pTemplateChild->IsContainerNode()) {
-            bSelfMatch = false;
-            eBindMatch = XFA_AttributeEnum::None;
-            if (eRelation != XFA_AttributeEnum::Ordered) {
-              CXFA_NodeIteratorTemplate<CXFA_Node,
-                                        CXFA_TraverseStrategy_XFAContainerNode>
-                  sChildIter(pTemplateChild);
-              CXFA_Node* pDataMatch = FindMatchingDataNode(
-                  pDocument, pTemplateChild, pDataScope, bAccessedDataDOM,
-                  false, &sChildIter, bSelfMatch, eBindMatch, true);
-              if (pDataMatch) {
-                RecurseRecord sNewRecord = {pTemplateChild, pDataMatch};
-                if (bSelfMatch)
-                  rgItemMatchList.insert(rgItemMatchList.begin(), sNewRecord);
-                else
-                  rgItemMatchList.push_back(sNewRecord);
-              } else {
-                rgItemUnmatchList.push_back(pTemplateChild);
-              }
-            } else {
-              rgItemUnmatchList.push_back(pTemplateChild);
-            }
-          }
-        }
-
-        switch (eRelation) {
-          case XFA_AttributeEnum::Choice: {
-            ASSERT(!rgItemMatchList.empty());
-            SortRecurseRecord(&rgItemMatchList, pDataScope, true);
-            pDocument->DataMerge_CopyContainer(
-                rgItemMatchList.front().pTemplateChild, pSubformSetNode,
-                pDataScope, false, true, true);
-            break;
-          }
-          case XFA_AttributeEnum::Unordered: {
-            if (!rgItemMatchList.empty()) {
-              SortRecurseRecord(&rgItemMatchList, pDataScope, false);
-              for (const auto& matched : rgItemMatchList) {
-                pDocument->DataMerge_CopyContainer(matched.pTemplateChild,
-                                                   pSubformSetNode, pDataScope,
-                                                   false, true, true);
-              }
-            }
-            for (auto* unmatched : rgItemUnmatchList) {
-              pDocument->DataMerge_CopyContainer(unmatched, pSubformSetNode,
-                                                 pDataScope, false, true, true);
-            }
-            break;
-          }
-          default:
-            break;
-        }
-      } else {
-        CXFA_Node* pSubformSetNode = XFA_NodeMerge_CloneOrMergeContainer(
-            pDocument, pFormParentNode, pTemplateNode, false, pSearchArray);
-        ASSERT(pSubformSetNode);
-        if (!pFirstInstance)
-          pFirstInstance = pSubformSetNode;
-
-        for (CXFA_Node* pTemplateChild = pTemplateNode->GetFirstChild();
-             pTemplateChild;
-             pTemplateChild = pTemplateChild->GetNextSibling()) {
-          if (NeedGenerateForm(pTemplateChild, bUseInstanceManager)) {
-            XFA_NodeMerge_CloneOrMergeContainer(pDocument, pSubformSetNode,
-                                                pTemplateChild, true, nullptr);
-          } else if (pTemplateChild->IsContainerNode()) {
-            pDocument->DataMerge_CopyContainer(pTemplateChild, pSubformSetNode,
-                                               pDataScope, false, true, true);
-          }
-        }
-      }
-    }
-
-    if (iCurRepeatIndex == 0 && bAccessedDataDOM == false) {
-      int32_t iLimit = iMax;
-      if (pInstMgrNode && pTemplateNode->GetNameHash() == 0) {
-        iLimit = pdfium::CollectionSize<int32_t>(subformArray);
-        if (iLimit < iMin)
-          iLimit = iInit;
-      }
-
-      for (; (iLimit < 0 || iCurRepeatIndex < iLimit); iCurRepeatIndex++) {
-        if (pInstMgrNode) {
-          if (pSearchArray && pSearchArray->empty()) {
-            if (pTemplateNode->GetNameHash() != 0)
-              break;
-            pSearchArray = nullptr;
-          }
-        } else if (!XFA_DataMerge_FindFormDOMInstance(
-                       pDocument, pTemplateNode->GetElementType(),
-                       pTemplateNode->GetNameHash(), pFormParentNode)) {
-          break;
-        }
-        CXFA_Node* pSubformNode = XFA_NodeMerge_CloneOrMergeContainer(
-            pDocument, pFormParentNode, pTemplateNode, false, pSearchArray);
-        ASSERT(pSubformNode);
-        if (!pFirstInstance)
-          pFirstInstance = pSubformNode;
-
-        for (CXFA_Node* pTemplateChild = pTemplateNode->GetFirstChild();
-             pTemplateChild;
-             pTemplateChild = pTemplateChild->GetNextSibling()) {
-          if (NeedGenerateForm(pTemplateChild, bUseInstanceManager)) {
-            XFA_NodeMerge_CloneOrMergeContainer(pDocument, pSubformNode,
-                                                pTemplateChild, true, nullptr);
-          } else if (pTemplateChild->IsContainerNode()) {
-            pDocument->DataMerge_CopyContainer(pTemplateChild, pSubformNode,
-                                               pDataScope, false, true, true);
-          }
-        }
-      }
-    }
-  }
-
-  int32_t iMinimalLimit = iCurRepeatIndex == 0 ? iInit : iMin;
-  for (; iCurRepeatIndex < iMinimalLimit; iCurRepeatIndex++) {
-    CXFA_Node* pSubformSetNode = XFA_NodeMerge_CloneOrMergeContainer(
-        pDocument, pFormParentNode, pTemplateNode, false, pSearchArray);
-    ASSERT(pSubformSetNode);
-    if (!pFirstInstance)
-      pFirstInstance = pSubformSetNode;
-
-    bool bFound = false;
-    for (CXFA_Node* pTemplateChild = pTemplateNode->GetFirstChild();
-         pTemplateChild; pTemplateChild = pTemplateChild->GetNextSibling()) {
-      if (NeedGenerateForm(pTemplateChild, bUseInstanceManager)) {
-        XFA_NodeMerge_CloneOrMergeContainer(pDocument, pSubformSetNode,
-                                            pTemplateChild, true, nullptr);
-      } else if (pTemplateChild->IsContainerNode()) {
-        if (bFound && eRelation == XFA_AttributeEnum::Choice)
-          continue;
-
-        pDocument->DataMerge_CopyContainer(pTemplateChild, pSubformSetNode,
-                                           pDataScope, false, bDataMerge, true);
-        bFound = true;
-      }
-    }
-  }
-  return pFirstInstance;
-}
-
-CXFA_Node* CopyContainer_Field(CXFA_Document* pDocument,
-                               CXFA_Node* pTemplateNode,
-                               CXFA_Node* pFormNode,
-                               CXFA_Node* pDataScope,
-                               bool bDataMerge,
-                               bool bUpLevel) {
-  CXFA_Node* pFieldNode = XFA_NodeMerge_CloneOrMergeContainer(
-      pDocument, pFormNode, pTemplateNode, false, nullptr);
-  ASSERT(pFieldNode);
-  for (CXFA_Node* pTemplateChildNode = pTemplateNode->GetFirstChild();
-       pTemplateChildNode;
-       pTemplateChildNode = pTemplateChildNode->GetNextSibling()) {
-    if (NeedGenerateForm(pTemplateChildNode, true)) {
-      XFA_NodeMerge_CloneOrMergeContainer(pDocument, pFieldNode,
-                                          pTemplateChildNode, true, nullptr);
-    } else if (pTemplateNode->GetElementType() == XFA_Element::ExclGroup &&
-               pTemplateChildNode->IsContainerNode()) {
-      if (pTemplateChildNode->GetElementType() == XFA_Element::Field) {
-        CopyContainer_Field(pDocument, pTemplateChildNode, pFieldNode, nullptr,
-                            false, true);
-      }
-    }
-  }
-  if (bDataMerge) {
-    bool bAccessedDataDOM = false;
-    bool bSelfMatch = false;
-    XFA_AttributeEnum eBindMatch;
-    CXFA_NodeIteratorTemplate<CXFA_Node, CXFA_TraverseStrategy_XFAContainerNode>
-        sNodeIter(pTemplateNode);
-    CXFA_Node* pDataNode = FindMatchingDataNode(
-        pDocument, pTemplateNode, pDataScope, bAccessedDataDOM, true,
-        &sNodeIter, bSelfMatch, eBindMatch, bUpLevel);
-    if (pDataNode)
-      CreateDataBinding(pFieldNode, pDataNode, true);
-  } else {
-    FormValueNode_MatchNoneCreateChild(pFieldNode);
-  }
-  return pFieldNode;
-}
-
-CXFA_Node* MaybeCreateDataNode(CXFA_Document* pDocument,
-                               CXFA_Node* pDataParent,
-                               XFA_Element eNodeType,
-                               const WideString& wsName) {
-  if (!pDataParent)
-    return nullptr;
-
-  CXFA_Node* pParentDDNode = pDataParent->GetDataDescriptionNode();
-  if (!pParentDDNode) {
-    CXFA_Node* pDataNode =
-        pDocument->CreateNode(XFA_PacketType::Datasets, eNodeType);
-    pDataNode->JSObject()->SetCData(XFA_Attribute::Name, wsName, false, false);
-    pDataNode->CreateXMLMappingNode();
-    pDataParent->InsertChild(pDataNode, nullptr);
-    pDataNode->SetFlag(XFA_NodeFlag_Initialized, false);
-    return pDataNode;
-  }
-
-  CXFA_NodeIteratorTemplate<CXFA_Node, CXFA_TraverseStrategy_DDGroup> sIterator(
-      pParentDDNode);
-  for (CXFA_Node* pDDGroupNode = sIterator.GetCurrent(); pDDGroupNode;
-       pDDGroupNode = sIterator.MoveToNext()) {
-    if (pDDGroupNode != pParentDDNode) {
-      if (pDDGroupNode->GetElementType() != XFA_Element::DataGroup)
-        continue;
-
-      Optional<WideString> ns = pDDGroupNode->JSObject()->TryNamespace();
-      if (!ns || *ns != L"http://ns.adobe.com/data-description/")
-        continue;
-    }
-
-    CXFA_Node* pDDNode =
-        pDDGroupNode->GetFirstChildByName(wsName.AsStringView());
-    if (!pDDNode)
-      continue;
-    if (pDDNode->GetElementType() != eNodeType)
-      break;
-
-    CXFA_Node* pDataNode =
-        pDocument->CreateNode(XFA_PacketType::Datasets, eNodeType);
-    pDataNode->JSObject()->SetCData(XFA_Attribute::Name, wsName, false, false);
-    pDataNode->CreateXMLMappingNode();
-    if (eNodeType == XFA_Element::DataValue &&
-        pDDNode->JSObject()->GetEnum(XFA_Attribute::Contains) ==
-            XFA_AttributeEnum::MetaData) {
-      pDataNode->JSObject()->SetEnum(XFA_Attribute::Contains,
-                                     XFA_AttributeEnum::MetaData, false);
-    }
-    pDataParent->InsertChild(pDataNode, nullptr);
-    pDataNode->SetDataDescriptionNode(pDDNode);
-    pDataNode->SetFlag(XFA_NodeFlag_Initialized, false);
-    return pDataNode;
-  }
-  return nullptr;
-}
-
-void UpdateBindingRelations(CXFA_Document* pDocument,
-                            CXFA_Node* pFormNode,
-                            CXFA_Node* pDataScope,
-                            bool bDataRef,
-                            bool bParentDataRef) {
-  bool bMatchRef = true;
-  XFA_Element eType = pFormNode->GetElementType();
-  CXFA_Node* pDataNode = pFormNode->GetBindData();
-  if (eType == XFA_Element::Subform || eType == XFA_Element::ExclGroup ||
-      eType == XFA_Element::Field) {
-    CXFA_Node* pTemplateNode = pFormNode->GetTemplateNodeIfExists();
-    CXFA_Bind* pTemplateNodeBind =
-        pTemplateNode
-            ? pTemplateNode->GetFirstChildByClass<CXFA_Bind>(XFA_Element::Bind)
-            : nullptr;
-    XFA_AttributeEnum eMatch =
-        pTemplateNodeBind
-            ? pTemplateNodeBind->JSObject()->GetEnum(XFA_Attribute::Match)
-            : XFA_AttributeEnum::Once;
-    switch (eMatch) {
-      case XFA_AttributeEnum::None:
-        if (!bDataRef || bParentDataRef)
-          FormValueNode_MatchNoneCreateChild(pFormNode);
-        break;
-      case XFA_AttributeEnum::Once:
-        if (!bDataRef || bParentDataRef) {
-          if (!pDataNode) {
-            if (pFormNode->GetNameHash() != 0 &&
-                pFormNode->JSObject()->GetEnum(XFA_Attribute::Scope) !=
-                    XFA_AttributeEnum::None) {
-              XFA_Element eDataNodeType = (eType == XFA_Element::Subform ||
-                                           XFA_FieldIsMultiListBox(pFormNode))
-                                              ? XFA_Element::DataGroup
-                                              : XFA_Element::DataValue;
-              pDataNode = MaybeCreateDataNode(
-                  pDocument, pDataScope, eDataNodeType,
-                  WideString(
-                      pFormNode->JSObject()->GetCData(XFA_Attribute::Name)));
-              if (pDataNode)
-                CreateDataBinding(pFormNode, pDataNode, false);
-            }
-            if (!pDataNode)
-              FormValueNode_MatchNoneCreateChild(pFormNode);
-
-          } else {
-            CXFA_Node* pDataParent = pDataNode->GetParent();
-            if (pDataParent != pDataScope) {
-              ASSERT(pDataParent);
-              pDataParent->RemoveChild(pDataNode, true);
-              pDataScope->InsertChild(pDataNode, nullptr);
-            }
-          }
-        }
-        break;
-      case XFA_AttributeEnum::Global:
-        if (!bDataRef || bParentDataRef) {
-          uint32_t dwNameHash = pFormNode->GetNameHash();
-          if (dwNameHash != 0 && !pDataNode) {
-            pDataNode = GetGlobalBinding(pDocument, dwNameHash);
-            if (!pDataNode) {
-              XFA_Element eDataNodeType = (eType == XFA_Element::Subform ||
-                                           XFA_FieldIsMultiListBox(pFormNode))
-                                              ? XFA_Element::DataGroup
-                                              : XFA_Element::DataValue;
-              CXFA_Node* pRecordNode =
-                  ToNode(pDocument->GetXFAObject(XFA_HASHCODE_Record));
-              pDataNode = MaybeCreateDataNode(
-                  pDocument, pRecordNode, eDataNodeType,
-                  WideString(
-                      pFormNode->JSObject()->GetCData(XFA_Attribute::Name)));
-              if (pDataNode) {
-                CreateDataBinding(pFormNode, pDataNode, false);
-                RegisterGlobalBinding(pDocument, pFormNode->GetNameHash(),
-                                      pDataNode);
-              }
-            } else {
-              CreateDataBinding(pFormNode, pDataNode, true);
-            }
-          }
-          if (!pDataNode)
-            FormValueNode_MatchNoneCreateChild(pFormNode);
-        }
-        break;
-      case XFA_AttributeEnum::DataRef: {
-        bMatchRef = bDataRef;
-        bParentDataRef = true;
-        if (!pDataNode && bDataRef) {
-          WideString wsRef =
-              pTemplateNodeBind
-                  ? pTemplateNodeBind->JSObject()->GetCData(XFA_Attribute::Ref)
-                  : L"";
-          uint32_t dFlags =
-              XFA_RESOLVENODE_Children | XFA_RESOLVENODE_CreateNode;
-          XFA_RESOLVENODE_RS rs;
-          pDocument->GetScriptContext()->ResolveObjects(
-              pDataScope, wsRef.AsStringView(), &rs, dFlags, pTemplateNode);
-          CXFA_Object* pObject =
-              !rs.objects.empty() ? rs.objects.front() : nullptr;
-          pDataNode = ToNode(pObject);
-          if (pDataNode) {
-            CreateDataBinding(pFormNode, pDataNode,
-                              rs.dwFlags == XFA_ResolveNode_RSType_ExistNodes);
-          } else {
-            FormValueNode_MatchNoneCreateChild(pFormNode);
-          }
-        }
-        break;
-      }
-      default:
-        break;
-    }
-  }
-
-  if (bMatchRef &&
-      (eType == XFA_Element::Subform || eType == XFA_Element::SubformSet ||
-       eType == XFA_Element::Area || eType == XFA_Element::PageArea ||
-       eType == XFA_Element::PageSet)) {
-    for (CXFA_Node* pFormChild = pFormNode->GetFirstChild(); pFormChild;
-         pFormChild = pFormChild->GetNextSibling()) {
-      if (!pFormChild->IsContainerNode())
-        continue;
-      if (pFormChild->IsUnusedNode())
-        continue;
-
-      UpdateBindingRelations(pDocument, pFormChild,
-                             pDataNode ? pDataNode : pDataScope, bDataRef,
-                             bParentDataRef);
-    }
-  }
-}
-
-void UpdateDataRelation(CXFA_Node* pDataNode, CXFA_Node* pDataDescriptionNode) {
-  ASSERT(pDataDescriptionNode);
-  for (CXFA_Node* pDataChild = pDataNode->GetFirstChild(); pDataChild;
-       pDataChild = pDataChild->GetNextSibling()) {
-    uint32_t dwNameHash = pDataChild->GetNameHash();
-    if (!dwNameHash)
-      continue;
-
-    CXFA_NodeIteratorTemplate<CXFA_Node, CXFA_TraverseStrategy_DDGroup>
-        sIterator(pDataDescriptionNode);
-    for (CXFA_Node* pDDGroupNode = sIterator.GetCurrent(); pDDGroupNode;
-         pDDGroupNode = sIterator.MoveToNext()) {
-      if (pDDGroupNode != pDataDescriptionNode) {
-        if (pDDGroupNode->GetElementType() != XFA_Element::DataGroup)
-          continue;
-
-        Optional<WideString> ns = pDDGroupNode->JSObject()->TryNamespace();
-        if (!ns || *ns != L"http://ns.adobe.com/data-description/")
-          continue;
-      }
-
-      CXFA_Node* pDDNode = pDDGroupNode->GetFirstChildByName(dwNameHash);
-      if (!pDDNode)
-        continue;
-      if (pDDNode->GetElementType() != pDataChild->GetElementType())
-        break;
-
-      pDataChild->SetDataDescriptionNode(pDDNode);
-      UpdateDataRelation(pDataChild, pDDNode);
-      break;
-    }
-  }
-}
-
-}  // namespace
 
 CXFA_Node* XFA_DataMerge_FindFormDOMInstance(CXFA_Document* pDocument,
                                              XFA_Element eType,
@@ -1280,34 +55,34 @@
   }
   if (pExistingNode) {
     if (pSubformArray) {
-      pFormParent->InsertChild(pExistingNode, nullptr);
+      pFormParent->InsertChildAndNotify(pExistingNode, nullptr);
     } else if (pExistingNode->IsContainerNode()) {
-      pFormParent->RemoveChild(pExistingNode, true);
-      pFormParent->InsertChild(pExistingNode, nullptr);
+      pFormParent->RemoveChildAndNotify(pExistingNode, true);
+      pFormParent->InsertChildAndNotify(pExistingNode, nullptr);
     }
     pExistingNode->ClearFlag(XFA_NodeFlag_UnusedNode);
     pExistingNode->SetTemplateNode(pTemplateNode);
     if (bRecursive && pExistingNode->GetElementType() != XFA_Element::Items) {
       for (CXFA_Node* pTemplateChild = pTemplateNode->GetFirstChild();
            pTemplateChild; pTemplateChild = pTemplateChild->GetNextSibling()) {
-        if (NeedGenerateForm(pTemplateChild, true)) {
+        if (XFA_DataMerge_NeedGenerateForm(pTemplateChild, true)) {
           XFA_NodeMerge_CloneOrMergeContainer(
               pDocument, pExistingNode, pTemplateChild, bRecursive, nullptr);
         }
       }
     }
-    pExistingNode->SetFlag(XFA_NodeFlag_Initialized, true);
+    pExistingNode->SetFlagAndNotify(XFA_NodeFlag_Initialized);
     return pExistingNode;
   }
 
   CXFA_Node* pNewNode = pTemplateNode->CloneTemplateToForm(false);
-  pFormParent->InsertChild(pNewNode, nullptr);
+  pFormParent->InsertChildAndNotify(pNewNode, nullptr);
   if (bRecursive) {
     for (CXFA_Node* pTemplateChild = pTemplateNode->GetFirstChild();
          pTemplateChild; pTemplateChild = pTemplateChild->GetNextSibling()) {
-      if (NeedGenerateForm(pTemplateChild, true)) {
+      if (XFA_DataMerge_NeedGenerateForm(pTemplateChild, true)) {
         CXFA_Node* pNewChild = pTemplateChild->CloneTemplateToForm(true);
-        pNewNode->InsertChild(pNewChild, nullptr);
+        pNewNode->InsertChildAndNotify(pNewChild, nullptr);
       }
     }
   }
@@ -1315,6 +90,9 @@
 }
 
 CXFA_Node* XFA_DataMerge_FindDataScope(CXFA_Node* pParentFormNode) {
+  if (!pParentFormNode)
+    return nullptr;
+
   for (CXFA_Node* pRootBoundNode = pParentFormNode;
        pRootBoundNode && pRootBoundNode->IsContainerNode();
        pRootBoundNode = pRootBoundNode->GetParent()) {
@@ -1326,227 +104,3 @@
       pParentFormNode->GetDocument()->GetXFAObject(XFA_HASHCODE_Data));
 }
 
-CXFA_Node* CXFA_Document::DataMerge_CopyContainer(CXFA_Node* pTemplateNode,
-                                                  CXFA_Node* pFormNode,
-                                                  CXFA_Node* pDataScope,
-                                                  bool bOneInstance,
-                                                  bool bDataMerge,
-                                                  bool bUpLevel) {
-  switch (pTemplateNode->GetElementType()) {
-    case XFA_Element::SubformSet:
-    case XFA_Element::Subform:
-    case XFA_Element::Area:
-    case XFA_Element::PageArea:
-      return CopyContainer_SubformSet(this, pTemplateNode, pFormNode,
-                                      pDataScope, bOneInstance, bDataMerge);
-    case XFA_Element::ExclGroup:
-    case XFA_Element::Field:
-    case XFA_Element::Draw:
-    case XFA_Element::ContentArea:
-      return CopyContainer_Field(this, pTemplateNode, pFormNode, pDataScope,
-                                 bDataMerge, bUpLevel);
-    case XFA_Element::PageSet:
-    case XFA_Element::Variables:
-      break;
-    default:
-      NOTREACHED();
-      break;
-  }
-  return nullptr;
-}
-
-void CXFA_Document::DataMerge_UpdateBindingRelations(
-    CXFA_Node* pFormUpdateRoot) {
-  CXFA_Node* pDataScope =
-      XFA_DataMerge_FindDataScope(pFormUpdateRoot->GetParent());
-  if (!pDataScope)
-    return;
-
-  UpdateBindingRelations(this, pFormUpdateRoot, pDataScope, false, false);
-  UpdateBindingRelations(this, pFormUpdateRoot, pDataScope, true, false);
-}
-
-CXFA_Node* CXFA_Document::GetNotBindNode(
-    const std::vector<CXFA_Object*>& arrayObjects) {
-  for (CXFA_Object* pObject : arrayObjects) {
-    CXFA_Node* pNode = pObject->AsNode();
-    if (pNode && !pNode->HasBindItem())
-      return pNode;
-  }
-  return nullptr;
-}
-
-void CXFA_Document::DoDataMerge() {
-  CXFA_Node* pDatasetsRoot = ToNode(GetXFAObject(XFA_HASHCODE_Datasets));
-  if (!pDatasetsRoot) {
-    CFX_XMLElement* pDatasetsXMLNode = new CFX_XMLElement(L"xfa:datasets");
-    pDatasetsXMLNode->SetString(L"xmlns:xfa",
-                                L"http://www.xfa.org/schema/xfa-data/1.0/");
-    pDatasetsRoot =
-        CreateNode(XFA_PacketType::Datasets, XFA_Element::DataModel);
-    pDatasetsRoot->JSObject()->SetCData(XFA_Attribute::Name, L"datasets", false,
-                                        false);
-    m_pRootNode->GetXMLMappingNode()->InsertChildNode(pDatasetsXMLNode);
-    m_pRootNode->InsertChild(pDatasetsRoot, nullptr);
-    pDatasetsRoot->SetXMLMappingNode(pDatasetsXMLNode);
-  }
-  CXFA_Node *pDataRoot = nullptr, *pDDRoot = nullptr;
-  WideString wsDatasetsURI =
-      pDatasetsRoot->JSObject()->TryNamespace().value_or(WideString());
-  for (CXFA_Node* pChildNode = pDatasetsRoot->GetFirstChild(); pChildNode;
-       pChildNode = pChildNode->GetNextSibling()) {
-    if (pChildNode->GetElementType() != XFA_Element::DataGroup)
-      continue;
-
-    if (!pDDRoot && pChildNode->GetNameHash() == XFA_HASHCODE_DataDescription) {
-      Optional<WideString> namespaceURI =
-          pChildNode->JSObject()->TryNamespace();
-      if (!namespaceURI)
-        continue;
-      if (*namespaceURI == L"http://ns.adobe.com/data-description/")
-        pDDRoot = pChildNode;
-    } else if (!pDataRoot && pChildNode->GetNameHash() == XFA_HASHCODE_Data) {
-      Optional<WideString> namespaceURI =
-          pChildNode->JSObject()->TryNamespace();
-      if (!namespaceURI)
-        continue;
-      if (*namespaceURI == wsDatasetsURI)
-        pDataRoot = pChildNode;
-    }
-    if (pDataRoot && pDDRoot)
-      break;
-  }
-
-  if (!pDataRoot) {
-    CFX_XMLElement* pDataRootXMLNode = new CFX_XMLElement(L"xfa:data");
-    pDataRoot = CreateNode(XFA_PacketType::Datasets, XFA_Element::DataGroup);
-    pDataRoot->JSObject()->SetCData(XFA_Attribute::Name, L"data", false, false);
-    pDataRoot->SetXMLMappingNode(pDataRootXMLNode);
-    pDatasetsRoot->InsertChild(pDataRoot, nullptr);
-  }
-
-  CXFA_DataGroup* pDataTopLevel =
-      pDataRoot->GetFirstChildByClass<CXFA_DataGroup>(XFA_Element::DataGroup);
-  uint32_t dwNameHash = pDataTopLevel ? pDataTopLevel->GetNameHash() : 0;
-  CXFA_Template* pTemplateRoot =
-      m_pRootNode->GetFirstChildByClass<CXFA_Template>(XFA_Element::Template);
-  if (!pTemplateRoot)
-    return;
-
-  CXFA_Node* pTemplateChosen =
-      dwNameHash != 0 ? pTemplateRoot->GetFirstChildByName(dwNameHash)
-                      : nullptr;
-  if (!pTemplateChosen ||
-      pTemplateChosen->GetElementType() != XFA_Element::Subform) {
-    pTemplateChosen =
-        pTemplateRoot->GetFirstChildByClass<CXFA_Subform>(XFA_Element::Subform);
-  }
-  if (!pTemplateChosen)
-    return;
-
-  CXFA_Form* pFormRoot =
-      m_pRootNode->GetFirstChildByClass<CXFA_Form>(XFA_Element::Form);
-  bool bEmptyForm = false;
-  if (!pFormRoot) {
-    bEmptyForm = true;
-    pFormRoot = static_cast<CXFA_Form*>(
-        CreateNode(XFA_PacketType::Form, XFA_Element::Form));
-    ASSERT(pFormRoot);
-    pFormRoot->JSObject()->SetCData(XFA_Attribute::Name, L"form", false, false);
-    m_pRootNode->InsertChild(pFormRoot, nullptr);
-  } else {
-    CXFA_NodeIteratorTemplate<CXFA_Node, CXFA_TraverseStrategy_XFANode>
-        sIterator(pFormRoot);
-    for (CXFA_Node* pNode = sIterator.MoveToNext(); pNode;
-         pNode = sIterator.MoveToNext()) {
-      pNode->SetFlag(XFA_NodeFlag_UnusedNode, true);
-    }
-  }
-
-  CXFA_Node* pSubformSetNode = XFA_NodeMerge_CloneOrMergeContainer(
-      this, pFormRoot, pTemplateChosen, false, nullptr);
-  ASSERT(pSubformSetNode);
-  if (!pDataTopLevel) {
-    WideString wsFormName =
-        pSubformSetNode->JSObject()->GetCData(XFA_Attribute::Name);
-    WideString wsDataTopLevelName(wsFormName.IsEmpty() ? L"form" : wsFormName);
-    CFX_XMLElement* pDataTopLevelXMLNode =
-        new CFX_XMLElement(wsDataTopLevelName);
-
-    pDataTopLevel = static_cast<CXFA_DataGroup*>(
-        CreateNode(XFA_PacketType::Datasets, XFA_Element::DataGroup));
-    pDataTopLevel->JSObject()->SetCData(XFA_Attribute::Name, wsDataTopLevelName,
-                                        false, false);
-    pDataTopLevel->SetXMLMappingNode(pDataTopLevelXMLNode);
-    CXFA_Node* pBeforeNode = pDataRoot->GetFirstChild();
-    pDataRoot->InsertChild(pDataTopLevel, pBeforeNode);
-  }
-
-  ASSERT(pDataTopLevel);
-  CreateDataBinding(pSubformSetNode, pDataTopLevel, true);
-  for (CXFA_Node* pTemplateChild = pTemplateChosen->GetFirstChild();
-       pTemplateChild; pTemplateChild = pTemplateChild->GetNextSibling()) {
-    if (NeedGenerateForm(pTemplateChild, true)) {
-      XFA_NodeMerge_CloneOrMergeContainer(this, pSubformSetNode, pTemplateChild,
-                                          true, nullptr);
-    } else if (pTemplateChild->IsContainerNode()) {
-      DataMerge_CopyContainer(pTemplateChild, pSubformSetNode, pDataTopLevel,
-                              false, true, true);
-    }
-  }
-  if (pDDRoot)
-    UpdateDataRelation(pDataRoot, pDDRoot);
-
-  DataMerge_UpdateBindingRelations(pSubformSetNode);
-  CXFA_PageSet* pPageSetNode =
-      pSubformSetNode->GetFirstChildByClass<CXFA_PageSet>(XFA_Element::PageSet);
-  while (pPageSetNode) {
-    m_pPendingPageSet.push_back(pPageSetNode);
-    CXFA_PageSet* pNextPageSetNode =
-        pPageSetNode->GetNextSameClassSibling<CXFA_PageSet>(
-            XFA_Element::PageSet);
-    pSubformSetNode->RemoveChild(pPageSetNode, true);
-    pPageSetNode = pNextPageSetNode;
-  }
-
-  if (bEmptyForm)
-    return;
-
-  CXFA_NodeIteratorTemplate<CXFA_Node, CXFA_TraverseStrategy_XFANode> sIterator(
-      pFormRoot);
-  CXFA_Node* pNode = sIterator.MoveToNext();
-  while (pNode) {
-    if (pNode->IsUnusedNode()) {
-      if (pNode->IsContainerNode() ||
-          pNode->GetElementType() == XFA_Element::InstanceManager) {
-        CXFA_Node* pNext = sIterator.SkipChildrenAndMoveToNext();
-        pNode->GetParent()->RemoveChild(pNode, true);
-        pNode = pNext;
-      } else {
-        pNode->ClearFlag(XFA_NodeFlag_UnusedNode);
-        pNode->SetFlag(XFA_NodeFlag_Initialized, true);
-        pNode = sIterator.MoveToNext();
-      }
-    } else {
-      pNode->SetFlag(XFA_NodeFlag_Initialized, true);
-      pNode = sIterator.MoveToNext();
-    }
-  }
-}
-
-void CXFA_Document::DoDataRemerge(bool bDoDataMerge) {
-  CXFA_Node* pFormRoot = ToNode(GetXFAObject(XFA_HASHCODE_Form));
-  if (pFormRoot) {
-    while (CXFA_Node* pNode = pFormRoot->GetFirstChild())
-      pFormRoot->RemoveChild(pNode, true);
-
-    pFormRoot->SetBindingNode(nullptr);
-  }
-  m_rgGlobalBinding.clear();
-
-  if (bDoDataMerge)
-    DoDataMerge();
-
-  CXFA_LayoutProcessor* pLayoutProcessor = GetLayoutProcessor();
-  pLayoutProcessor->SetForceReLayout(true);
-}
diff --git a/xfa/fxfa/parser/xfa_document_datamerger_imp.h b/xfa/fxfa/parser/xfa_document_datamerger_imp.h
index 9e58678..d2c84d3 100644
--- a/xfa/fxfa/parser/xfa_document_datamerger_imp.h
+++ b/xfa/fxfa/parser/xfa_document_datamerger_imp.h
@@ -14,6 +14,8 @@
 class CXFA_Document;
 class CXFA_Node;
 
+bool XFA_DataMerge_NeedGenerateForm(CXFA_Node* pTemplateChild,
+                                    bool bUseInstanceManager);
 CXFA_Node* XFA_NodeMerge_CloneOrMergeContainer(
     CXFA_Document* pDocument,
     CXFA_Node* pFormParent,
diff --git a/xfa/fxfa/parser/xfa_resolvenode_rs.h b/xfa/fxfa/parser/xfa_resolvenode_rs.h
index 86960ab..dd9b79a 100644
--- a/xfa/fxfa/parser/xfa_resolvenode_rs.h
+++ b/xfa/fxfa/parser/xfa_resolvenode_rs.h
@@ -7,25 +7,12 @@
 #ifndef XFA_FXFA_PARSER_XFA_RESOLVENODE_RS_H_
 #define XFA_FXFA_PARSER_XFA_RESOLVENODE_RS_H_
 
-#include <memory>
-#include <utility>
 #include <vector>
 
-#include "fxjs/cfxjse_value.h"
-#include "third_party/base/ptr_util.h"
-#include "xfa/fxfa/fxfa.h"
-#include "xfa/fxfa/parser/cxfa_object.h"
+#include "core/fxcrt/unowned_ptr.h"
+#include "xfa/fxfa/parser/xfa_basic_data.h"
 
-#define XFA_RESOLVENODE_Children 0x0001
-#define XFA_RESOLVENODE_Attributes 0x0004
-#define XFA_RESOLVENODE_Properties 0x0008
-#define XFA_RESOLVENODE_Siblings 0x0020
-#define XFA_RESOLVENODE_Parent 0x0040
-#define XFA_RESOLVENODE_AnyChild 0x0080
-#define XFA_RESOLVENODE_ALL 0x0100
-#define XFA_RESOLVENODE_CreateNode 0x0400
-#define XFA_RESOLVENODE_Bind 0x0800
-#define XFA_RESOLVENODE_BindNew 0x1000
+class CXFA_Object;
 
 enum XFA_ResolveNode_RSType {
   XFA_ResolveNode_RSType_Nodes,
@@ -40,14 +27,13 @@
   XFA_RESOLVENODE_RS();
   ~XFA_RESOLVENODE_RS();
 
-  std::vector<CXFA_Object*> objects;  // Not owned.
-  XFA_ResolveNode_RSType dwFlags;
-  const XFA_SCRIPTATTRIBUTEINFO* pScriptAttribute;
+  XFA_ResolveNode_RSType dwFlags = XFA_ResolveNode_RSType_Nodes;
+  XFA_SCRIPTATTRIBUTEINFO script_attribute;
+  std::vector<UnownedPtr<CXFA_Object>> objects;
 };
 
-inline XFA_RESOLVENODE_RS::XFA_RESOLVENODE_RS()
-    : dwFlags(XFA_ResolveNode_RSType_Nodes), pScriptAttribute(nullptr) {}
+inline XFA_RESOLVENODE_RS::XFA_RESOLVENODE_RS() = default;
 
-inline XFA_RESOLVENODE_RS::~XFA_RESOLVENODE_RS() {}
+inline XFA_RESOLVENODE_RS::~XFA_RESOLVENODE_RS() = default;
 
 #endif  // XFA_FXFA_PARSER_XFA_RESOLVENODE_RS_H_
diff --git a/xfa/fxfa/parser/xfa_utils.cpp b/xfa/fxfa/parser/xfa_utils.cpp
index 5d2f222..e9a01ba 100644
--- a/xfa/fxfa/parser/xfa_utils.cpp
+++ b/xfa/fxfa/parser/xfa_utils.cpp
@@ -18,6 +18,7 @@
 #include "core/fxcrt/xml/cfx_xmlnode.h"
 #include "core/fxcrt/xml/cfx_xmltext.h"
 #include "fxjs/xfa/cjx_object.h"
+#include "third_party/base/stl_util.h"
 #include "xfa/fxfa/parser/cxfa_document.h"
 #include "xfa/fxfa/parser/cxfa_localemgr.h"
 #include "xfa/fxfa/parser/cxfa_localevalue.h"
@@ -29,24 +30,7 @@
 
 namespace {
 
-constexpr const wchar_t kFormNS[] = L"http://www.xfa.org/schema/xfa-form/";
-
-const double fraction_scales[] = {0.1,
-                                  0.01,
-                                  0.001,
-                                  0.0001,
-                                  0.00001,
-                                  0.000001,
-                                  0.0000001,
-                                  0.00000001,
-                                  0.000000001,
-                                  0.0000000001,
-                                  0.00000000001,
-                                  0.000000000001,
-                                  0.0000000000001,
-                                  0.00000000000001,
-                                  0.000000000000001,
-                                  0.0000000000000001};
+const char kFormNS[] = "http://www.xfa.org/schema/xfa-form/";
 
 WideString ExportEncodeAttribute(const WideString& str) {
   CFX_WideTextBuf textBuf;
@@ -54,19 +38,19 @@
   for (int32_t i = 0; i < iLen; i++) {
     switch (str[i]) {
       case '&':
-        textBuf << L"&amp;";
+        textBuf << "&amp;";
         break;
       case '<':
-        textBuf << L"&lt;";
+        textBuf << "&lt;";
         break;
       case '>':
-        textBuf << L"&gt;";
+        textBuf << "&gt;";
         break;
       case '\'':
-        textBuf << L"&apos;";
+        textBuf << "&apos;";
         break;
       case '\"':
-        textBuf << L"&quot;";
+        textBuf << "&quot;";
         break;
       default:
         textBuf.AppendChar(str[i]);
@@ -89,20 +73,20 @@
       continue;
 
     if (ch == '&') {
-      textBuf << L"&amp;";
+      textBuf << "&amp;";
     } else if (ch == '<') {
-      textBuf << L"&lt;";
+      textBuf << "&lt;";
     } else if (ch == '>') {
-      textBuf << L"&gt;";
+      textBuf << "&gt;";
     } else if (ch == '\'') {
-      textBuf << L"&apos;";
+      textBuf << "&apos;";
     } else if (ch == '\"') {
-      textBuf << L"&quot;";
+      textBuf << "&quot;";
     } else if (ch == ' ') {
       if (i && str[i - 1] != ' ') {
         textBuf.AppendChar(' ');
       } else {
-        textBuf << L"&#x20;";
+        textBuf << "&#x20;";
       }
     } else {
       textBuf.AppendChar(str[i]);
@@ -142,11 +126,9 @@
   CXFA_Node* pGrandParentNode = pParentNode->GetParent();
   if (!pGrandParentNode || !pGrandParentNode->IsContainerNode())
     return true;
-  if (pGrandParentNode->GetBindData())
+  if (!pGrandParentNode->GetBindData())
     return false;
-
-  XFA_Element eUIType = pGrandParentNode->GetWidgetAcc()->GetUIType();
-  if (eUIType == XFA_Element::PasswordEdit)
+  if (pGrandParentNode->GetFFWidgetType() == XFA_FFWidgetType::kPasswordEdit)
     return false;
   return true;
 }
@@ -184,8 +166,8 @@
       continue;
     }
     WideString wsAttr;
-    SaveAttribute(pNode, attr, CXFA_Node::AttributeToName(attr), bSaveXML,
-                  wsAttr);
+    SaveAttribute(pNode, attr, WideString::FromASCII(XFA_AttributeToName(attr)),
+                  bSaveXML, wsAttr);
     wsAttrs += wsAttr;
   }
 
@@ -208,66 +190,50 @@
       Optional<WideString> contentType =
           pNode->JSObject()->TryAttribute(XFA_Attribute::ContentType, false);
       if (pRawValueNode->GetElementType() == XFA_Element::SharpxHTML &&
-          (contentType && *contentType == L"text/html")) {
+          contentType.has_value() &&
+          contentType.value().EqualsASCII("text/html")) {
         CFX_XMLNode* pExDataXML = pNode->GetXMLMappingNode();
         if (!pExDataXML)
           break;
 
-        CFX_XMLNode* pRichTextXML =
-            pExDataXML->GetNodeItem(CFX_XMLNode::FirstChild);
+        CFX_XMLNode* pRichTextXML = pExDataXML->GetFirstChild();
         if (!pRichTextXML)
           break;
 
-        auto pMemStream = pdfium::MakeRetain<CFX_MemoryStream>(true);
-        auto pTempStream =
-            pdfium::MakeRetain<CFX_SeekableStreamProxy>(pMemStream, true);
-
-        pTempStream->SetCodePage(FX_CODEPAGE_UTF8);
-        pRichTextXML->SaveXMLNode(pTempStream);
+        auto pMemStream = pdfium::MakeRetain<CFX_MemoryStream>();
+        pRichTextXML->Save(pMemStream);
         wsChildren += WideString::FromUTF8(
             ByteStringView(pMemStream->GetBuffer(), pMemStream->GetSize()));
       } else if (pRawValueNode->GetElementType() == XFA_Element::Sharpxml &&
-                 (contentType && *contentType == L"text/xml")) {
+                 contentType.has_value() &&
+                 contentType.value().EqualsASCII("text/xml")) {
         Optional<WideString> rawValue = pRawValueNode->JSObject()->TryAttribute(
             XFA_Attribute::Value, false);
         if (!rawValue || rawValue->IsEmpty())
           break;
 
-        std::vector<WideString> wsSelTextArray;
-        size_t iStart = 0;
-        auto iEnd = rawValue->Find(L'\n', iStart);
-        iEnd = !iEnd.has_value() ? rawValue->GetLength() : iEnd;
-        while (iEnd.has_value() && iEnd >= iStart) {
-          wsSelTextArray.push_back(
-              rawValue->Mid(iStart, iEnd.value() - iStart));
-          iStart = iEnd.value() + 1;
-          if (iStart >= rawValue->GetLength())
-            break;
-          iEnd = rawValue->Find(L'\n', iStart);
-        }
+        std::vector<WideString> wsSelTextArray =
+            fxcrt::Split(rawValue.value(), L'\n');
 
         CXFA_Node* pParentNode = pNode->GetParent();
-        ASSERT(pParentNode);
         CXFA_Node* pGrandparentNode = pParentNode->GetParent();
-        ASSERT(pGrandparentNode);
-        WideString bodyTagName;
-        bodyTagName =
+        WideString bodyTagName =
             pGrandparentNode->JSObject()->GetCData(XFA_Attribute::Name);
         if (bodyTagName.IsEmpty())
           bodyTagName = L"ListBox1";
 
-        buf << L"<";
+        buf << "<";
         buf << bodyTagName;
-        buf << L" xmlns=\"\"\n>";
+        buf << " xmlns=\"\"\n>";
         for (int32_t i = 0; i < pdfium::CollectionSize<int32_t>(wsSelTextArray);
              i++) {
-          buf << L"<value\n>";
+          buf << "<value\n>";
           buf << ExportEncodeContent(wsSelTextArray[i]);
-          buf << L"</value\n>";
+          buf << "</value\n>";
         }
-        buf << L"</";
+        buf << "</";
         buf << bodyTagName;
-        buf << L"\n>";
+        buf << "\n>";
         wsChildren += buf.AsStringView();
         buf.Clear();
       } else {
@@ -318,29 +284,28 @@
 
   if (!wsChildren.IsEmpty() || !wsAttrs.IsEmpty() ||
       pNode->JSObject()->HasAttribute(XFA_Attribute::Name)) {
-    WideStringView wsElement = pNode->GetClassName();
+    WideString wsElement = WideString::FromASCII(pNode->GetClassName());
     WideString wsName;
     SaveAttribute(pNode, XFA_Attribute::Name, L"name", true, wsName);
-    buf << L"<";
+    buf << "<";
     buf << wsElement;
     buf << wsName;
     buf << wsAttrs;
     if (wsChildren.IsEmpty()) {
-      buf << L"\n/>";
+      buf << "\n/>";
     } else {
-      buf << L"\n>";
+      buf << "\n>";
       buf << wsChildren;
-      buf << L"</";
+      buf << "</";
       buf << wsElement;
-      buf << L"\n>";
+      buf << "\n>";
     }
   }
 }
 
-void RegenerateFormFile_Container(
-    CXFA_Node* pNode,
-    const RetainPtr<CFX_SeekableStreamProxy>& pStream,
-    bool bSaveXML) {
+void RegenerateFormFile_Container(CXFA_Node* pNode,
+                                  const RetainPtr<IFX_SeekableStream>& pStream,
+                                  bool bSaveXML) {
   XFA_Element eType = pNode->GetElementType();
   if (eType == XFA_Element::Field || eType == XFA_Element::Draw ||
       !pNode->IsContainerNode()) {
@@ -348,13 +313,13 @@
     RegenerateFormFile_Changed(pNode, buf, bSaveXML);
     size_t nLen = buf.GetLength();
     if (nLen > 0)
-      pStream->WriteString(buf.AsStringView());
+      pStream->WriteString(buf.MakeString().ToUTF8().AsStringView());
     return;
   }
 
-  WideStringView wsElement(pNode->GetClassName());
-  pStream->WriteString(L"<");
-  pStream->WriteString(wsElement);
+  WideString wsElement = WideString::FromASCII(pNode->GetClassName());
+  pStream->WriteString("<");
+  pStream->WriteString(wsElement.ToUTF8().AsStringView());
 
   WideString wsOutput;
   SaveAttribute(pNode, XFA_Attribute::Name, L"name", true, wsOutput);
@@ -368,26 +333,28 @@
       continue;
 
     WideString wsAttr;
-    SaveAttribute(pNode, attr, CXFA_Node::AttributeToName(attr), false, wsAttr);
+    SaveAttribute(pNode, attr, WideString::FromASCII(XFA_AttributeToName(attr)),
+                  false, wsAttr);
     wsOutput += wsAttr;
   }
 
   if (!wsOutput.IsEmpty())
-    pStream->WriteString(wsOutput.AsStringView());
+    pStream->WriteString(wsOutput.ToUTF8().AsStringView());
 
   CXFA_Node* pChildNode = pNode->GetFirstChild();
-  if (pChildNode) {
-    pStream->WriteString(L"\n>");
-    while (pChildNode) {
-      RegenerateFormFile_Container(pChildNode, pStream, bSaveXML);
-      pChildNode = pChildNode->GetNextSibling();
-    }
-    pStream->WriteString(L"</");
-    pStream->WriteString(wsElement);
-    pStream->WriteString(L"\n>");
-  } else {
-    pStream->WriteString(L"\n/>");
+  if (!pChildNode) {
+    pStream->WriteString(" />\n");
+    return;
   }
+
+  pStream->WriteString(">\n");
+  while (pChildNode) {
+    RegenerateFormFile_Container(pChildNode, pStream, bSaveXML);
+    pChildNode = pChildNode->GetNextSibling();
+  }
+  pStream->WriteString("</");
+  pStream->WriteString(wsElement.ToUTF8().AsStringView());
+  pStream->WriteString(">\n");
 }
 
 WideString RecognizeXFAVersionNumber(CXFA_Node* pTemplateRoot) {
@@ -408,14 +375,6 @@
 
 }  // namespace
 
-double XFA_GetFractionalScale(uint32_t idx) {
-  return fraction_scales[idx];
-}
-
-int XFA_GetMaxFractionalScale() {
-  return FX_ArraySize(fraction_scales);
-}
-
 CXFA_LocaleValue XFA_GetLocaleValue(CXFA_Node* pNode) {
   CXFA_Value* pNodeValue =
       pNode->GetChild<CXFA_Value>(0, XFA_Element::Value, false);
@@ -457,7 +416,7 @@
       break;
   }
   return CXFA_LocaleValue(iVTType, pNode->GetRawValue(),
-                          pNode->GetDocument()->GetLocalMgr());
+                          pNode->GetDocument()->GetLocaleMgr());
 }
 
 bool XFA_FDEExtension_ResolveNamespaceQualifier(CFX_XMLElement* pNode,
@@ -466,7 +425,7 @@
   if (!pNode)
     return false;
 
-  CFX_XMLNode* pFakeRoot = pNode->GetNodeItem(CFX_XMLNode::Root);
+  CFX_XMLNode* pFakeRoot = pNode->GetRoot();
   WideString wsNSAttribute;
   bool bRet = false;
   if (wsQualifier.IsEmpty()) {
@@ -476,13 +435,10 @@
     wsNSAttribute = L"xmlns:" + wsQualifier;
   }
   for (CFX_XMLNode* pParent = pNode; pParent != pFakeRoot;
-       pParent = pParent->GetNodeItem(CFX_XMLNode::Parent)) {
-    if (pParent->GetType() != FX_XMLNODE_Element)
-      continue;
-
-    auto* pElement = static_cast<CFX_XMLElement*>(pParent);
-    if (pElement->HasAttribute(wsNSAttribute.c_str())) {
-      *wsNamespaceURI = pElement->GetString(wsNSAttribute.c_str());
+       pParent = pParent->GetParent()) {
+    CFX_XMLElement* pElement = ToXMLElement(pParent);
+    if (pElement && pElement->HasAttribute(wsNSAttribute)) {
+      *wsNamespaceURI = pElement->GetAttribute(wsNSAttribute);
       return true;
     }
   }
@@ -504,37 +460,22 @@
   if (pDataNode->GetElementType() != XFA_Element::DataGroup)
     return;
 
+  CFX_XMLElement* pElement = ToXMLElement(pDataNode->GetXMLMappingNode());
   if (iChildNum > 0) {
-    CFX_XMLNode* pXMLNode = pDataNode->GetXMLMappingNode();
-    ASSERT(pXMLNode->GetType() == FX_XMLNODE_Element);
-    CFX_XMLElement* pXMLElement = static_cast<CFX_XMLElement*>(pXMLNode);
-    if (pXMLElement->HasAttribute(L"xfa:dataNode"))
-      pXMLElement->RemoveAttribute(L"xfa:dataNode");
-
+    if (pElement->HasAttribute(L"xfa:dataNode"))
+      pElement->RemoveAttribute(L"xfa:dataNode");
     return;
   }
-
-  CFX_XMLNode* pXMLNode = pDataNode->GetXMLMappingNode();
-  ASSERT(pXMLNode->GetType() == FX_XMLNODE_Element);
-  static_cast<CFX_XMLElement*>(pXMLNode)->SetString(L"xfa:dataNode",
-                                                    L"dataGroup");
+  pElement->SetAttribute(L"xfa:dataNode", L"dataGroup");
 }
 
 void XFA_DataExporter_RegenerateFormFile(
     CXFA_Node* pNode,
-    const RetainPtr<CFX_SeekableStreamProxy>& pStream,
-    const char* pChecksum,
+    const RetainPtr<IFX_SeekableStream>& pStream,
     bool bSaveXML) {
   if (pNode->IsModelNode()) {
-    pStream->WriteString(L"<form");
-    if (pChecksum) {
-      WideString wsChecksum = WideString::FromUTF8(pChecksum);
-      pStream->WriteString(L" checksum=\"");
-      pStream->WriteString(wsChecksum.AsStringView());
-      pStream->WriteString(L"\"");
-    }
-    pStream->WriteString(L" xmlns=\"");
-    pStream->WriteString(WideStringView(kFormNS));
+    pStream->WriteString("<form xmlns=\"");
+    pStream->WriteString(kFormNS);
 
     WideString wsVersionNumber = RecognizeXFAVersionNumber(
         ToNode(pNode->GetDocument()->GetXFAObject(XFA_HASHCODE_Template)));
@@ -542,14 +483,14 @@
       wsVersionNumber = L"2.8";
 
     wsVersionNumber += L"/\"\n>";
-    pStream->WriteString(wsVersionNumber.AsStringView());
+    pStream->WriteString(wsVersionNumber.ToUTF8().AsStringView());
 
     CXFA_Node* pChildNode = pNode->GetFirstChild();
     while (pChildNode) {
       RegenerateFormFile_Container(pChildNode, pStream, false);
       pChildNode = pChildNode->GetNextSibling();
     }
-    pStream->WriteString(L"</form\n>");
+    pStream->WriteString("</form\n>");
   } else {
     RegenerateFormFile_Container(pNode, pStream, bSaveXML);
   }
@@ -570,7 +511,7 @@
   }
 
   return pFirstChild->JSObject()->GetEnum(XFA_Attribute::Open) ==
-         XFA_AttributeEnum::MultiSelect;
+         XFA_AttributeValue::MultiSelect;
 }
 
 int32_t XFA_MapRotation(int32_t nRotation) {
@@ -579,33 +520,7 @@
   return nRotation;
 }
 
-const XFA_SCRIPTATTRIBUTEINFO* XFA_GetScriptAttributeByName(
-    XFA_Element eElement,
-    const WideStringView& wsAttributeName) {
-  if (wsAttributeName.IsEmpty())
-    return nullptr;
-
-  int32_t iElementIndex = static_cast<int32_t>(eElement);
-  while (iElementIndex != -1) {
-    const XFA_SCRIPTHIERARCHY* scriptIndex = g_XFAScriptIndex + iElementIndex;
-    int32_t icount = scriptIndex->wAttributeCount;
-    if (icount == 0) {
-      iElementIndex = scriptIndex->wParentIndex;
-      continue;
-    }
-    uint32_t uHash = FX_HashCode_GetW(wsAttributeName, false);
-    int32_t iStart = scriptIndex->wAttributeStart, iEnd = iStart + icount - 1;
-    do {
-      int32_t iMid = (iStart + iEnd) / 2;
-      const XFA_SCRIPTATTRIBUTEINFO* pInfo = g_SomAttributeData + iMid;
-      if (uHash == pInfo->uHash)
-        return pInfo;
-      if (uHash < pInfo->uHash)
-        iEnd = iMid - 1;
-      else
-        iStart = iMid + 1;
-    } while (iStart <= iEnd);
-    iElementIndex = scriptIndex->wParentIndex;
-  }
-  return nullptr;
+void XFA_EventErrorAccumulate(XFA_EventError* pAcc, XFA_EventError eNew) {
+  if (*pAcc == XFA_EventError::kNotExist || eNew == XFA_EventError::kError)
+    *pAcc = eNew;
 }
diff --git a/xfa/fxfa/parser/xfa_utils.h b/xfa/fxfa/parser/xfa_utils.h
index 9308157..89c30c3 100644
--- a/xfa/fxfa/parser/xfa_utils.h
+++ b/xfa/fxfa/parser/xfa_utils.h
@@ -7,17 +7,14 @@
 #ifndef XFA_FXFA_PARSER_XFA_UTILS_H_
 #define XFA_FXFA_PARSER_XFA_UTILS_H_
 
-#include "core/fxcrt/cfx_seekablestreamproxy.h"
+#include "core/fxcrt/fx_stream.h"
+#include "xfa/fxfa/fxfa.h"
 #include "xfa/fxfa/fxfa_basic.h"
 
 class CFX_XMLElement;
 class CFX_XMLNode;
 class CXFA_LocaleValue;
 class CXFA_Node;
-class CXFA_WidgetAcc;
-
-double XFA_GetFractionalScale(uint32_t idx);
-int XFA_GetMaxFractionalScale();
 
 bool XFA_FDEExtension_ResolveNamespaceQualifier(CFX_XMLElement* pNode,
                                                 const WideString& wsQualifier,
@@ -32,12 +29,9 @@
 void XFA_DataExporter_DealWithDataGroupNode(CXFA_Node* pDataNode);
 void XFA_DataExporter_RegenerateFormFile(
     CXFA_Node* pNode,
-    const RetainPtr<CFX_SeekableStreamProxy>& pStream,
-    const char* pChecksum,
+    const RetainPtr<IFX_SeekableStream>& pStream,
     bool bSaveXML);
 
-const XFA_SCRIPTATTRIBUTEINFO* XFA_GetScriptAttributeByName(
-    XFA_Element eElement,
-    const WideStringView& wsAttributeName);
+void XFA_EventErrorAccumulate(XFA_EventError* pAcc, XFA_EventError eNew);
 
 #endif  // XFA_FXFA_PARSER_XFA_UTILS_H_
diff --git a/xfa/fxfa/parser/xfa_utils_unittest.cpp b/xfa/fxfa/parser/xfa_utils_unittest.cpp
index c9f662e..e4d6cb8 100644
--- a/xfa/fxfa/parser/xfa_utils_unittest.cpp
+++ b/xfa/fxfa/parser/xfa_utils_unittest.cpp
@@ -5,7 +5,6 @@
 #include "xfa/fxfa/parser/xfa_utils.h"
 
 #include "testing/gtest/include/gtest/gtest.h"
-#include "testing/test_support.h"
 
 TEST(XfaUtilsImpTest, XFA_MapRotation) {
   struct TestCase {
diff --git a/xfa/fxgraphics/BUILD.gn b/xfa/fxgraphics/BUILD.gn
new file mode 100644
index 0000000..b1b0204
--- /dev/null
+++ b/xfa/fxgraphics/BUILD.gn
@@ -0,0 +1,31 @@
+# Copyright 2018 The 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.
+
+import("../../pdfium.gni")
+
+assert(pdf_enable_xfa)
+
+source_set("fxgraphics") {
+  sources = [
+    "cxfa_gecolor.cpp",
+    "cxfa_gecolor.h",
+    "cxfa_gepath.cpp",
+    "cxfa_gepath.h",
+    "cxfa_gepattern.cpp",
+    "cxfa_gepattern.h",
+    "cxfa_geshading.cpp",
+    "cxfa_geshading.h",
+    "cxfa_graphics.cpp",
+    "cxfa_graphics.h",
+  ]
+  configs += [
+    "../../:pdfium_core_config",
+    "../:xfa_warnings",
+  ]
+  deps = [
+    "../../core/fxcrt",
+    "../../core/fxge",
+  ]
+  visibility = [ "../../*" ]
+}
diff --git a/xfa/fxgraphics/cxfa_gecolor.cpp b/xfa/fxgraphics/cxfa_gecolor.cpp
index 3dca4a7..32dec96 100644
--- a/xfa/fxgraphics/cxfa_gecolor.cpp
+++ b/xfa/fxgraphics/cxfa_gecolor.cpp
@@ -6,42 +6,16 @@
 
 #include "xfa/fxgraphics/cxfa_gecolor.h"
 
-CXFA_GEColor::CXFA_GEColor() : m_type(Invalid) {}
-
-CXFA_GEColor::CXFA_GEColor(const FX_ARGB argb) : m_type(Solid), m_argb(argb) {
-  m_pointer.pattern = nullptr;
-}
+CXFA_GEColor::CXFA_GEColor(const FX_ARGB argb) : m_type(Solid), m_argb(argb) {}
 
 CXFA_GEColor::CXFA_GEColor(CXFA_GEPattern* pattern, const FX_ARGB argb)
-    : m_type(Pattern), m_argb(argb) {
-  m_pointer.pattern = pattern;
-}
+    : m_type(Pattern), m_argb(argb), m_pPattern(pattern) {}
 
 CXFA_GEColor::CXFA_GEColor(CXFA_GEShading* shading)
-    : m_type(Shading), m_argb(0) {
-  m_pointer.shading = shading;
-}
+    : m_type(Shading), m_pShading(shading) {}
 
-CXFA_GEColor::~CXFA_GEColor() {}
+CXFA_GEColor::CXFA_GEColor(const CXFA_GEColor& that) = default;
 
-CXFA_GEColor& CXFA_GEColor::operator=(const CXFA_GEColor& that) {
-  if (this != &that) {
-    m_type = that.m_type;
-    switch (m_type) {
-      case Solid:
-        m_argb = that.m_argb;
-        m_pointer.pattern = nullptr;
-        break;
-      case Pattern:
-        m_argb = that.m_argb;
-        m_pointer.pattern = that.m_pointer.pattern;
-        break;
-      case Shading:
-        m_argb = 0;
-        m_pointer.shading = that.m_pointer.shading;
-      default:
-        break;
-    }
-  }
-  return *this;
-}
+CXFA_GEColor::~CXFA_GEColor() = default;
+
+CXFA_GEColor& CXFA_GEColor::operator=(const CXFA_GEColor& that) = default;
diff --git a/xfa/fxgraphics/cxfa_gecolor.h b/xfa/fxgraphics/cxfa_gecolor.h
index b60585b..9cf40aa 100644
--- a/xfa/fxgraphics/cxfa_gecolor.h
+++ b/xfa/fxgraphics/cxfa_gecolor.h
@@ -7,6 +7,7 @@
 #ifndef XFA_FXGRAPHICS_CXFA_GECOLOR_H_
 #define XFA_FXGRAPHICS_CXFA_GECOLOR_H_
 
+#include "core/fxcrt/unowned_ptr.h"
 #include "core/fxge/fx_dib.h"
 
 class CXFA_GEPattern;
@@ -16,10 +17,10 @@
  public:
   enum Type { Invalid, Solid, Pattern, Shading };
 
-  CXFA_GEColor();
   explicit CXFA_GEColor(const FX_ARGB argb);
   explicit CXFA_GEColor(CXFA_GEShading* shading);
   CXFA_GEColor(CXFA_GEPattern* pattern, const FX_ARGB argb);
+  CXFA_GEColor(const CXFA_GEColor& that);
   ~CXFA_GEColor();
 
   Type GetType() const { return m_type; }
@@ -29,22 +30,20 @@
   }
   CXFA_GEPattern* GetPattern() const {
     ASSERT(m_type == Pattern);
-    return m_pointer.pattern;
+    return m_pPattern.Get();
   }
   CXFA_GEShading* GetShading() const {
     ASSERT(m_type == Shading);
-    return m_pointer.shading;
+    return m_pShading.Get();
   }
 
   CXFA_GEColor& operator=(const CXFA_GEColor& that);
 
  private:
-  Type m_type;
-  FX_ARGB m_argb;
-  union {
-    CXFA_GEPattern* pattern;
-    CXFA_GEShading* shading;
-  } m_pointer;
+  Type m_type = Invalid;
+  FX_ARGB m_argb = 0;
+  UnownedPtr<CXFA_GEPattern> m_pPattern;
+  UnownedPtr<CXFA_GEShading> m_pShading;
 };
 
 #endif  // XFA_FXGRAPHICS_CXFA_GECOLOR_H_
diff --git a/xfa/fxgraphics/cxfa_gepath.cpp b/xfa/fxgraphics/cxfa_gepath.cpp
index 88372f7..6597c80 100644
--- a/xfa/fxgraphics/cxfa_gepath.cpp
+++ b/xfa/fxgraphics/cxfa_gepath.cpp
@@ -7,7 +7,6 @@
 #include "xfa/fxgraphics/cxfa_gepath.h"
 
 #include "core/fxge/cfx_pathdata.h"
-#include "third_party/base/ptr_util.h"
 
 CXFA_GEPath::CXFA_GEPath() {}
 
@@ -147,5 +146,5 @@
 }
 
 void CXFA_GEPath::TransformBy(const CFX_Matrix& mt) {
-  data_.Transform(&mt);
+  data_.Transform(mt);
 }
diff --git a/xfa/fxgraphics/cxfa_gepattern.cpp b/xfa/fxgraphics/cxfa_gepattern.cpp
index 2a6a0e4..5a98a5f 100644
--- a/xfa/fxgraphics/cxfa_gepattern.cpp
+++ b/xfa/fxgraphics/cxfa_gepattern.cpp
@@ -8,13 +8,7 @@
 
 CXFA_GEPattern::CXFA_GEPattern(FX_HatchStyle hatchStyle,
                                const FX_ARGB foreArgb,
-                               const FX_ARGB backArgb,
-                               CFX_Matrix* matrix)
-    : m_hatchStyle(hatchStyle), m_foreArgb(foreArgb), m_backArgb(backArgb) {
-  if (matrix)
-    m_matrix = *matrix;
-  else
-    m_matrix.SetIdentity();
-}
+                               const FX_ARGB backArgb)
+    : m_hatchStyle(hatchStyle), m_foreArgb(foreArgb), m_backArgb(backArgb) {}
 
 CXFA_GEPattern::~CXFA_GEPattern() {}
diff --git a/xfa/fxgraphics/cxfa_gepattern.h b/xfa/fxgraphics/cxfa_gepattern.h
index 0f4ced2..f5a3413 100644
--- a/xfa/fxgraphics/cxfa_gepattern.h
+++ b/xfa/fxgraphics/cxfa_gepattern.h
@@ -14,20 +14,17 @@
 class CFX_DIBitmap;
 class CFX_Matrix;
 
-class CXFA_GEPattern {
+class CXFA_GEPattern final {
  public:
   CXFA_GEPattern(FX_HatchStyle hatchStyle,
                  const FX_ARGB foreArgb,
-                 const FX_ARGB backArgb,
-                 CFX_Matrix* matrix = nullptr);
+                 const FX_ARGB backArgb);
 
-  virtual ~CXFA_GEPattern();
+  ~CXFA_GEPattern();
 
  private:
   friend class CXFA_Graphics;
 
-  CFX_Matrix m_matrix;
-
   const FX_HatchStyle m_hatchStyle;
   const FX_ARGB m_foreArgb;
   const FX_ARGB m_backArgb;
diff --git a/xfa/fxgraphics/cxfa_geshading.cpp b/xfa/fxgraphics/cxfa_geshading.cpp
index f691169..d1bec70 100644
--- a/xfa/fxgraphics/cxfa_geshading.cpp
+++ b/xfa/fxgraphics/cxfa_geshading.cpp
@@ -73,6 +73,6 @@
 
     // TODO(dsinclair): Add overloads for FX_ARGB. pdfium:437
     m_argbArray[i] =
-        FXARGB_TODIB(FXARGB_MAKE(a1 + a3, r1 + r3, g1 + g3, b1 + b3));
+        FXARGB_TODIB(ArgbEncode(a1 + a3, r1 + r3, g1 + g3, b1 + b3));
   }
 }
diff --git a/xfa/fxgraphics/cxfa_geshading.h b/xfa/fxgraphics/cxfa_geshading.h
index fc7a13e..8905a12 100644
--- a/xfa/fxgraphics/cxfa_geshading.h
+++ b/xfa/fxgraphics/cxfa_geshading.h
@@ -15,7 +15,7 @@
 
 enum CXFA_GEShading_Type { FX_SHADING_Axial = 1, FX_SHADING_Radial };
 
-class CXFA_GEShading {
+class CXFA_GEShading final {
  public:
   // Axial shading.
   CXFA_GEShading(const CFX_PointF& beginPoint,
@@ -34,7 +34,8 @@
                  bool isExtendedEnd,
                  const FX_ARGB beginArgb,
                  const FX_ARGB endArgb);
-  virtual ~CXFA_GEShading();
+
+  ~CXFA_GEShading();
 
  private:
   friend class CXFA_Graphics;
diff --git a/xfa/fxgraphics/cxfa_graphics.cpp b/xfa/fxgraphics/cxfa_graphics.cpp
index d1e2f35..ff6bac1 100644
--- a/xfa/fxgraphics/cxfa_graphics.cpp
+++ b/xfa/fxgraphics/cxfa_graphics.cpp
@@ -6,6 +6,7 @@
 
 #include "xfa/fxgraphics/cxfa_graphics.h"
 
+#include <cmath>
 #include <memory>
 
 #include "core/fxge/cfx_defaultrenderdevice.h"
@@ -20,20 +21,13 @@
 
 namespace {
 
-enum {
-  FX_CONTEXT_None = 0,
-  FX_CONTEXT_Device,
-};
-
-#define FX_HATCHSTYLE_Total 53
-
 struct FX_HATCHDATA {
   int32_t width;
   int32_t height;
   uint8_t maskBits[64];
 };
 
-const FX_HATCHDATA hatchBitmapData[FX_HATCHSTYLE_Total] = {
+const FX_HATCHDATA kHatchBitmapData[] = {
     {16,  // Horizontal
      16,
      {
@@ -96,31 +90,40 @@
      }},
 };
 
+const FX_HATCHDATA kHatchPlaceHolder = {
+    0,
+    0,
+    {
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    }};
+
+const FX_HATCHDATA& GetHatchBitmapData(size_t index) {
+  return index < FX_ArraySize(kHatchBitmapData) ? kHatchBitmapData[index]
+                                                : kHatchPlaceHolder;
+}
+
 }  // namespace
 
 CXFA_Graphics::CXFA_Graphics(CFX_RenderDevice* renderDevice)
-    : m_type(FX_CONTEXT_None), m_renderDevice(renderDevice) {
-  if (!renderDevice)
-    return;
-  m_type = FX_CONTEXT_Device;
+    : m_renderDevice(renderDevice) {
+  ASSERT(m_renderDevice);
 }
 
-CXFA_Graphics::~CXFA_Graphics() {}
+CXFA_Graphics::~CXFA_Graphics() = default;
 
 void CXFA_Graphics::SaveGraphState() {
-  if (m_type != FX_CONTEXT_Device || !m_renderDevice)
-    return;
-
   m_renderDevice->SaveState();
   m_infoStack.push_back(pdfium::MakeUnique<TInfo>(m_info));
 }
 
 void CXFA_Graphics::RestoreGraphState() {
-  if (m_type != FX_CONTEXT_Device || !m_renderDevice)
-    return;
-
   m_renderDevice->RestoreState(false);
-  if (m_infoStack.empty() || !m_infoStack.back())
+  if (m_infoStack.empty())
     return;
 
   m_info = *m_infoStack.back();
@@ -129,100 +132,72 @@
 }
 
 void CXFA_Graphics::SetLineCap(CFX_GraphStateData::LineCap lineCap) {
-  if (m_type == FX_CONTEXT_Device && m_renderDevice) {
-    m_info.graphState.m_LineCap = lineCap;
-  }
+  m_info.graphState.m_LineCap = lineCap;
 }
 
 void CXFA_Graphics::SetLineDash(float dashPhase,
-                                float* dashArray,
-                                int32_t dashCount) {
-  if (dashCount > 0 && !dashArray)
-    return;
+                                const float* dashArray,
+                                size_t dashCount) {
+  ASSERT(dashArray);
+  ASSERT(dashCount);
 
-  dashCount = dashCount < 0 ? 0 : dashCount;
-  if (m_type == FX_CONTEXT_Device && m_renderDevice) {
-    float scale = 1.0;
-    if (m_info.isActOnDash) {
-      scale = m_info.graphState.m_LineWidth;
-    }
-    m_info.graphState.m_DashPhase = dashPhase;
-    m_info.graphState.SetDashCount(dashCount);
-    for (int32_t i = 0; i < dashCount; i++) {
-      m_info.graphState.m_DashArray[i] = dashArray[i] * scale;
-    }
-  }
+  float scale = m_info.isActOnDash ? m_info.graphState.m_LineWidth : 1.0;
+  m_info.graphState.m_DashPhase = dashPhase;
+  m_info.graphState.m_DashArray.resize(dashCount);
+  for (size_t i = 0; i < dashCount; i++)
+    m_info.graphState.m_DashArray[i] = dashArray[i] * scale;
 }
 
 void CXFA_Graphics::SetSolidLineDash() {
-  if (m_type == FX_CONTEXT_Device && m_renderDevice)
-    m_info.graphState.SetDashCount(0);
+  m_info.graphState.m_DashArray.clear();
 }
 
 void CXFA_Graphics::SetLineWidth(float lineWidth) {
-  if (m_type == FX_CONTEXT_Device && m_renderDevice)
-    m_info.graphState.m_LineWidth = lineWidth;
+  m_info.graphState.m_LineWidth = lineWidth;
 }
 
 void CXFA_Graphics::EnableActOnDash() {
-  if (m_type == FX_CONTEXT_Device && m_renderDevice)
-    m_info.isActOnDash = true;
+  m_info.isActOnDash = true;
 }
 
 void CXFA_Graphics::SetStrokeColor(const CXFA_GEColor& color) {
-  if (m_type == FX_CONTEXT_Device && m_renderDevice)
-    m_info.strokeColor = color;
+  m_info.strokeColor = color;
 }
 
 void CXFA_Graphics::SetFillColor(const CXFA_GEColor& color) {
-  if (m_type == FX_CONTEXT_Device && m_renderDevice)
     m_info.fillColor = color;
 }
 
 void CXFA_Graphics::StrokePath(CXFA_GEPath* path, const CFX_Matrix* matrix) {
-  if (!path)
-    return;
-  if (m_type == FX_CONTEXT_Device && m_renderDevice)
+  if (path)
     RenderDeviceStrokePath(path, matrix);
 }
 
 void CXFA_Graphics::FillPath(CXFA_GEPath* path,
                              FX_FillMode fillMode,
                              const CFX_Matrix* matrix) {
-  if (!path)
-    return;
-  if (m_type == FX_CONTEXT_Device && m_renderDevice)
+  if (path)
     RenderDeviceFillPath(path, fillMode, matrix);
 }
 
 void CXFA_Graphics::ConcatMatrix(const CFX_Matrix* matrix) {
-  if (!matrix)
-    return;
-  if (m_type == FX_CONTEXT_Device && m_renderDevice) {
+  if (matrix)
     m_info.CTM.Concat(*matrix);
-  }
 }
 
 const CFX_Matrix* CXFA_Graphics::GetMatrix() const {
-  if (m_type == FX_CONTEXT_Device && m_renderDevice)
-    return &m_info.CTM;
-  return nullptr;
+  return &m_info.CTM;
 }
 
 CFX_RectF CXFA_Graphics::GetClipRect() const {
-  if (m_type != FX_CONTEXT_Device || !m_renderDevice)
-    return CFX_RectF();
-
   FX_RECT r = m_renderDevice->GetClipBox();
-  return CFX_Rect(r.left, r.top, r.Width(), r.Height()).As<float>();
+  return CFX_RectF(r.left, r.top, r.Width(), r.Height());
 }
 
 void CXFA_Graphics::SetClipRect(const CFX_RectF& rect) {
-  if (m_type == FX_CONTEXT_Device && m_renderDevice) {
-    m_renderDevice->SetClip_Rect(
-        FX_RECT(FXSYS_round(rect.left), FXSYS_round(rect.top),
-                FXSYS_round(rect.right()), FXSYS_round(rect.bottom())));
-  }
+  m_renderDevice->SetClip_Rect(
+      FX_RECT(FXSYS_roundf(rect.left), FXSYS_roundf(rect.top),
+              FXSYS_roundf(rect.right()), FXSYS_roundf(rect.bottom())));
 }
 
 CFX_RenderDevice* CXFA_Graphics::GetRenderDevice() {
@@ -268,7 +243,6 @@
 void CXFA_Graphics::FillPathWithPattern(const CXFA_GEPath* path,
                                         FX_FillMode fillMode,
                                         const CFX_Matrix& matrix) {
-  CXFA_GEPattern* pattern = m_info.fillColor.GetPattern();
   RetainPtr<CFX_DIBitmap> bitmap = m_renderDevice->GetBitmap();
   int32_t width = bitmap->GetWidth();
   int32_t height = bitmap->GetHeight();
@@ -277,26 +251,26 @@
   m_renderDevice->GetDIBits(bmp, 0, 0);
 
   FX_HatchStyle hatchStyle = m_info.fillColor.GetPattern()->m_hatchStyle;
-  const FX_HATCHDATA& data = hatchBitmapData[static_cast<int>(hatchStyle)];
+  const FX_HATCHDATA& data =
+      GetHatchBitmapData(static_cast<size_t>(hatchStyle));
 
   auto mask = pdfium::MakeRetain<CFX_DIBitmap>();
   mask->Create(data.width, data.height, FXDIB_1bppMask);
   memcpy(mask->GetBuffer(), data.maskBits, mask->GetPitch() * data.height);
-  CFX_FloatRect rectf =
+  const CFX_FloatRect rectf =
       matrix.TransformRect(path->GetPathData()->GetBoundingBox());
+  const FX_RECT rect = rectf.ToRoundedFxRect();
 
-  FX_RECT rect(FXSYS_round(rectf.left), FXSYS_round(rectf.top),
-               FXSYS_round(rectf.right), FXSYS_round(rectf.bottom));
   CFX_DefaultRenderDevice device;
   device.Attach(bmp, false, nullptr, false);
-  device.FillRect(&rect, m_info.fillColor.GetPattern()->m_backArgb);
+  device.FillRect(rect, m_info.fillColor.GetPattern()->m_backArgb);
   for (int32_t j = rect.bottom; j < rect.top; j += mask->GetHeight()) {
     for (int32_t i = rect.left; i < rect.right; i += mask->GetWidth())
       device.SetBitMask(mask, i, j, m_info.fillColor.GetPattern()->m_foreArgb);
   }
   CFX_RenderDevice::StateRestorer restorer(m_renderDevice);
   m_renderDevice->SetClip_PathFill(path->GetPathData(), &matrix, fillMode);
-  SetDIBitsWithMatrix(bmp, pattern->m_matrix);
+  SetDIBitsWithMatrix(bmp, CFX_Matrix());
 }
 
 void CXFA_Graphics::FillPathWithShading(const CXFA_GEPath* path,
@@ -320,24 +294,26 @@
       float y_span = end_y - start_y;
       float axis_len_square = (x_span * x_span) + (y_span * y_span);
       for (int32_t row = 0; row < height; row++) {
-        uint32_t* dib_buf = (uint32_t*)(bmp->GetBuffer() + row * pitch);
+        uint32_t* dib_buf =
+            reinterpret_cast<uint32_t*>(bmp->GetBuffer() + row * pitch);
         for (int32_t column = 0; column < width; column++) {
-          float x = (float)(column);
-          float y = (float)(row);
-          float scale = (((x - start_x) * x_span) + ((y - start_y) * y_span)) /
-                        axis_len_square;
-          if (scale < 0) {
-            if (!m_info.fillColor.GetShading()->m_isExtendedBegin) {
-              continue;
+          float scale = 0.0f;
+          if (axis_len_square) {
+            float y = static_cast<float>(row);
+            float x = static_cast<float>(column);
+            scale = (((x - start_x) * x_span) + ((y - start_y) * y_span)) /
+                    axis_len_square;
+            if (std::isnan(scale) || scale < 0.0f) {
+              if (!m_info.fillColor.GetShading()->m_isExtendedBegin)
+                continue;
+              scale = 0.0f;
+            } else if (scale > 1.0f) {
+              if (!m_info.fillColor.GetShading()->m_isExtendedEnd)
+                continue;
+              scale = 1.0f;
             }
-            scale = 0;
-          } else if (scale > 1.0f) {
-            if (!m_info.fillColor.GetShading()->m_isExtendedEnd) {
-              continue;
-            }
-            scale = 1.0f;
           }
-          int32_t index = (int32_t)(scale * (FX_SHADING_Steps - 1));
+          int32_t index = static_cast<int32_t>(scale * (FX_SHADING_Steps - 1));
           dib_buf[column] = m_info.fillColor.GetShading()->m_argbArray[index];
         }
       }
@@ -386,16 +362,14 @@
               continue;
             }
           }
-          if (s < 0) {
-            if (!m_info.fillColor.GetShading()->m_isExtendedBegin) {
+          if (std::isnan(s) || s < 0.0f) {
+            if (!m_info.fillColor.GetShading()->m_isExtendedBegin)
               continue;
-            }
-            s = 0;
+            s = 0.0f;
           }
           if (s > 1.0f) {
-            if (!m_info.fillColor.GetShading()->m_isExtendedEnd) {
+            if (!m_info.fillColor.GetShading()->m_isExtendedEnd)
               continue;
-            }
             s = 1.0f;
           }
           int index = (int32_t)(s * (FX_SHADING_Steps - 1));
@@ -417,7 +391,7 @@
   }
 }
 
-void CXFA_Graphics::SetDIBitsWithMatrix(const RetainPtr<CFX_DIBSource>& source,
+void CXFA_Graphics::SetDIBitsWithMatrix(const RetainPtr<CFX_DIBBase>& source,
                                         const CFX_Matrix& matrix) {
   if (matrix.IsIdentity()) {
     m_renderDevice->SetDIBits(source, 0, 0);
@@ -428,7 +402,7 @@
     int32_t left;
     int32_t top;
     RetainPtr<CFX_DIBitmap> bmp1 = source->FlipImage(false, true);
-    RetainPtr<CFX_DIBitmap> bmp2 = bmp1->TransformTo(&m, &left, &top);
+    RetainPtr<CFX_DIBitmap> bmp2 = bmp1->TransformTo(m, &left, &top);
     m_renderDevice->SetDIBits(bmp2, left, top);
   }
 }
@@ -444,7 +418,7 @@
       fillColor(info.fillColor) {}
 
 CXFA_Graphics::TInfo& CXFA_Graphics::TInfo::operator=(const TInfo& other) {
-  graphState.Copy(other.graphState);
+  graphState = other.graphState;
   CTM = other.CTM;
   isActOnDash = other.isActOnDash;
   strokeColor = other.strokeColor;
diff --git a/xfa/fxgraphics/cxfa_graphics.h b/xfa/fxgraphics/cxfa_graphics.h
index 886bc45..d6ab7de 100644
--- a/xfa/fxgraphics/cxfa_graphics.h
+++ b/xfa/fxgraphics/cxfa_graphics.h
@@ -11,14 +11,9 @@
 #include <vector>
 
 #include "core/fxcrt/fx_system.h"
-#include "core/fxge/cfx_defaultrenderdevice.h"
 #include "core/fxge/cfx_graphstatedata.h"
-#include "core/fxge/cfx_renderdevice.h"
-#include "core/fxge/fx_dib.h"
 #include "xfa/fxgraphics/cxfa_gecolor.h"
 
-class CXFA_GEPath;
-
 using FX_FillMode = int32_t;
 
 enum class FX_HatchStyle {
@@ -30,7 +25,9 @@
   DiagonalCross = 5
 };
 
+class CFX_DIBBase;
 class CFX_RenderDevice;
+class CXFA_GEPath;
 
 class CXFA_Graphics {
  public:
@@ -45,7 +42,7 @@
   CFX_RenderDevice* GetRenderDevice();
 
   void SetLineCap(CFX_GraphStateData::LineCap lineCap);
-  void SetLineDash(float dashPhase, float* dashArray, int32_t dashCount);
+  void SetLineDash(float dashPhase, const float* dashArray, size_t dashCount);
   void SetSolidLineDash();
   void SetLineWidth(float lineWidth);
   void EnableActOnDash();
@@ -58,9 +55,6 @@
                 const CFX_Matrix* matrix);
   void ConcatMatrix(const CFX_Matrix* matrix);
 
- protected:
-  int32_t m_type;
-
  private:
   struct TInfo {
     TInfo();
@@ -72,25 +66,24 @@
     bool isActOnDash;
     CXFA_GEColor strokeColor;
     CXFA_GEColor fillColor;
-  } m_info;
+  };
 
   void RenderDeviceStrokePath(const CXFA_GEPath* path,
                               const CFX_Matrix* matrix);
   void RenderDeviceFillPath(const CXFA_GEPath* path,
                             FX_FillMode fillMode,
                             const CFX_Matrix* matrix);
-
   void FillPathWithPattern(const CXFA_GEPath* path,
                            FX_FillMode fillMode,
                            const CFX_Matrix& matrix);
   void FillPathWithShading(const CXFA_GEPath* path,
                            FX_FillMode fillMode,
                            const CFX_Matrix& matrix);
-
-  void SetDIBitsWithMatrix(const RetainPtr<CFX_DIBSource>& source,
+  void SetDIBitsWithMatrix(const RetainPtr<CFX_DIBBase>& source,
                            const CFX_Matrix& matrix);
 
   CFX_RenderDevice* const m_renderDevice;  // Not owned.
+  TInfo m_info;
   std::vector<std::unique_ptr<TInfo>> m_infoStack;
 };